S: S-226 64 LUND
S: Sweden
+N: Tilman Schmidt
+E: tilman@imap.cc
+D: Siemens Gigaset ISDN driver author and maintainer
+D: ISDN CAPI subsystem contributions
+
N: Henning P. Schmiedehausen
E: hps@tanstaafl.de
D: added PCI support to the serial driver
+++ /dev/null
-=======
-Credits
-=======
-
-
-I want to thank all who contributed to this project and especially to:
-(in alphabetical order)
-
-Thomas Bogendörfer (tsbogend@bigbug.franken.de)
- Tester, lots of bugfixes and hints.
-
-Alan Cox (alan@lxorguk.ukuu.org.uk)
- For help getting into standard-kernel.
-
-Henner Eisen (eis@baty.hanse.de)
- For X.25 implementation.
-
-Volker Götz (volker@oops.franken.de)
- For contribution of man-pages, the imontty-tool and a perfect
- maintaining of the mailing-list at hub-wue.
-
-Matthias Hessler (hessler@isdn4linux.de)
- For creating and maintaining the FAQ.
-
-Bernhard Hailer (Bernhard.Hailer@lrz.uni-muenchen.de)
- For creating the FAQ, and the leafsite HOWTO.
-
-Michael 'Ghandi' Herold (michael@abadonna.franken.de)
- For contribution of the vbox answering machine.
-
-Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- For his Sync-PPP-code.
-
-Karsten Keil (keil@isdn4linux.de)
- For adding 1TR6-support to the Teles-driver.
- For the HiSax-driver.
-
-Michael Knigge (knick@cove.han.de)
- For contributing the imon-tool
-
-Andreas Kool (akool@Kool.f.EUnet.de)
- For contribution of the isdnlog/isdnrep-tool
-
-Pedro Roque Marques (roque@di.fc.ul.pt)
- For lot of new ideas and the pcbit driver.
-
-Eberhard Mönkeberg (emoenke@gwdg.de)
- For testing and help to get into kernel.
-
-Thomas Neumann (tn@ruhr.de)
- For help with Cisco-SLARP and keepalive
-
-Jan den Ouden (denouden@groovin.xs4all.nl)
- For contribution of the original teles-driver
-
-Carsten Paeth (calle@calle.in-berlin.de)
- For the AVM-B1-CAPI2.0 driver
-
-Thomas Pfeiffer (pfeiffer@pds.de)
- For V.110, extended T.70 and Hylafax extensions in isdn_tty.c
-
-Max Riegel (riegel@max.franken.de)
- For making the ICN hardware-documentation and test-equipment available.
-
-Armin Schindler (mac@melware.de)
- For the eicon active card driver.
-
-Gerhard 'Fido' Schneider (fido@wuff.mayn.de)
- For heavy-duty-beta-testing with his BBS ;)
-
-Thomas Uhl (uhl@think.de)
- For distributing the cards.
- For pushing me to work ;-)
+++ /dev/null
-.. SPDX-License-Identifier: GPL-2.0
-
-====
-ISDN
-====
-
-.. toctree::
- :maxdepth: 2
-
- interface_capi
-
- m_isdn
-
- credits
+++ /dev/null
-=========================================
-Kernel CAPI Interface to Hardware Drivers
-=========================================
-
-1. Overview
-===========
-
-From the CAPI 2.0 specification:
-COMMON-ISDN-API (CAPI) is an application programming interface standard used
-to access ISDN equipment connected to basic rate interfaces (BRI) and primary
-rate interfaces (PRI).
-
-Kernel CAPI operates as a dispatching layer between CAPI applications and CAPI
-hardware drivers. Hardware drivers register ISDN devices (controllers, in CAPI
-lingo) with Kernel CAPI to indicate their readiness to provide their service
-to CAPI applications. CAPI applications also register with Kernel CAPI,
-requesting association with a CAPI device. Kernel CAPI then dispatches the
-application registration to an available device, forwarding it to the
-corresponding hardware driver. Kernel CAPI then forwards CAPI messages in both
-directions between the application and the hardware driver.
-
-Format and semantics of CAPI messages are specified in the CAPI 2.0 standard.
-This standard is freely available from https://www.capi.org.
-
-
-2. Driver and Device Registration
-=================================
-
-CAPI drivers must register each of the ISDN devices they control with Kernel
-CAPI by calling the Kernel CAPI function attach_capi_ctr() with a pointer to a
-struct capi_ctr before they can be used. This structure must be filled with
-the names of the driver and controller, and a number of callback function
-pointers which are subsequently used by Kernel CAPI for communicating with the
-driver. The registration can be revoked by calling the function
-detach_capi_ctr() with a pointer to the same struct capi_ctr.
-
-Before the device can be actually used, the driver must fill in the device
-information fields 'manu', 'version', 'profile' and 'serial' in the capi_ctr
-structure of the device, and signal its readiness by calling capi_ctr_ready().
-From then on, Kernel CAPI may call the registered callback functions for the
-device.
-
-If the device becomes unusable for any reason (shutdown, disconnect ...), the
-driver has to call capi_ctr_down(). This will prevent further calls to the
-callback functions by Kernel CAPI.
-
-
-3. Application Registration and Communication
-=============================================
-
-Kernel CAPI forwards registration requests from applications (calls to CAPI
-operation CAPI_REGISTER) to an appropriate hardware driver by calling its
-register_appl() callback function. A unique Application ID (ApplID, u16) is
-allocated by Kernel CAPI and passed to register_appl() along with the
-parameter structure provided by the application. This is analogous to the
-open() operation on regular files or character devices.
-
-After a successful return from register_appl(), CAPI messages from the
-application may be passed to the driver for the device via calls to the
-send_message() callback function. Conversely, the driver may call Kernel
-CAPI's capi_ctr_handle_message() function to pass a received CAPI message to
-Kernel CAPI for forwarding to an application, specifying its ApplID.
-
-Deregistration requests (CAPI operation CAPI_RELEASE) from applications are
-forwarded as calls to the release_appl() callback function, passing the same
-ApplID as with register_appl(). After return from release_appl(), no CAPI
-messages for that application may be passed to or from the device anymore.
-
-
-4. Data Structures
-==================
-
-4.1 struct capi_driver
-----------------------
-
-This structure describes a Kernel CAPI driver itself. It is used in the
-register_capi_driver() and unregister_capi_driver() functions, and contains
-the following non-private fields, all to be set by the driver before calling
-register_capi_driver():
-
-``char name[32]``
- the name of the driver, as a zero-terminated ASCII string
-``char revision[32]``
- the revision number of the driver, as a zero-terminated ASCII string
-
-4.2 struct capi_ctr
--------------------
-
-This structure describes an ISDN device (controller) handled by a Kernel CAPI
-driver. After registration via the attach_capi_ctr() function it is passed to
-all controller specific lower layer interface and callback functions to
-identify the controller to operate on.
-
-It contains the following non-private fields:
-
-to be set by the driver before calling attach_capi_ctr():
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-``struct module *owner``
- pointer to the driver module owning the device
-
-``void *driverdata``
- an opaque pointer to driver specific data, not touched by Kernel CAPI
-
-``char name[32]``
- the name of the controller, as a zero-terminated ASCII string
-
-``char *driver_name``
- the name of the driver, as a zero-terminated ASCII string
-
-``int (*load_firmware)(struct capi_ctr *ctrlr, capiloaddata *ldata)``
- (optional) pointer to a callback function for sending firmware and
- configuration data to the device
-
- The function may return before the operation has completed.
-
- Completion must be signalled by a call to capi_ctr_ready().
-
- Return value: 0 on success, error code on error
- Called in process context.
-
-``void (*reset_ctr)(struct capi_ctr *ctrlr)``
- (optional) pointer to a callback function for stopping the device,
- releasing all registered applications
-
- The function may return before the operation has completed.
-
- Completion must be signalled by a call to capi_ctr_down().
-
- Called in process context.
-
-``void (*register_appl)(struct capi_ctr *ctrlr, u16 applid, capi_register_params *rparam)``
- pointers to callback function for registration of
- applications with the device
-
- Calls to these functions are serialized by Kernel CAPI so that only
- one call to any of them is active at any time.
-
-``void (*release_appl)(struct capi_ctr *ctrlr, u16 applid)``
- pointers to callback functions deregistration of
- applications with the device
-
- Calls to these functions are serialized by Kernel CAPI so that only
- one call to any of them is active at any time.
-
-``u16 (*send_message)(struct capi_ctr *ctrlr, struct sk_buff *skb)``
- pointer to a callback function for sending a CAPI message to the
- device
-
- Return value: CAPI error code
-
- If the method returns 0 (CAPI_NOERROR) the driver has taken ownership
- of the skb and the caller may no longer access it. If it returns a
- non-zero (error) value then ownership of the skb returns to the caller
- who may reuse or free it.
-
- The return value should only be used to signal problems with respect
- to accepting or queueing the message. Errors occurring during the
- actual processing of the message should be signaled with an
- appropriate reply message.
-
- May be called in process or interrupt context.
-
- Calls to this function are not serialized by Kernel CAPI, ie. it must
- be prepared to be re-entered.
-
-``char *(*procinfo)(struct capi_ctr *ctrlr)``
- pointer to a callback function returning the entry for the device in
- the CAPI controller info table, /proc/capi/controller
-
-Note:
- Callback functions except send_message() are never called in interrupt
- context.
-
-to be filled in before calling capi_ctr_ready():
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-``u8 manu[CAPI_MANUFACTURER_LEN]``
- value to return for CAPI_GET_MANUFACTURER
-
-``capi_version version``
- value to return for CAPI_GET_VERSION
-
-``capi_profile profile``
- value to return for CAPI_GET_PROFILE
-
-``u8 serial[CAPI_SERIAL_LEN]``
- value to return for CAPI_GET_SERIAL
-
-
-4.3 SKBs
---------
-
-CAPI messages are passed between Kernel CAPI and the driver via send_message()
-and capi_ctr_handle_message(), stored in the data portion of a socket buffer
-(skb). Each skb contains a single CAPI message coded according to the CAPI 2.0
-standard.
-
-For the data transfer messages, DATA_B3_REQ and DATA_B3_IND, the actual
-payload data immediately follows the CAPI message itself within the same skb.
-The Data and Data64 parameters are not used for processing. The Data64
-parameter may be omitted by setting the length field of the CAPI message to 22
-instead of 30.
-
-
-4.4 The _cmsg Structure
------------------------
-
-(declared in <linux/isdn/capiutil.h>)
-
-The _cmsg structure stores the contents of a CAPI 2.0 message in an easily
-accessible form. It contains members for all possible CAPI 2.0 parameters,
-including subparameters of the Additional Info and B Protocol structured
-parameters, with the following exceptions:
-
-* second Calling party number (CONNECT_IND)
-
-* Data64 (DATA_B3_REQ and DATA_B3_IND)
-
-* Sending complete (subparameter of Additional Info, CONNECT_REQ and INFO_REQ)
-
-* Global Configuration (subparameter of B Protocol, CONNECT_REQ, CONNECT_RESP
- and SELECT_B_PROTOCOL_REQ)
-
-Only those parameters appearing in the message type currently being processed
-are actually used. Unused members should be set to zero.
-
-Members are named after the CAPI 2.0 standard names of the parameters they
-represent. See <linux/isdn/capiutil.h> for the exact spelling. Member data
-types are:
-
-=========== =================================================================
-u8 for CAPI parameters of type 'byte'
-
-u16 for CAPI parameters of type 'word'
-
-u32 for CAPI parameters of type 'dword'
-
-_cstruct for CAPI parameters of type 'struct'
- The member is a pointer to a buffer containing the parameter in
- CAPI encoding (length + content). It may also be NULL, which will
- be taken to represent an empty (zero length) parameter.
- Subparameters are stored in encoded form within the content part.
-
-_cmstruct alternative representation for CAPI parameters of type 'struct'
- (used only for the 'Additional Info' and 'B Protocol' parameters)
- The representation is a single byte containing one of the values:
- CAPI_DEFAULT: The parameter is empty/absent.
- CAPI_COMPOSE: The parameter is present.
- Subparameter values are stored individually in the corresponding
- _cmsg structure members.
-=========== =================================================================
-
-
-5. Lower Layer Interface Functions
-==================================
-
-::
-
- int attach_capi_ctr(struct capi_ctr *ctrlr)
- int detach_capi_ctr(struct capi_ctr *ctrlr)
-
-register/unregister a device (controller) with Kernel CAPI
-
-::
-
- void capi_ctr_ready(struct capi_ctr *ctrlr)
- void capi_ctr_down(struct capi_ctr *ctrlr)
-
-signal controller ready/not ready
-
-::
-
- void capi_ctr_handle_message(struct capi_ctr * ctrlr, u16 applid,
- struct sk_buff *skb)
-
-pass a received CAPI message to Kernel CAPI
-for forwarding to the specified application
-
-
-6. Helper Functions and Macros
-==============================
-
-Macros to extract/set element values from/in a CAPI message header
-(from <linux/isdn/capiutil.h>):
-
-====================== ============================= ====================
-Get Macro Set Macro Element (Type)
-====================== ============================= ====================
-CAPIMSG_LEN(m) CAPIMSG_SETLEN(m, len) Total Length (u16)
-CAPIMSG_APPID(m) CAPIMSG_SETAPPID(m, applid) ApplID (u16)
-CAPIMSG_COMMAND(m) CAPIMSG_SETCOMMAND(m,cmd) Command (u8)
-CAPIMSG_SUBCOMMAND(m) CAPIMSG_SETSUBCOMMAND(m, cmd) Subcommand (u8)
-CAPIMSG_CMD(m) - Command*256
- + Subcommand (u16)
-CAPIMSG_MSGID(m) CAPIMSG_SETMSGID(m, msgid) Message Number (u16)
-
-CAPIMSG_CONTROL(m) CAPIMSG_SETCONTROL(m, contr) Controller/PLCI/NCCI
- (u32)
-CAPIMSG_DATALEN(m) CAPIMSG_SETDATALEN(m, len) Data Length (u16)
-====================== ============================= ====================
-
-
-Library functions for working with _cmsg structures
-(from <linux/isdn/capiutil.h>):
-
-``char *capi_cmd2str(u8 Command, u8 Subcommand)``
- Returns the CAPI 2.0 message name corresponding to the given command
- and subcommand values, as a static ASCII string. The return value may
- be NULL if the command/subcommand is not one of those defined in the
- CAPI 2.0 standard.
-
-
-7. Debugging
-============
-
-The module kernelcapi has a module parameter showcapimsgs controlling some
-debugging output produced by the module. It can only be set when the module is
-loaded, via a parameter "showcapimsgs=<n>" to the modprobe command, either on
-the command line or in the configuration file.
-
-If the lowest bit of showcapimsgs is set, kernelcapi logs controller and
-application up and down events.
-
-In addition, every registered CAPI controller has an associated traceflag
-parameter controlling how CAPI messages sent from and to the controller are
-logged. The traceflag parameter is initialized with the value of the
-showcapimsgs parameter when the controller is registered, but can later be
-changed via the MANUFACTURER_REQ command KCAPI_CMD_TRACE.
-
-If the value of traceflag is non-zero, CAPI messages are logged.
-DATA_B3 messages are only logged if the value of traceflag is > 2.
-
-If the lowest bit of traceflag is set, only the command/subcommand and message
-length are logged. Otherwise, kernelcapi logs a readable representation of
-the entire message.
+++ /dev/null
-============
-mISDN Driver
-============
-
-mISDN is a new modular ISDN driver, in the long term it should replace
-the old I4L driver architecture for passive ISDN cards.
-It was designed to allow a broad range of applications and interfaces
-but only have the basic function in kernel, the interface to the user
-space is based on sockets with a own address family AF_ISDN.
networking/index
netlabel/index
infiniband/index
- isdn/index
mhi/index
Storage interfaces
T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
F: drivers/infiniband/ulp/isert
-ISDN/CMTP OVER BLUETOOTH
-L: netdev@vger.kernel.org
-S: Orphan
-W: http://www.isdn4linux.de
-F: Documentation/isdn/
-F: drivers/isdn/capi/
-F: include/linux/isdn/
-F: include/uapi/linux/isdn/
-F: net/bluetooth/cmtp/
-
-ISDN/mISDN SUBSYSTEM
-L: netdev@vger.kernel.org
-S: Orphan
-W: http://www.isdn4linux.de
-F: drivers/isdn/Kconfig
-F: drivers/isdn/Makefile
-F: drivers/isdn/hardware/
-F: drivers/isdn/mISDN/
-
ISL28022 HARDWARE MONITORING DRIVER
M: Carsten Spieß <mail@carsten-spiess.de>
L: linux-hwmon@vger.kernel.org
source "drivers/net/Kconfig"
-source "drivers/isdn/Kconfig"
-
# input before char - char/joystick depends on it. As does USB.
source "drivers/input/Kconfig"
obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_ACCESSIBILITY) += accessibility/
-obj-$(CONFIG_ISDN) += isdn/
obj-$(CONFIG_EDAC) += edac/
obj-$(CONFIG_EISA) += eisa/
obj-$(CONFIG_PM_OPP) += opp/
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# ISDN device configuration
-#
-
-menuconfig ISDN
- bool "ISDN support"
- depends on NET && NETDEVICES
- help
- ISDN ("Integrated Services Digital Network", called RNIS in France)
- is a fully digital telephone service that can be used for voice and
- data connections. If your computer is equipped with an ISDN
- adapter you can use it to connect to your Internet service provider
- (with SLIP or PPP) faster than via a conventional telephone modem
- (though still much slower than with DSL) or to make and accept
- voice calls (eg. turning your PC into a software answering machine
- or PABX).
-
- Select this option if you want your kernel to support ISDN.
-
-if ISDN
-
-source "drivers/isdn/capi/Kconfig"
-
-source "drivers/isdn/mISDN/Kconfig"
-
-endif # ISDN
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0
-# Makefile for the kernel ISDN subsystem and device drivers.
-
-# Object files in subdirectories
-
-obj-$(CONFIG_BT_CMTP) += capi/
-obj-$(CONFIG_MISDN) += mISDN/
-obj-$(CONFIG_ISDN) += hardware/
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0-only
-config ISDN_CAPI
- def_bool ISDN && BT
- help
- This provides CAPI (the Common ISDN Application Programming
- Interface) Version 2.0, a standard making it easy for programs to
- access ISDN hardware in a device independent way. (For details see
- <https://www.capi.org/>.) CAPI supports making and accepting voice
- and data connections, controlling call options and protocols,
- as well as ISDN supplementary services like call forwarding or
- three-party conferences (if supported by the specific hardware
- driver).
-
- This subsystem requires a hardware specific driver.
- See CONFIG_BT_CMTP for the last remaining regular driver
- in the kernel that uses the CAPI subsystem.
-
-config CAPI_TRACE
- def_bool BT_CMTP
- help
- If you say Y here, the kernelcapi driver can make verbose traces
- of CAPI messages. This feature can be enabled/disabled via IOCTL for
- every controller (default disabled).
-
-config ISDN_CAPI_MIDDLEWARE
- def_bool BT_CMTP && TTY
- help
- This option will enhance the capabilities of the /dev/capi20
- interface. It will provide a means of moving a data connection,
- established via the usual /dev/capi20 interface to a special tty
- device. If you want to use pppd with pppdcapiplugin to dial up to
- your ISP, say Y here.
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0
-# Makefile for the CAPI subsystem used by BT_CMTP
-
-obj-$(CONFIG_BT_CMTP) += kernelcapi.o
-kernelcapi-y := kcapi.o capiutil.o capi.o
-kernelcapi-$(CONFIG_PROC_FS) += kcapi_proc.o
+++ /dev/null
-/* $Id: capi.c,v 1.1.2.7 2004/04/28 09:48:59 armin Exp $
- *
- * CAPI 2.0 Interface for Linux
- *
- * Copyright 1996 by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/compiler.h>
-#include <linux/module.h>
-#include <linux/ethtool.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/fs.h>
-#include <linux/signal.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/tty.h>
-#include <linux/netdevice.h>
-#include <linux/ppp_defs.h>
-#include <linux/ppp-ioctl.h>
-#include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/poll.h>
-#include <linux/capi.h>
-#include <linux/kernelcapi.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/moduleparam.h>
-#include <linux/isdn/capiutil.h>
-#include <linux/isdn/capicmd.h>
-
-#include "kcapi.h"
-
-MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer and /dev/capi20 interface");
-MODULE_AUTHOR("Carsten Paeth");
-MODULE_LICENSE("GPL");
-
-/* -------- driver information -------------------------------------- */
-
-static DEFINE_MUTEX(capi_mutex);
-static const struct class capi_class = {
- .name = "capi",
-};
-static int capi_major = 68; /* allocated */
-
-module_param_named(major, capi_major, uint, 0);
-
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-#define CAPINC_NR_PORTS 32
-#define CAPINC_MAX_PORTS 256
-
-static int capi_ttyminors = CAPINC_NR_PORTS;
-
-module_param_named(ttyminors, capi_ttyminors, uint, 0);
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-
-/* -------- defines ------------------------------------------------- */
-
-#define CAPINC_MAX_RECVQUEUE 10
-#define CAPINC_MAX_SENDQUEUE 10
-#define CAPI_MAX_BLKSIZE 2048
-
-/* -------- data structures ----------------------------------------- */
-
-struct capidev;
-struct capincci;
-struct capiminor;
-
-struct ackqueue_entry {
- struct list_head list;
- u16 datahandle;
-};
-
-struct capiminor {
- unsigned int minor;
-
- struct capi20_appl *ap;
- u32 ncci;
- atomic_t datahandle;
- atomic_t msgid;
-
- struct tty_port port;
- int ttyinstop;
- int ttyoutstop;
-
- struct sk_buff_head inqueue;
-
- struct sk_buff_head outqueue;
- int outbytes;
- struct sk_buff *outskb;
- spinlock_t outlock;
-
- /* transmit path */
- struct list_head ackqueue;
- int nack;
- spinlock_t ackqlock;
-};
-
-struct capincci {
- struct list_head list;
- u32 ncci;
- struct capidev *cdev;
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- struct capiminor *minorp;
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-};
-
-struct capidev {
- struct list_head list;
- struct capi20_appl ap;
- u16 errcode;
- unsigned userflags;
-
- struct sk_buff_head recvqueue;
- wait_queue_head_t recvwait;
-
- struct list_head nccis;
-
- struct mutex lock;
-};
-
-/* -------- global variables ---------------------------------------- */
-
-static DEFINE_MUTEX(capidev_list_lock);
-static LIST_HEAD(capidev_list);
-
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-
-static DEFINE_SPINLOCK(capiminors_lock);
-static struct capiminor **capiminors;
-
-static struct tty_driver *capinc_tty_driver;
-
-/* -------- datahandles --------------------------------------------- */
-
-static int capiminor_add_ack(struct capiminor *mp, u16 datahandle)
-{
- struct ackqueue_entry *n;
-
- n = kmalloc_obj(*n, GFP_ATOMIC);
- if (unlikely(!n)) {
- printk(KERN_ERR "capi: alloc datahandle failed\n");
- return -1;
- }
- n->datahandle = datahandle;
- INIT_LIST_HEAD(&n->list);
- spin_lock_bh(&mp->ackqlock);
- list_add_tail(&n->list, &mp->ackqueue);
- mp->nack++;
- spin_unlock_bh(&mp->ackqlock);
- return 0;
-}
-
-static int capiminor_del_ack(struct capiminor *mp, u16 datahandle)
-{
- struct ackqueue_entry *p, *tmp;
-
- spin_lock_bh(&mp->ackqlock);
- list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
- if (p->datahandle == datahandle) {
- list_del(&p->list);
- mp->nack--;
- spin_unlock_bh(&mp->ackqlock);
- kfree(p);
- return 0;
- }
- }
- spin_unlock_bh(&mp->ackqlock);
- return -1;
-}
-
-static void capiminor_del_all_ack(struct capiminor *mp)
-{
- struct ackqueue_entry *p, *tmp;
-
- list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
- list_del(&p->list);
- kfree(p);
- mp->nack--;
- }
-}
-
-
-/* -------- struct capiminor ---------------------------------------- */
-
-static void capiminor_destroy(struct tty_port *port)
-{
- struct capiminor *mp = container_of(port, struct capiminor, port);
-
- kfree_skb(mp->outskb);
- skb_queue_purge(&mp->inqueue);
- skb_queue_purge(&mp->outqueue);
- capiminor_del_all_ack(mp);
- kfree(mp);
-}
-
-static const struct tty_port_operations capiminor_port_ops = {
- .destruct = capiminor_destroy,
-};
-
-static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
-{
- struct capiminor *mp;
- struct device *dev;
- unsigned int minor;
-
- mp = kzalloc_obj(*mp);
- if (!mp) {
- printk(KERN_ERR "capi: can't alloc capiminor\n");
- return NULL;
- }
-
- mp->ap = ap;
- mp->ncci = ncci;
- INIT_LIST_HEAD(&mp->ackqueue);
- spin_lock_init(&mp->ackqlock);
-
- skb_queue_head_init(&mp->inqueue);
- skb_queue_head_init(&mp->outqueue);
- spin_lock_init(&mp->outlock);
-
- tty_port_init(&mp->port);
- mp->port.ops = &capiminor_port_ops;
-
- /* Allocate the least unused minor number. */
- spin_lock(&capiminors_lock);
- for (minor = 0; minor < capi_ttyminors; minor++)
- if (!capiminors[minor]) {
- capiminors[minor] = mp;
- break;
- }
- spin_unlock(&capiminors_lock);
-
- if (minor == capi_ttyminors) {
- printk(KERN_NOTICE "capi: out of minors\n");
- goto err_out1;
- }
-
- mp->minor = minor;
-
- dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor,
- NULL);
- if (IS_ERR(dev))
- goto err_out2;
-
- return mp;
-
-err_out2:
- spin_lock(&capiminors_lock);
- capiminors[minor] = NULL;
- spin_unlock(&capiminors_lock);
-
-err_out1:
- tty_port_put(&mp->port);
- return NULL;
-}
-
-static struct capiminor *capiminor_get(unsigned int minor)
-{
- struct capiminor *mp;
-
- spin_lock(&capiminors_lock);
- mp = capiminors[minor];
- if (mp)
- tty_port_get(&mp->port);
- spin_unlock(&capiminors_lock);
-
- return mp;
-}
-
-static inline void capiminor_put(struct capiminor *mp)
-{
- tty_port_put(&mp->port);
-}
-
-static void capiminor_free(struct capiminor *mp)
-{
- tty_unregister_device(capinc_tty_driver, mp->minor);
-
- spin_lock(&capiminors_lock);
- capiminors[mp->minor] = NULL;
- spin_unlock(&capiminors_lock);
-
- capiminor_put(mp);
-}
-
-/* -------- struct capincci ----------------------------------------- */
-
-static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np)
-{
- if (cdev->userflags & CAPIFLAG_HIGHJACKING)
- np->minorp = capiminor_alloc(&cdev->ap, np->ncci);
-}
-
-static void capincci_free_minor(struct capincci *np)
-{
- struct capiminor *mp = np->minorp;
-
- if (mp) {
- tty_port_tty_vhangup(&mp->port);
- capiminor_free(mp);
- }
-}
-
-static inline unsigned int capincci_minor_opencount(struct capincci *np)
-{
- struct capiminor *mp = np->minorp;
- unsigned int count = 0;
- struct tty_struct *tty;
-
- if (mp) {
- tty = tty_port_tty_get(&mp->port);
- if (tty) {
- count = tty->count;
- tty_kref_put(tty);
- }
- }
- return count;
-}
-
-#else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */
-
-static inline void
-capincci_alloc_minor(struct capidev *cdev, struct capincci *np) { }
-static inline void capincci_free_minor(struct capincci *np) { }
-
-#endif /* !CONFIG_ISDN_CAPI_MIDDLEWARE */
-
-static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci)
-{
- struct capincci *np;
-
- np = kzalloc_obj(*np);
- if (!np)
- return NULL;
- np->ncci = ncci;
- np->cdev = cdev;
-
- capincci_alloc_minor(cdev, np);
-
- list_add_tail(&np->list, &cdev->nccis);
-
- return np;
-}
-
-static void capincci_free(struct capidev *cdev, u32 ncci)
-{
- struct capincci *np, *tmp;
-
- list_for_each_entry_safe(np, tmp, &cdev->nccis, list)
- if (ncci == 0xffffffff || np->ncci == ncci) {
- capincci_free_minor(np);
- list_del(&np->list);
- kfree(np);
- }
-}
-
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-static struct capincci *capincci_find(struct capidev *cdev, u32 ncci)
-{
- struct capincci *np;
-
- list_for_each_entry(np, &cdev->nccis, list)
- if (np->ncci == ncci)
- return np;
- return NULL;
-}
-
-/* -------- handle data queue --------------------------------------- */
-
-static struct sk_buff *
-gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
-{
- struct sk_buff *nskb;
- nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_KERNEL);
- if (nskb) {
- u16 datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 4 + 2);
- unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN);
- capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN);
- capimsg_setu16(s, 2, mp->ap->applid);
- capimsg_setu8 (s, 4, CAPI_DATA_B3);
- capimsg_setu8 (s, 5, CAPI_RESP);
- capimsg_setu16(s, 6, atomic_inc_return(&mp->msgid));
- capimsg_setu32(s, 8, mp->ncci);
- capimsg_setu16(s, 12, datahandle);
- }
- return nskb;
-}
-
-static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
-{
- unsigned int datalen = skb->len - CAPIMSG_LEN(skb->data);
- struct tty_struct *tty;
- struct sk_buff *nskb;
- u16 errcode, datahandle;
- struct tty_ldisc *ld;
- int ret = -1;
-
- tty = tty_port_tty_get(&mp->port);
- if (!tty) {
- pr_debug("capi: currently no receiver\n");
- return -1;
- }
-
- ld = tty_ldisc_ref(tty);
- if (!ld) {
- /* fatal error, do not requeue */
- ret = 0;
- kfree_skb(skb);
- goto deref_tty;
- }
-
- if (ld->ops->receive_buf == NULL) {
- pr_debug("capi: ldisc has no receive_buf function\n");
- /* fatal error, do not requeue */
- goto free_skb;
- }
- if (mp->ttyinstop) {
- pr_debug("capi: recv tty throttled\n");
- goto deref_ldisc;
- }
-
- if (tty->receive_room < datalen) {
- pr_debug("capi: no room in tty\n");
- goto deref_ldisc;
- }
-
- nskb = gen_data_b3_resp_for(mp, skb);
- if (!nskb) {
- printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
- goto deref_ldisc;
- }
-
- datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4);
-
- errcode = capi20_put_message(mp->ap, nskb);
-
- if (errcode == CAPI_NOERROR) {
- skb_pull(skb, CAPIMSG_LEN(skb->data));
- pr_debug("capi: DATA_B3_RESP %u len=%d => ldisc\n",
- datahandle, skb->len);
- ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
- } else {
- printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
- errcode);
- kfree_skb(nskb);
-
- if (errcode == CAPI_SENDQUEUEFULL)
- goto deref_ldisc;
- }
-
-free_skb:
- ret = 0;
- kfree_skb(skb);
-
-deref_ldisc:
- tty_ldisc_deref(ld);
-
-deref_tty:
- tty_kref_put(tty);
- return ret;
-}
-
-static void handle_minor_recv(struct capiminor *mp)
-{
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&mp->inqueue)) != NULL)
- if (handle_recv_skb(mp, skb) < 0) {
- skb_queue_head(&mp->inqueue, skb);
- return;
- }
-}
-
-static void handle_minor_send(struct capiminor *mp)
-{
- struct tty_struct *tty;
- struct sk_buff *skb;
- u16 len;
- u16 errcode;
- u16 datahandle;
-
- tty = tty_port_tty_get(&mp->port);
- if (!tty)
- return;
-
- if (mp->ttyoutstop) {
- pr_debug("capi: send: tty stopped\n");
- tty_kref_put(tty);
- return;
- }
-
- while (1) {
- spin_lock_bh(&mp->outlock);
- skb = __skb_dequeue(&mp->outqueue);
- if (!skb) {
- spin_unlock_bh(&mp->outlock);
- break;
- }
- len = (u16)skb->len;
- mp->outbytes -= len;
- spin_unlock_bh(&mp->outlock);
-
- datahandle = atomic_inc_return(&mp->datahandle);
- skb_push(skb, CAPI_DATA_B3_REQ_LEN);
- memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
- capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
- capimsg_setu16(skb->data, 2, mp->ap->applid);
- capimsg_setu8 (skb->data, 4, CAPI_DATA_B3);
- capimsg_setu8 (skb->data, 5, CAPI_REQ);
- capimsg_setu16(skb->data, 6, atomic_inc_return(&mp->msgid));
- capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */
- capimsg_setu32(skb->data, 12, (u32)(long)skb->data);/* Data32 */
- capimsg_setu16(skb->data, 16, len); /* Data length */
- capimsg_setu16(skb->data, 18, datahandle);
- capimsg_setu16(skb->data, 20, 0); /* Flags */
-
- if (capiminor_add_ack(mp, datahandle) < 0) {
- skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
-
- spin_lock_bh(&mp->outlock);
- __skb_queue_head(&mp->outqueue, skb);
- mp->outbytes += len;
- spin_unlock_bh(&mp->outlock);
-
- break;
- }
- errcode = capi20_put_message(mp->ap, skb);
- if (errcode == CAPI_NOERROR) {
- pr_debug("capi: DATA_B3_REQ %u len=%u\n",
- datahandle, len);
- continue;
- }
- capiminor_del_ack(mp, datahandle);
-
- if (errcode == CAPI_SENDQUEUEFULL) {
- skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
-
- spin_lock_bh(&mp->outlock);
- __skb_queue_head(&mp->outqueue, skb);
- mp->outbytes += len;
- spin_unlock_bh(&mp->outlock);
-
- break;
- }
-
- /* ups, drop packet */
- printk(KERN_ERR "capi: put_message = %x\n", errcode);
- kfree_skb(skb);
- }
- tty_kref_put(tty);
-}
-
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-/* -------- function called by lower level -------------------------- */
-
-static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
-{
- struct capidev *cdev = ap->private;
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- struct capiminor *mp;
- u16 datahandle;
- struct capincci *np;
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-
- mutex_lock(&cdev->lock);
-
- if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) {
- u16 info = CAPIMSG_U16(skb->data, 12); // Info field
- if ((info & 0xff00) == 0)
- capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
- }
- if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND)
- capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
-
- if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
- skb_queue_tail(&cdev->recvqueue, skb);
- wake_up_interruptible(&cdev->recvwait);
- goto unlock_out;
- }
-
-#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
- skb_queue_tail(&cdev->recvqueue, skb);
- wake_up_interruptible(&cdev->recvwait);
-
-#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-
- np = capincci_find(cdev, CAPIMSG_CONTROL(skb->data));
- if (!np) {
- printk(KERN_ERR "BUG: capi_signal: ncci not found\n");
- skb_queue_tail(&cdev->recvqueue, skb);
- wake_up_interruptible(&cdev->recvwait);
- goto unlock_out;
- }
-
- mp = np->minorp;
- if (!mp) {
- skb_queue_tail(&cdev->recvqueue, skb);
- wake_up_interruptible(&cdev->recvwait);
- goto unlock_out;
- }
- if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
- datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 4 + 2);
- pr_debug("capi_signal: DATA_B3_IND %u len=%d\n",
- datahandle, skb->len-CAPIMSG_LEN(skb->data));
- skb_queue_tail(&mp->inqueue, skb);
-
- handle_minor_recv(mp);
-
- } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) {
-
- datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4);
- pr_debug("capi_signal: DATA_B3_CONF %u 0x%x\n",
- datahandle,
- CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 2));
- kfree_skb(skb);
- capiminor_del_ack(mp, datahandle);
- tty_port_tty_wakeup(&mp->port);
- handle_minor_send(mp);
-
- } else {
- /* ups, let capi application handle it :-) */
- skb_queue_tail(&cdev->recvqueue, skb);
- wake_up_interruptible(&cdev->recvwait);
- }
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-
-unlock_out:
- mutex_unlock(&cdev->lock);
-}
-
-/* -------- file_operations for capidev ----------------------------- */
-
-static ssize_t
-capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
-{
- struct capidev *cdev = file->private_data;
- struct sk_buff *skb;
- size_t copied;
- int err;
-
- if (!cdev->ap.applid)
- return -ENODEV;
-
- skb = skb_dequeue(&cdev->recvqueue);
- if (!skb) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
- err = wait_event_interruptible(cdev->recvwait,
- (skb = skb_dequeue(&cdev->recvqueue)));
- if (err)
- return err;
- }
- if (skb->len > count) {
- skb_queue_head(&cdev->recvqueue, skb);
- return -EMSGSIZE;
- }
- if (copy_to_user(buf, skb->data, skb->len)) {
- skb_queue_head(&cdev->recvqueue, skb);
- return -EFAULT;
- }
- copied = skb->len;
-
- kfree_skb(skb);
-
- return copied;
-}
-
-static ssize_t
-capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-{
- struct capidev *cdev = file->private_data;
- struct sk_buff *skb;
- u16 mlen;
-
- if (!cdev->ap.applid)
- return -ENODEV;
-
- if (count < CAPIMSG_BASELEN)
- return -EINVAL;
-
- skb = alloc_skb(count, GFP_USER);
- if (!skb)
- return -ENOMEM;
-
- if (copy_from_user(skb_put(skb, count), buf, count)) {
- kfree_skb(skb);
- return -EFAULT;
- }
- mlen = CAPIMSG_LEN(skb->data);
- if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
- if (count < CAPI_DATA_B3_REQ_LEN ||
- (size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) {
- kfree_skb(skb);
- return -EINVAL;
- }
- } else {
- if (mlen != count) {
- kfree_skb(skb);
- return -EINVAL;
- }
- }
- CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);
-
- if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
- if (count < CAPI_DISCONNECT_B3_RESP_LEN) {
- kfree_skb(skb);
- return -EINVAL;
- }
- mutex_lock(&cdev->lock);
- capincci_free(cdev, CAPIMSG_NCCI(skb->data));
- mutex_unlock(&cdev->lock);
- }
-
- cdev->errcode = capi20_put_message(&cdev->ap, skb);
-
- if (cdev->errcode) {
- kfree_skb(skb);
- return -EIO;
- }
- return count;
-}
-
-static __poll_t
-capi_poll(struct file *file, poll_table *wait)
-{
- struct capidev *cdev = file->private_data;
- __poll_t mask = 0;
-
- if (!cdev->ap.applid)
- return EPOLLERR;
-
- poll_wait(file, &(cdev->recvwait), wait);
- mask = EPOLLOUT | EPOLLWRNORM;
- if (!skb_queue_empty_lockless(&cdev->recvqueue))
- mask |= EPOLLIN | EPOLLRDNORM;
- return mask;
-}
-
-static int
-capi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct capidev *cdev = file->private_data;
- capi_ioctl_struct data;
- int retval = -EINVAL;
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
- case CAPI_REGISTER:
- mutex_lock(&cdev->lock);
-
- if (cdev->ap.applid) {
- retval = -EEXIST;
- goto register_out;
- }
- if (copy_from_user(&cdev->ap.rparam, argp,
- sizeof(struct capi_register_params))) {
- retval = -EFAULT;
- goto register_out;
- }
- cdev->ap.private = cdev;
- cdev->ap.recv_message = capi_recv_message;
- cdev->errcode = capi20_register(&cdev->ap);
- retval = (int)cdev->ap.applid;
- if (cdev->errcode) {
- cdev->ap.applid = 0;
- retval = -EIO;
- }
-
-register_out:
- mutex_unlock(&cdev->lock);
- return retval;
-
- case CAPI_GET_VERSION:
- if (copy_from_user(&data.contr, argp,
- sizeof(data.contr)))
- return -EFAULT;
- cdev->errcode = capi20_get_version(data.contr, &data.version);
- if (cdev->errcode)
- return -EIO;
- if (copy_to_user(argp, &data.version,
- sizeof(data.version)))
- return -EFAULT;
- return 0;
-
- case CAPI_GET_SERIAL:
- if (copy_from_user(&data.contr, argp,
- sizeof(data.contr)))
- return -EFAULT;
- cdev->errcode = capi20_get_serial(data.contr, data.serial);
- if (cdev->errcode)
- return -EIO;
- if (copy_to_user(argp, data.serial,
- sizeof(data.serial)))
- return -EFAULT;
- return 0;
-
- case CAPI_GET_PROFILE:
- if (copy_from_user(&data.contr, argp,
- sizeof(data.contr)))
- return -EFAULT;
-
- if (data.contr == 0) {
- cdev->errcode = capi20_get_profile(data.contr, &data.profile);
- if (cdev->errcode)
- return -EIO;
-
- retval = copy_to_user(argp,
- &data.profile.ncontroller,
- sizeof(data.profile.ncontroller));
-
- } else {
- cdev->errcode = capi20_get_profile(data.contr, &data.profile);
- if (cdev->errcode)
- return -EIO;
-
- retval = copy_to_user(argp, &data.profile,
- sizeof(data.profile));
- }
- if (retval)
- return -EFAULT;
- return 0;
-
- case CAPI_GET_MANUFACTURER:
- if (copy_from_user(&data.contr, argp,
- sizeof(data.contr)))
- return -EFAULT;
- cdev->errcode = capi20_get_manufacturer(data.contr, data.manufacturer);
- if (cdev->errcode)
- return -EIO;
-
- if (copy_to_user(argp, data.manufacturer,
- sizeof(data.manufacturer)))
- return -EFAULT;
-
- return 0;
-
- case CAPI_GET_ERRCODE:
- data.errcode = cdev->errcode;
- cdev->errcode = CAPI_NOERROR;
- if (arg) {
- if (copy_to_user(argp, &data.errcode,
- sizeof(data.errcode)))
- return -EFAULT;
- }
- return data.errcode;
-
- case CAPI_INSTALLED:
- if (capi20_isinstalled() == CAPI_NOERROR)
- return 0;
- return -ENXIO;
-
- case CAPI_MANUFACTURER_CMD: {
- struct capi_manufacturer_cmd mcmd;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (copy_from_user(&mcmd, argp, sizeof(mcmd)))
- return -EFAULT;
- return capi20_manufacturer(mcmd.cmd, mcmd.data);
- }
- case CAPI_SET_FLAGS:
- case CAPI_CLR_FLAGS: {
- unsigned userflags;
-
- if (copy_from_user(&userflags, argp, sizeof(userflags)))
- return -EFAULT;
-
- mutex_lock(&cdev->lock);
- if (cmd == CAPI_SET_FLAGS)
- cdev->userflags |= userflags;
- else
- cdev->userflags &= ~userflags;
- mutex_unlock(&cdev->lock);
- return 0;
- }
- case CAPI_GET_FLAGS:
- if (copy_to_user(argp, &cdev->userflags,
- sizeof(cdev->userflags)))
- return -EFAULT;
- return 0;
-
-#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
- case CAPI_NCCI_OPENCOUNT:
- return 0;
-
-#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- case CAPI_NCCI_OPENCOUNT: {
- struct capincci *nccip;
- unsigned ncci;
- int count = 0;
-
- if (copy_from_user(&ncci, argp, sizeof(ncci)))
- return -EFAULT;
-
- mutex_lock(&cdev->lock);
- nccip = capincci_find(cdev, (u32)ncci);
- if (nccip)
- count = capincci_minor_opencount(nccip);
- mutex_unlock(&cdev->lock);
- return count;
- }
-
- case CAPI_NCCI_GETUNIT: {
- struct capincci *nccip;
- struct capiminor *mp;
- unsigned ncci;
- int unit = -ESRCH;
-
- if (copy_from_user(&ncci, argp, sizeof(ncci)))
- return -EFAULT;
-
- mutex_lock(&cdev->lock);
- nccip = capincci_find(cdev, (u32)ncci);
- if (nccip) {
- mp = nccip->minorp;
- if (mp)
- unit = mp->minor;
- }
- mutex_unlock(&cdev->lock);
- return unit;
- }
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-
- default:
- return -EINVAL;
- }
-}
-
-static long
-capi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- mutex_lock(&capi_mutex);
- ret = capi_ioctl(file, cmd, arg);
- mutex_unlock(&capi_mutex);
-
- return ret;
-}
-
-#ifdef CONFIG_COMPAT
-static long
-capi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- if (cmd == CAPI_MANUFACTURER_CMD) {
- struct {
- compat_ulong_t cmd;
- compat_uptr_t data;
- } mcmd32;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (copy_from_user(&mcmd32, compat_ptr(arg), sizeof(mcmd32)))
- return -EFAULT;
-
- mutex_lock(&capi_mutex);
- ret = capi20_manufacturer(mcmd32.cmd, compat_ptr(mcmd32.data));
- mutex_unlock(&capi_mutex);
-
- return ret;
- }
-
- return capi_unlocked_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
-}
-#endif
-
-static int capi_open(struct inode *inode, struct file *file)
-{
- struct capidev *cdev;
-
- cdev = kzalloc_obj(*cdev);
- if (!cdev)
- return -ENOMEM;
-
- mutex_init(&cdev->lock);
- skb_queue_head_init(&cdev->recvqueue);
- init_waitqueue_head(&cdev->recvwait);
- INIT_LIST_HEAD(&cdev->nccis);
- file->private_data = cdev;
-
- mutex_lock(&capidev_list_lock);
- list_add_tail(&cdev->list, &capidev_list);
- mutex_unlock(&capidev_list_lock);
-
- return stream_open(inode, file);
-}
-
-static int capi_release(struct inode *inode, struct file *file)
-{
- struct capidev *cdev = file->private_data;
-
- mutex_lock(&capidev_list_lock);
- list_del(&cdev->list);
- mutex_unlock(&capidev_list_lock);
-
- if (cdev->ap.applid)
- capi20_release(&cdev->ap);
- skb_queue_purge(&cdev->recvqueue);
- capincci_free(cdev, 0xffffffff);
-
- kfree(cdev);
- return 0;
-}
-
-static const struct file_operations capi_fops =
-{
- .owner = THIS_MODULE,
- .read = capi_read,
- .write = capi_write,
- .poll = capi_poll,
- .unlocked_ioctl = capi_unlocked_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = capi_compat_ioctl,
-#endif
- .open = capi_open,
- .release = capi_release,
-};
-
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-/* -------- tty_operations for capincci ----------------------------- */
-
-static int
-capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
-{
- struct capiminor *mp = capiminor_get(tty->index);
- int ret = tty_standard_install(driver, tty);
-
- if (ret == 0)
- tty->driver_data = mp;
- else
- capiminor_put(mp);
- return ret;
-}
-
-static void capinc_tty_cleanup(struct tty_struct *tty)
-{
- struct capiminor *mp = tty->driver_data;
- tty->driver_data = NULL;
- capiminor_put(mp);
-}
-
-static int capinc_tty_open(struct tty_struct *tty, struct file *filp)
-{
- struct capiminor *mp = tty->driver_data;
- int err;
-
- err = tty_port_open(&mp->port, tty, filp);
- if (err)
- return err;
-
- handle_minor_recv(mp);
- return 0;
-}
-
-static void capinc_tty_close(struct tty_struct *tty, struct file *filp)
-{
- struct capiminor *mp = tty->driver_data;
-
- tty_port_close(&mp->port, tty, filp);
-}
-
-static ssize_t capinc_tty_write(struct tty_struct *tty, const u8 *buf,
- size_t count)
-{
- struct capiminor *mp = tty->driver_data;
- struct sk_buff *skb;
-
- pr_debug("capinc_tty_write(count=%zu)\n", count);
-
- spin_lock_bh(&mp->outlock);
- skb = mp->outskb;
- if (skb) {
- mp->outskb = NULL;
- __skb_queue_tail(&mp->outqueue, skb);
- mp->outbytes += skb->len;
- }
-
- skb = alloc_skb(CAPI_DATA_B3_REQ_LEN + count, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n");
- spin_unlock_bh(&mp->outlock);
- return -ENOMEM;
- }
-
- skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
- skb_put_data(skb, buf, count);
-
- __skb_queue_tail(&mp->outqueue, skb);
- mp->outbytes += skb->len;
- spin_unlock_bh(&mp->outlock);
-
- handle_minor_send(mp);
-
- return count;
-}
-
-static int capinc_tty_put_char(struct tty_struct *tty, u8 ch)
-{
- struct capiminor *mp = tty->driver_data;
- bool invoke_send = false;
- struct sk_buff *skb;
- int ret = 1;
-
- pr_debug("capinc_put_char(%u)\n", ch);
-
- spin_lock_bh(&mp->outlock);
- skb = mp->outskb;
- if (skb) {
- if (skb_tailroom(skb) > 0) {
- skb_put_u8(skb, ch);
- goto unlock_out;
- }
- mp->outskb = NULL;
- __skb_queue_tail(&mp->outqueue, skb);
- mp->outbytes += skb->len;
- invoke_send = true;
- }
-
- skb = alloc_skb(CAPI_DATA_B3_REQ_LEN + CAPI_MAX_BLKSIZE, GFP_ATOMIC);
- if (skb) {
- skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
- skb_put_u8(skb, ch);
- mp->outskb = skb;
- } else {
- printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
- ret = 0;
- }
-
-unlock_out:
- spin_unlock_bh(&mp->outlock);
-
- if (invoke_send)
- handle_minor_send(mp);
-
- return ret;
-}
-
-static void capinc_tty_flush_chars(struct tty_struct *tty)
-{
- struct capiminor *mp = tty->driver_data;
- struct sk_buff *skb;
-
- spin_lock_bh(&mp->outlock);
- skb = mp->outskb;
- if (skb) {
- mp->outskb = NULL;
- __skb_queue_tail(&mp->outqueue, skb);
- mp->outbytes += skb->len;
- spin_unlock_bh(&mp->outlock);
-
- handle_minor_send(mp);
- } else
- spin_unlock_bh(&mp->outlock);
-
- handle_minor_recv(mp);
-}
-
-static unsigned int capinc_tty_write_room(struct tty_struct *tty)
-{
- struct capiminor *mp = tty->driver_data;
- unsigned int room;
-
- room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
- room *= CAPI_MAX_BLKSIZE;
- pr_debug("capinc_tty_write_room = %u\n", room);
- return room;
-}
-
-static unsigned int capinc_tty_chars_in_buffer(struct tty_struct *tty)
-{
- struct capiminor *mp = tty->driver_data;
-
- pr_debug("capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n",
- mp->outbytes, mp->nack,
- skb_queue_len(&mp->outqueue),
- skb_queue_len(&mp->inqueue));
- return mp->outbytes;
-}
-
-static void capinc_tty_throttle(struct tty_struct *tty)
-{
- struct capiminor *mp = tty->driver_data;
- mp->ttyinstop = 1;
-}
-
-static void capinc_tty_unthrottle(struct tty_struct *tty)
-{
- struct capiminor *mp = tty->driver_data;
-
- mp->ttyinstop = 0;
- handle_minor_recv(mp);
-}
-
-static void capinc_tty_stop(struct tty_struct *tty)
-{
- struct capiminor *mp = tty->driver_data;
-
- mp->ttyoutstop = 1;
-}
-
-static void capinc_tty_start(struct tty_struct *tty)
-{
- struct capiminor *mp = tty->driver_data;
-
- mp->ttyoutstop = 0;
- handle_minor_send(mp);
-}
-
-static void capinc_tty_hangup(struct tty_struct *tty)
-{
- struct capiminor *mp = tty->driver_data;
-
- tty_port_hangup(&mp->port);
-}
-
-static void capinc_tty_send_xchar(struct tty_struct *tty, u8 ch)
-{
- pr_debug("capinc_tty_send_xchar(%u)\n", ch);
-}
-
-static const struct tty_operations capinc_ops = {
- .open = capinc_tty_open,
- .close = capinc_tty_close,
- .write = capinc_tty_write,
- .put_char = capinc_tty_put_char,
- .flush_chars = capinc_tty_flush_chars,
- .write_room = capinc_tty_write_room,
- .chars_in_buffer = capinc_tty_chars_in_buffer,
- .throttle = capinc_tty_throttle,
- .unthrottle = capinc_tty_unthrottle,
- .stop = capinc_tty_stop,
- .start = capinc_tty_start,
- .hangup = capinc_tty_hangup,
- .send_xchar = capinc_tty_send_xchar,
- .install = capinc_tty_install,
- .cleanup = capinc_tty_cleanup,
-};
-
-static int __init capinc_tty_init(void)
-{
- struct tty_driver *drv;
- int err;
-
- if (capi_ttyminors > CAPINC_MAX_PORTS)
- capi_ttyminors = CAPINC_MAX_PORTS;
- if (capi_ttyminors <= 0)
- capi_ttyminors = CAPINC_NR_PORTS;
-
- capiminors = kzalloc_objs(struct capiminor *, capi_ttyminors);
- if (!capiminors)
- return -ENOMEM;
-
- drv = tty_alloc_driver(capi_ttyminors, TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV);
- if (IS_ERR(drv)) {
- kfree(capiminors);
- return PTR_ERR(drv);
- }
- drv->driver_name = "capi_nc";
- drv->name = "capi!";
- drv->major = 0;
- drv->minor_start = 0;
- drv->type = TTY_DRIVER_TYPE_SERIAL;
- drv->subtype = SERIAL_TYPE_NORMAL;
- drv->init_termios = tty_std_termios;
- drv->init_termios.c_iflag = ICRNL;
- drv->init_termios.c_oflag = OPOST | ONLCR;
- drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- drv->init_termios.c_lflag = 0;
- tty_set_operations(drv, &capinc_ops);
-
- err = tty_register_driver(drv);
- if (err) {
- tty_driver_kref_put(drv);
- kfree(capiminors);
- printk(KERN_ERR "Couldn't register capi_nc driver\n");
- return err;
- }
- capinc_tty_driver = drv;
- return 0;
-}
-
-static void __exit capinc_tty_exit(void)
-{
- tty_unregister_driver(capinc_tty_driver);
- tty_driver_kref_put(capinc_tty_driver);
- kfree(capiminors);
-}
-
-#else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */
-
-static inline int capinc_tty_init(void)
-{
- return 0;
-}
-
-static inline void capinc_tty_exit(void) { }
-
-#endif /* !CONFIG_ISDN_CAPI_MIDDLEWARE */
-
-/* -------- /proc functions ----------------------------------------- */
-
-/*
- * /proc/capi/capi20:
- * minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
- */
-static int __maybe_unused capi20_proc_show(struct seq_file *m, void *v)
-{
- struct capidev *cdev;
- struct list_head *l;
-
- mutex_lock(&capidev_list_lock);
- list_for_each(l, &capidev_list) {
- cdev = list_entry(l, struct capidev, list);
- seq_printf(m, "0 %d %lu %lu %lu %lu\n",
- cdev->ap.applid,
- cdev->ap.nrecvctlpkt,
- cdev->ap.nrecvdatapkt,
- cdev->ap.nsentctlpkt,
- cdev->ap.nsentdatapkt);
- }
- mutex_unlock(&capidev_list_lock);
- return 0;
-}
-
-/*
- * /proc/capi/capi20ncci:
- * applid ncci
- */
-static int __maybe_unused capi20ncci_proc_show(struct seq_file *m, void *v)
-{
- struct capidev *cdev;
- struct capincci *np;
-
- mutex_lock(&capidev_list_lock);
- list_for_each_entry(cdev, &capidev_list, list) {
- mutex_lock(&cdev->lock);
- list_for_each_entry(np, &cdev->nccis, list)
- seq_printf(m, "%d 0x%x\n", cdev->ap.applid, np->ncci);
- mutex_unlock(&cdev->lock);
- }
- mutex_unlock(&capidev_list_lock);
- return 0;
-}
-
-static void __init proc_init(void)
-{
- proc_create_single("capi/capi20", 0, NULL, capi20_proc_show);
- proc_create_single("capi/capi20ncci", 0, NULL, capi20ncci_proc_show);
-}
-
-static void __exit proc_exit(void)
-{
- remove_proc_entry("capi/capi20", NULL);
- remove_proc_entry("capi/capi20ncci", NULL);
-}
-
-/* -------- init function and module interface ---------------------- */
-
-
-static int __init capi_init(void)
-{
- const char *compileinfo;
- int major_ret;
- int ret;
-
- ret = kcapi_init();
- if (ret)
- return ret;
-
- major_ret = register_chrdev(capi_major, "capi20", &capi_fops);
- if (major_ret < 0) {
- printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
- kcapi_exit();
- return major_ret;
- }
-
- ret = class_register(&capi_class);
- if (ret) {
- unregister_chrdev(capi_major, "capi20");
- kcapi_exit();
- return ret;
- }
-
- device_create(&capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi20");
-
- if (capinc_tty_init() < 0) {
- device_destroy(&capi_class, MKDEV(capi_major, 0));
- class_unregister(&capi_class);
- unregister_chrdev(capi_major, "capi20");
- kcapi_exit();
- return -ENOMEM;
- }
-
- proc_init();
-
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- compileinfo = " (middleware)";
-#else
- compileinfo = " (no middleware)";
-#endif
- printk(KERN_NOTICE "CAPI 2.0 started up with major %d%s\n",
- capi_major, compileinfo);
-
- return 0;
-}
-
-static void __exit capi_exit(void)
-{
- proc_exit();
-
- device_destroy(&capi_class, MKDEV(capi_major, 0));
- class_unregister(&capi_class);
- unregister_chrdev(capi_major, "capi20");
-
- capinc_tty_exit();
-
- kcapi_exit();
-}
-
-module_init(capi_init);
-module_exit(capi_exit);
+++ /dev/null
-/* $Id: capiutil.c,v 1.13.6.4 2001/09/23 22:24:33 kai Exp $
- *
- * CAPI 2.0 convert capi message to capi message struct
- *
- * From CAPI 2.0 Development Kit AVM 1995 (msg.c)
- * Rewritten for Linux 1996 by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/isdn/capiutil.h>
-#include <linux/slab.h>
-
-#include "kcapi.h"
-
-/* from CAPI2.0 DDK AVM Berlin GmbH */
-
-typedef struct {
- int typ;
- size_t off;
-} _cdef;
-
-#define _CBYTE 1
-#define _CWORD 2
-#define _CDWORD 3
-#define _CSTRUCT 4
-#define _CMSTRUCT 5
-#define _CEND 6
-
-static _cdef cdef[] =
-{
- /*00 */
- {_CEND},
- /*01 */
- {_CEND},
- /*02 */
- {_CEND},
- /*03 */
- {_CDWORD, offsetof(_cmsg, adr.adrController)},
- /*04 */
- {_CMSTRUCT, offsetof(_cmsg, AdditionalInfo)},
- /*05 */
- {_CSTRUCT, offsetof(_cmsg, B1configuration)},
- /*06 */
- {_CWORD, offsetof(_cmsg, B1protocol)},
- /*07 */
- {_CSTRUCT, offsetof(_cmsg, B2configuration)},
- /*08 */
- {_CWORD, offsetof(_cmsg, B2protocol)},
- /*09 */
- {_CSTRUCT, offsetof(_cmsg, B3configuration)},
- /*0a */
- {_CWORD, offsetof(_cmsg, B3protocol)},
- /*0b */
- {_CSTRUCT, offsetof(_cmsg, BC)},
- /*0c */
- {_CSTRUCT, offsetof(_cmsg, BChannelinformation)},
- /*0d */
- {_CMSTRUCT, offsetof(_cmsg, BProtocol)},
- /*0e */
- {_CSTRUCT, offsetof(_cmsg, CalledPartyNumber)},
- /*0f */
- {_CSTRUCT, offsetof(_cmsg, CalledPartySubaddress)},
- /*10 */
- {_CSTRUCT, offsetof(_cmsg, CallingPartyNumber)},
- /*11 */
- {_CSTRUCT, offsetof(_cmsg, CallingPartySubaddress)},
- /*12 */
- {_CDWORD, offsetof(_cmsg, CIPmask)},
- /*13 */
- {_CDWORD, offsetof(_cmsg, CIPmask2)},
- /*14 */
- {_CWORD, offsetof(_cmsg, CIPValue)},
- /*15 */
- {_CDWORD, offsetof(_cmsg, Class)},
- /*16 */
- {_CSTRUCT, offsetof(_cmsg, ConnectedNumber)},
- /*17 */
- {_CSTRUCT, offsetof(_cmsg, ConnectedSubaddress)},
- /*18 */
- {_CDWORD, offsetof(_cmsg, Data)},
- /*19 */
- {_CWORD, offsetof(_cmsg, DataHandle)},
- /*1a */
- {_CWORD, offsetof(_cmsg, DataLength)},
- /*1b */
- {_CSTRUCT, offsetof(_cmsg, FacilityConfirmationParameter)},
- /*1c */
- {_CSTRUCT, offsetof(_cmsg, Facilitydataarray)},
- /*1d */
- {_CSTRUCT, offsetof(_cmsg, FacilityIndicationParameter)},
- /*1e */
- {_CSTRUCT, offsetof(_cmsg, FacilityRequestParameter)},
- /*1f */
- {_CWORD, offsetof(_cmsg, FacilitySelector)},
- /*20 */
- {_CWORD, offsetof(_cmsg, Flags)},
- /*21 */
- {_CDWORD, offsetof(_cmsg, Function)},
- /*22 */
- {_CSTRUCT, offsetof(_cmsg, HLC)},
- /*23 */
- {_CWORD, offsetof(_cmsg, Info)},
- /*24 */
- {_CSTRUCT, offsetof(_cmsg, InfoElement)},
- /*25 */
- {_CDWORD, offsetof(_cmsg, InfoMask)},
- /*26 */
- {_CWORD, offsetof(_cmsg, InfoNumber)},
- /*27 */
- {_CSTRUCT, offsetof(_cmsg, Keypadfacility)},
- /*28 */
- {_CSTRUCT, offsetof(_cmsg, LLC)},
- /*29 */
- {_CSTRUCT, offsetof(_cmsg, ManuData)},
- /*2a */
- {_CDWORD, offsetof(_cmsg, ManuID)},
- /*2b */
- {_CSTRUCT, offsetof(_cmsg, NCPI)},
- /*2c */
- {_CWORD, offsetof(_cmsg, Reason)},
- /*2d */
- {_CWORD, offsetof(_cmsg, Reason_B3)},
- /*2e */
- {_CWORD, offsetof(_cmsg, Reject)},
- /*2f */
- {_CSTRUCT, offsetof(_cmsg, Useruserdata)}
-};
-
-static unsigned char *cpars[] =
-{
- /* ALERT_REQ */ [0x01] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
- /* CONNECT_REQ */ [0x02] = "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
- /* DISCONNECT_REQ */ [0x04] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
- /* LISTEN_REQ */ [0x05] = "\x03\x25\x12\x13\x10\x11\x01",
- /* INFO_REQ */ [0x08] = "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01",
- /* FACILITY_REQ */ [0x09] = "\x03\x1f\x1e\x01",
- /* SELECT_B_PROTOCOL_REQ */ [0x0a] = "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01",
- /* CONNECT_B3_REQ */ [0x0b] = "\x03\x2b\x01",
- /* DISCONNECT_B3_REQ */ [0x0d] = "\x03\x2b\x01",
- /* DATA_B3_REQ */ [0x0f] = "\x03\x18\x1a\x19\x20\x01",
- /* RESET_B3_REQ */ [0x10] = "\x03\x2b\x01",
- /* ALERT_CONF */ [0x13] = "\x03\x23\x01",
- /* CONNECT_CONF */ [0x14] = "\x03\x23\x01",
- /* DISCONNECT_CONF */ [0x16] = "\x03\x23\x01",
- /* LISTEN_CONF */ [0x17] = "\x03\x23\x01",
- /* MANUFACTURER_REQ */ [0x18] = "\x03\x2a\x15\x21\x29\x01",
- /* INFO_CONF */ [0x1a] = "\x03\x23\x01",
- /* FACILITY_CONF */ [0x1b] = "\x03\x23\x1f\x1b\x01",
- /* SELECT_B_PROTOCOL_CONF */ [0x1c] = "\x03\x23\x01",
- /* CONNECT_B3_CONF */ [0x1d] = "\x03\x23\x01",
- /* DISCONNECT_B3_CONF */ [0x1f] = "\x03\x23\x01",
- /* DATA_B3_CONF */ [0x21] = "\x03\x19\x23\x01",
- /* RESET_B3_CONF */ [0x22] = "\x03\x23\x01",
- /* CONNECT_IND */ [0x26] = "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
- /* CONNECT_ACTIVE_IND */ [0x27] = "\x03\x16\x17\x28\x01",
- /* DISCONNECT_IND */ [0x28] = "\x03\x2c\x01",
- /* MANUFACTURER_CONF */ [0x2a] = "\x03\x2a\x15\x21\x29\x01",
- /* INFO_IND */ [0x2c] = "\x03\x26\x24\x01",
- /* FACILITY_IND */ [0x2d] = "\x03\x1f\x1d\x01",
- /* CONNECT_B3_IND */ [0x2f] = "\x03\x2b\x01",
- /* CONNECT_B3_ACTIVE_IND */ [0x30] = "\x03\x2b\x01",
- /* DISCONNECT_B3_IND */ [0x31] = "\x03\x2d\x2b\x01",
- /* DATA_B3_IND */ [0x33] = "\x03\x18\x1a\x19\x20\x01",
- /* RESET_B3_IND */ [0x34] = "\x03\x2b\x01",
- /* CONNECT_B3_T90_ACTIVE_IND */ [0x35] = "\x03\x2b\x01",
- /* CONNECT_RESP */ [0x38] = "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01",
- /* CONNECT_ACTIVE_RESP */ [0x39] = "\x03\x01",
- /* DISCONNECT_RESP */ [0x3a] = "\x03\x01",
- /* MANUFACTURER_IND */ [0x3c] = "\x03\x2a\x15\x21\x29\x01",
- /* INFO_RESP */ [0x3e] = "\x03\x01",
- /* FACILITY_RESP */ [0x3f] = "\x03\x1f\x01",
- /* CONNECT_B3_RESP */ [0x41] = "\x03\x2e\x2b\x01",
- /* CONNECT_B3_ACTIVE_RESP */ [0x42] = "\x03\x01",
- /* DISCONNECT_B3_RESP */ [0x43] = "\x03\x01",
- /* DATA_B3_RESP */ [0x45] = "\x03\x19\x01",
- /* RESET_B3_RESP */ [0x46] = "\x03\x01",
- /* CONNECT_B3_T90_ACTIVE_RESP */ [0x47] = "\x03\x01",
- /* MANUFACTURER_RESP */ [0x4e] = "\x03\x2a\x15\x21\x29\x01",
-};
-
-/*-------------------------------------------------------*/
-
-#define byteTLcpy(x, y) *(u8 *)(x) = *(u8 *)(y);
-#define wordTLcpy(x, y) *(u16 *)(x) = *(u16 *)(y);
-#define dwordTLcpy(x, y) memcpy(x, y, 4);
-#define structTLcpy(x, y, l) memcpy(x, y, l)
-#define structTLcpyovl(x, y, l) memmove(x, y, l)
-
-#define byteTRcpy(x, y) *(u8 *)(y) = *(u8 *)(x);
-#define wordTRcpy(x, y) *(u16 *)(y) = *(u16 *)(x);
-#define dwordTRcpy(x, y) memcpy(y, x, 4);
-#define structTRcpy(x, y, l) memcpy(y, x, l)
-#define structTRcpyovl(x, y, l) memmove(y, x, l)
-
-/*-------------------------------------------------------*/
-static unsigned command_2_index(u8 c, u8 sc)
-{
- if (c & 0x80)
- c = 0x9 + (c & 0x0f);
- else if (c == 0x41)
- c = 0x9 + 0x1;
- if (c > 0x18)
- c = 0x00;
- return (sc & 3) * (0x9 + 0x9) + c;
-}
-
-/**
- * capi_cmd2par() - find parameter string for CAPI 2.0 command/subcommand
- * @cmd: command number
- * @subcmd: subcommand number
- *
- * Return value: static string, NULL if command/subcommand unknown
- */
-
-static unsigned char *capi_cmd2par(u8 cmd, u8 subcmd)
-{
- return cpars[command_2_index(cmd, subcmd)];
-}
-
-/*-------------------------------------------------------*/
-#define TYP (cdef[cmsg->par[cmsg->p]].typ)
-#define OFF (((u8 *)cmsg) + cdef[cmsg->par[cmsg->p]].off)
-
-static void jumpcstruct(_cmsg *cmsg)
-{
- unsigned layer;
- for (cmsg->p++, layer = 1; layer;) {
- /* $$$$$ assert (cmsg->p); */
- cmsg->p++;
- switch (TYP) {
- case _CMSTRUCT:
- layer++;
- break;
- case _CEND:
- layer--;
- break;
- }
- }
-}
-
-/*-------------------------------------------------------*/
-
-static char *mnames[] =
-{
- [0x01] = "ALERT_REQ",
- [0x02] = "CONNECT_REQ",
- [0x04] = "DISCONNECT_REQ",
- [0x05] = "LISTEN_REQ",
- [0x08] = "INFO_REQ",
- [0x09] = "FACILITY_REQ",
- [0x0a] = "SELECT_B_PROTOCOL_REQ",
- [0x0b] = "CONNECT_B3_REQ",
- [0x0d] = "DISCONNECT_B3_REQ",
- [0x0f] = "DATA_B3_REQ",
- [0x10] = "RESET_B3_REQ",
- [0x13] = "ALERT_CONF",
- [0x14] = "CONNECT_CONF",
- [0x16] = "DISCONNECT_CONF",
- [0x17] = "LISTEN_CONF",
- [0x18] = "MANUFACTURER_REQ",
- [0x1a] = "INFO_CONF",
- [0x1b] = "FACILITY_CONF",
- [0x1c] = "SELECT_B_PROTOCOL_CONF",
- [0x1d] = "CONNECT_B3_CONF",
- [0x1f] = "DISCONNECT_B3_CONF",
- [0x21] = "DATA_B3_CONF",
- [0x22] = "RESET_B3_CONF",
- [0x26] = "CONNECT_IND",
- [0x27] = "CONNECT_ACTIVE_IND",
- [0x28] = "DISCONNECT_IND",
- [0x2a] = "MANUFACTURER_CONF",
- [0x2c] = "INFO_IND",
- [0x2d] = "FACILITY_IND",
- [0x2f] = "CONNECT_B3_IND",
- [0x30] = "CONNECT_B3_ACTIVE_IND",
- [0x31] = "DISCONNECT_B3_IND",
- [0x33] = "DATA_B3_IND",
- [0x34] = "RESET_B3_IND",
- [0x35] = "CONNECT_B3_T90_ACTIVE_IND",
- [0x38] = "CONNECT_RESP",
- [0x39] = "CONNECT_ACTIVE_RESP",
- [0x3a] = "DISCONNECT_RESP",
- [0x3c] = "MANUFACTURER_IND",
- [0x3e] = "INFO_RESP",
- [0x3f] = "FACILITY_RESP",
- [0x41] = "CONNECT_B3_RESP",
- [0x42] = "CONNECT_B3_ACTIVE_RESP",
- [0x43] = "DISCONNECT_B3_RESP",
- [0x45] = "DATA_B3_RESP",
- [0x46] = "RESET_B3_RESP",
- [0x47] = "CONNECT_B3_T90_ACTIVE_RESP",
- [0x4e] = "MANUFACTURER_RESP"
-};
-
-/**
- * capi_cmd2str() - convert CAPI 2.0 command/subcommand number to name
- * @cmd: command number
- * @subcmd: subcommand number
- *
- * Return value: static string
- */
-
-char *capi_cmd2str(u8 cmd, u8 subcmd)
-{
- char *result;
-
- result = mnames[command_2_index(cmd, subcmd)];
- if (result == NULL)
- result = "INVALID_COMMAND";
- return result;
-}
-
-
-/*-------------------------------------------------------*/
-
-#ifdef CONFIG_CAPI_TRACE
-
-/*-------------------------------------------------------*/
-
-static char *pnames[] =
-{
- /*00 */ NULL,
- /*01 */ NULL,
- /*02 */ NULL,
- /*03 */ "Controller/PLCI/NCCI",
- /*04 */ "AdditionalInfo",
- /*05 */ "B1configuration",
- /*06 */ "B1protocol",
- /*07 */ "B2configuration",
- /*08 */ "B2protocol",
- /*09 */ "B3configuration",
- /*0a */ "B3protocol",
- /*0b */ "BC",
- /*0c */ "BChannelinformation",
- /*0d */ "BProtocol",
- /*0e */ "CalledPartyNumber",
- /*0f */ "CalledPartySubaddress",
- /*10 */ "CallingPartyNumber",
- /*11 */ "CallingPartySubaddress",
- /*12 */ "CIPmask",
- /*13 */ "CIPmask2",
- /*14 */ "CIPValue",
- /*15 */ "Class",
- /*16 */ "ConnectedNumber",
- /*17 */ "ConnectedSubaddress",
- /*18 */ "Data32",
- /*19 */ "DataHandle",
- /*1a */ "DataLength",
- /*1b */ "FacilityConfirmationParameter",
- /*1c */ "Facilitydataarray",
- /*1d */ "FacilityIndicationParameter",
- /*1e */ "FacilityRequestParameter",
- /*1f */ "FacilitySelector",
- /*20 */ "Flags",
- /*21 */ "Function",
- /*22 */ "HLC",
- /*23 */ "Info",
- /*24 */ "InfoElement",
- /*25 */ "InfoMask",
- /*26 */ "InfoNumber",
- /*27 */ "Keypadfacility",
- /*28 */ "LLC",
- /*29 */ "ManuData",
- /*2a */ "ManuID",
- /*2b */ "NCPI",
- /*2c */ "Reason",
- /*2d */ "Reason_B3",
- /*2e */ "Reject",
- /*2f */ "Useruserdata"
-};
-
-#include <linux/stdarg.h>
-
-/*-------------------------------------------------------*/
-static _cdebbuf *bufprint(_cdebbuf *cdb, char *fmt, ...)
-{
- va_list f;
- size_t n, r;
-
- if (!cdb)
- return NULL;
- va_start(f, fmt);
- r = cdb->size - cdb->pos;
- n = vsnprintf(cdb->p, r, fmt, f);
- va_end(f);
- if (n >= r) {
- /* truncated, need bigger buffer */
- size_t ns = 2 * cdb->size;
- u_char *nb;
-
- while ((ns - cdb->pos) <= n)
- ns *= 2;
- nb = kmalloc(ns, GFP_ATOMIC);
- if (!nb) {
- cdebbuf_free(cdb);
- return NULL;
- }
- memcpy(nb, cdb->buf, cdb->pos);
- kfree(cdb->buf);
- nb[cdb->pos] = 0;
- cdb->buf = nb;
- cdb->p = cdb->buf + cdb->pos;
- cdb->size = ns;
- va_start(f, fmt);
- r = cdb->size - cdb->pos;
- n = vsnprintf(cdb->p, r, fmt, f);
- va_end(f);
- }
- cdb->p += n;
- cdb->pos += n;
- return cdb;
-}
-
-static _cdebbuf *printstructlen(_cdebbuf *cdb, u8 *m, unsigned len)
-{
- unsigned hex = 0;
-
- if (!cdb)
- return NULL;
- for (; len; len--, m++)
- if (isalnum(*m) || *m == ' ') {
- if (hex)
- cdb = bufprint(cdb, ">");
- cdb = bufprint(cdb, "%c", *m);
- hex = 0;
- } else {
- if (!hex)
- cdb = bufprint(cdb, "<%02x", *m);
- else
- cdb = bufprint(cdb, " %02x", *m);
- hex = 1;
- }
- if (hex)
- cdb = bufprint(cdb, ">");
- return cdb;
-}
-
-static _cdebbuf *printstruct(_cdebbuf *cdb, u8 *m)
-{
- unsigned len;
-
- if (m[0] != 0xff) {
- len = m[0];
- m += 1;
- } else {
- len = ((u16 *) (m + 1))[0];
- m += 3;
- }
- cdb = printstructlen(cdb, m, len);
- return cdb;
-}
-
-/*-------------------------------------------------------*/
-#define NAME (pnames[cmsg->par[cmsg->p]])
-
-static _cdebbuf *protocol_message_2_pars(_cdebbuf *cdb, _cmsg *cmsg, int level)
-{
- if (!cmsg->par)
- return NULL; /* invalid command/subcommand */
-
- for (; TYP != _CEND; cmsg->p++) {
- int slen = 29 + 3 - level;
- int i;
-
- if (!cdb)
- return NULL;
- cdb = bufprint(cdb, " ");
- for (i = 0; i < level - 1; i++)
- cdb = bufprint(cdb, " ");
-
- switch (TYP) {
- case _CBYTE:
- cdb = bufprint(cdb, "%-*s = 0x%x\n", slen, NAME, *(u8 *) (cmsg->m + cmsg->l));
- cmsg->l++;
- break;
- case _CWORD:
- cdb = bufprint(cdb, "%-*s = 0x%x\n", slen, NAME, *(u16 *) (cmsg->m + cmsg->l));
- cmsg->l += 2;
- break;
- case _CDWORD:
- cdb = bufprint(cdb, "%-*s = 0x%lx\n", slen, NAME, *(u32 *) (cmsg->m + cmsg->l));
- cmsg->l += 4;
- break;
- case _CSTRUCT:
- cdb = bufprint(cdb, "%-*s = ", slen, NAME);
- if (cmsg->m[cmsg->l] == '\0')
- cdb = bufprint(cdb, "default");
- else
- cdb = printstruct(cdb, cmsg->m + cmsg->l);
- cdb = bufprint(cdb, "\n");
- if (cmsg->m[cmsg->l] != 0xff)
- cmsg->l += 1 + cmsg->m[cmsg->l];
- else
- cmsg->l += 3 + *(u16 *) (cmsg->m + cmsg->l + 1);
-
- break;
-
- case _CMSTRUCT:
-/*----- Metastruktur 0 -----*/
- if (cmsg->m[cmsg->l] == '\0') {
- cdb = bufprint(cdb, "%-*s = default\n", slen, NAME);
- cmsg->l++;
- jumpcstruct(cmsg);
- } else {
- char *name = NAME;
- unsigned _l = cmsg->l;
- cdb = bufprint(cdb, "%-*s\n", slen, name);
- cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
- cmsg->p++;
- cdb = protocol_message_2_pars(cdb, cmsg, level + 1);
- }
- break;
- }
- }
- return cdb;
-}
-/*-------------------------------------------------------*/
-
-static _cdebbuf *g_debbuf;
-static u_long g_debbuf_lock;
-static _cmsg *g_cmsg;
-
-static _cdebbuf *cdebbuf_alloc(void)
-{
- _cdebbuf *cdb;
-
- if (likely(!test_and_set_bit(1, &g_debbuf_lock))) {
- cdb = g_debbuf;
- goto init;
- } else
- cdb = kmalloc_obj(_cdebbuf, GFP_ATOMIC);
- if (!cdb)
- return NULL;
- cdb->buf = kmalloc(CDEBUG_SIZE, GFP_ATOMIC);
- if (!cdb->buf) {
- kfree(cdb);
- return NULL;
- }
- cdb->size = CDEBUG_SIZE;
-init:
- cdb->buf[0] = 0;
- cdb->p = cdb->buf;
- cdb->pos = 0;
- return cdb;
-}
-
-/**
- * cdebbuf_free() - free CAPI debug buffer
- * @cdb: buffer to free
- */
-
-void cdebbuf_free(_cdebbuf *cdb)
-{
- if (likely(cdb == g_debbuf)) {
- test_and_clear_bit(1, &g_debbuf_lock);
- return;
- }
- if (likely(cdb))
- kfree(cdb->buf);
- kfree(cdb);
-}
-
-
-/**
- * capi_message2str() - format CAPI 2.0 message for printing
- * @msg: CAPI 2.0 message
- *
- * Allocates a CAPI debug buffer and fills it with a printable representation
- * of the CAPI 2.0 message in @msg.
- * Return value: allocated debug buffer, NULL on error
- * The returned buffer should be freed by a call to cdebbuf_free() after use.
- */
-
-_cdebbuf *capi_message2str(u8 *msg)
-{
- _cdebbuf *cdb;
- _cmsg *cmsg;
-
- cdb = cdebbuf_alloc();
- if (unlikely(!cdb))
- return NULL;
- if (likely(cdb == g_debbuf))
- cmsg = g_cmsg;
- else
- cmsg = kmalloc_obj(_cmsg, GFP_ATOMIC);
- if (unlikely(!cmsg)) {
- cdebbuf_free(cdb);
- return NULL;
- }
- cmsg->m = msg;
- cmsg->l = 8;
- cmsg->p = 0;
- byteTRcpy(cmsg->m + 4, &cmsg->Command);
- byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
- cmsg->par = capi_cmd2par(cmsg->Command, cmsg->Subcommand);
-
- cdb = bufprint(cdb, "%-26s ID=%03d #0x%04x LEN=%04d\n",
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- ((unsigned short *) msg)[1],
- ((unsigned short *) msg)[3],
- ((unsigned short *) msg)[0]);
-
- cdb = protocol_message_2_pars(cdb, cmsg, 1);
- if (unlikely(cmsg != g_cmsg))
- kfree(cmsg);
- return cdb;
-}
-
-int __init cdebug_init(void)
-{
- g_cmsg = kmalloc_obj(_cmsg);
- if (!g_cmsg)
- return -ENOMEM;
- g_debbuf = kmalloc_obj(_cdebbuf);
- if (!g_debbuf) {
- kfree(g_cmsg);
- return -ENOMEM;
- }
- g_debbuf->buf = kmalloc(CDEBUG_GSIZE, GFP_KERNEL);
- if (!g_debbuf->buf) {
- kfree(g_cmsg);
- kfree(g_debbuf);
- return -ENOMEM;
- }
- g_debbuf->size = CDEBUG_GSIZE;
- g_debbuf->buf[0] = 0;
- g_debbuf->p = g_debbuf->buf;
- g_debbuf->pos = 0;
- return 0;
-}
-
-void cdebug_exit(void)
-{
- if (g_debbuf)
- kfree(g_debbuf->buf);
- kfree(g_debbuf);
- kfree(g_cmsg);
-}
-
-#else /* !CONFIG_CAPI_TRACE */
-
-static _cdebbuf g_debbuf = {"CONFIG_CAPI_TRACE not enabled", NULL, 0, 0};
-
-_cdebbuf *capi_message2str(u8 *msg)
-{
- return &g_debbuf;
-}
-
-_cdebbuf *capi_cmsg2str(_cmsg *cmsg)
-{
- return &g_debbuf;
-}
-
-void cdebbuf_free(_cdebbuf *cdb)
-{
-}
-
-int __init cdebug_init(void)
-{
- return 0;
-}
-
-void cdebug_exit(void)
-{
-}
-
-#endif
+++ /dev/null
-/* $Id: kcapi.c,v 1.1.2.8 2004/03/26 19:57:20 armin Exp $
- *
- * Kernel CAPI 2.0 Module
- *
- * Copyright 1999 by Carsten Paeth <calle@calle.de>
- * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include "kcapi.h"
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/proc_fs.h>
-#include <linux/sched/signal.h>
-#include <linux/seq_file.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-#include <linux/capi.h>
-#include <linux/kernelcapi.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/isdn/capicmd.h>
-#include <linux/isdn/capiutil.h>
-#include <linux/mutex.h>
-#include <linux/rcupdate.h>
-
-static int showcapimsgs;
-static struct workqueue_struct *kcapi_wq;
-
-module_param(showcapimsgs, uint, 0);
-
-/* ------------------------------------------------------------- */
-
-struct capictr_event {
- struct work_struct work;
- unsigned int type;
- u32 controller;
-};
-
-/* ------------------------------------------------------------- */
-
-static const struct capi_version driver_version = {2, 0, 1, 1 << 4};
-static char driver_serial[CAPI_SERIAL_LEN] = "0004711";
-static char capi_manufakturer[64] = "AVM Berlin";
-
-#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
-
-struct capi_ctr *capi_controller[CAPI_MAXCONTR];
-DEFINE_MUTEX(capi_controller_lock);
-
-struct capi20_appl *capi_applications[CAPI_MAXAPPL];
-
-static int ncontrollers;
-
-/* -------- controller ref counting -------------------------------------- */
-
-static inline struct capi_ctr *
-capi_ctr_get(struct capi_ctr *ctr)
-{
- if (!try_module_get(ctr->owner))
- return NULL;
- return ctr;
-}
-
-static inline void
-capi_ctr_put(struct capi_ctr *ctr)
-{
- module_put(ctr->owner);
-}
-
-/* ------------------------------------------------------------- */
-
-static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
-{
- if (contr < 1 || contr - 1 >= CAPI_MAXCONTR)
- return NULL;
-
- return capi_controller[contr - 1];
-}
-
-static inline struct capi20_appl *__get_capi_appl_by_nr(u16 applid)
-{
- lockdep_assert_held(&capi_controller_lock);
-
- if (applid < 1 || applid - 1 >= CAPI_MAXAPPL)
- return NULL;
-
- return capi_applications[applid - 1];
-}
-
-static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
-{
- if (applid < 1 || applid - 1 >= CAPI_MAXAPPL)
- return NULL;
-
- return rcu_dereference(capi_applications[applid - 1]);
-}
-
-/* -------- util functions ------------------------------------ */
-
-static inline int capi_cmd_valid(u8 cmd)
-{
- switch (cmd) {
- case CAPI_ALERT:
- case CAPI_CONNECT:
- case CAPI_CONNECT_ACTIVE:
- case CAPI_CONNECT_B3_ACTIVE:
- case CAPI_CONNECT_B3:
- case CAPI_CONNECT_B3_T90_ACTIVE:
- case CAPI_DATA_B3:
- case CAPI_DISCONNECT_B3:
- case CAPI_DISCONNECT:
- case CAPI_FACILITY:
- case CAPI_INFO:
- case CAPI_LISTEN:
- case CAPI_MANUFACTURER:
- case CAPI_RESET_B3:
- case CAPI_SELECT_B_PROTOCOL:
- return 1;
- }
- return 0;
-}
-
-static inline int capi_subcmd_valid(u8 subcmd)
-{
- switch (subcmd) {
- case CAPI_REQ:
- case CAPI_CONF:
- case CAPI_IND:
- case CAPI_RESP:
- return 1;
- }
- return 0;
-}
-
-/* ------------------------------------------------------------ */
-
-static void
-register_appl(struct capi_ctr *ctr, u16 applid, capi_register_params *rparam)
-{
- ctr = capi_ctr_get(ctr);
-
- if (ctr)
- ctr->register_appl(ctr, applid, rparam);
- else
- printk(KERN_WARNING "%s: cannot get controller resources\n",
- __func__);
-}
-
-
-static void release_appl(struct capi_ctr *ctr, u16 applid)
-{
- DBG("applid %#x", applid);
-
- ctr->release_appl(ctr, applid);
- capi_ctr_put(ctr);
-}
-
-static void notify_up(u32 contr)
-{
- struct capi20_appl *ap;
- struct capi_ctr *ctr;
- u16 applid;
-
- mutex_lock(&capi_controller_lock);
-
- if (showcapimsgs & 1)
- printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
-
- ctr = get_capi_ctr_by_nr(contr);
- if (ctr) {
- if (ctr->state == CAPI_CTR_RUNNING)
- goto unlock_out;
-
- ctr->state = CAPI_CTR_RUNNING;
-
- for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
- ap = __get_capi_appl_by_nr(applid);
- if (ap)
- register_appl(ctr, applid, &ap->rparam);
- }
- } else
- printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
-
-unlock_out:
- mutex_unlock(&capi_controller_lock);
-}
-
-static void ctr_down(struct capi_ctr *ctr, int new_state)
-{
- struct capi20_appl *ap;
- u16 applid;
-
- if (ctr->state == CAPI_CTR_DETECTED || ctr->state == CAPI_CTR_DETACHED)
- return;
-
- ctr->state = new_state;
-
- memset(ctr->manu, 0, sizeof(ctr->manu));
- memset(&ctr->version, 0, sizeof(ctr->version));
- memset(&ctr->profile, 0, sizeof(ctr->profile));
- memset(ctr->serial, 0, sizeof(ctr->serial));
-
- for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
- ap = __get_capi_appl_by_nr(applid);
- if (ap)
- capi_ctr_put(ctr);
- }
-}
-
-static void notify_down(u32 contr)
-{
- struct capi_ctr *ctr;
-
- mutex_lock(&capi_controller_lock);
-
- if (showcapimsgs & 1)
- printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
-
- ctr = get_capi_ctr_by_nr(contr);
- if (ctr)
- ctr_down(ctr, CAPI_CTR_DETECTED);
- else
- printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
-
- mutex_unlock(&capi_controller_lock);
-}
-
-static void do_notify_work(struct work_struct *work)
-{
- struct capictr_event *event =
- container_of(work, struct capictr_event, work);
-
- switch (event->type) {
- case CAPICTR_UP:
- notify_up(event->controller);
- break;
- case CAPICTR_DOWN:
- notify_down(event->controller);
- break;
- }
-
- kfree(event);
-}
-
-static int notify_push(unsigned int event_type, u32 controller)
-{
- struct capictr_event *event = kmalloc_obj(*event, GFP_ATOMIC);
-
- if (!event)
- return -ENOMEM;
-
- INIT_WORK(&event->work, do_notify_work);
- event->type = event_type;
- event->controller = controller;
-
- queue_work(kcapi_wq, &event->work);
- return 0;
-}
-
-/* -------- Receiver ------------------------------------------ */
-
-static void recv_handler(struct work_struct *work)
-{
- struct sk_buff *skb;
- struct capi20_appl *ap =
- container_of(work, struct capi20_appl, recv_work);
-
- if ((!ap) || (ap->release_in_progress))
- return;
-
- mutex_lock(&ap->recv_mtx);
- while ((skb = skb_dequeue(&ap->recv_queue))) {
- if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
- ap->nrecvdatapkt++;
- else
- ap->nrecvctlpkt++;
-
- ap->recv_message(ap, skb);
- }
- mutex_unlock(&ap->recv_mtx);
-}
-
-/**
- * capi_ctr_handle_message() - handle incoming CAPI message
- * @ctr: controller descriptor structure.
- * @appl: application ID.
- * @skb: message.
- *
- * Called by hardware driver to pass a CAPI message to the application.
- */
-
-void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
- struct sk_buff *skb)
-{
- struct capi20_appl *ap;
- int showctl = 0;
- u8 cmd, subcmd;
- _cdebbuf *cdb;
-
- if (ctr->state != CAPI_CTR_RUNNING) {
- cdb = capi_message2str(skb->data);
- if (cdb) {
- printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s",
- ctr->cnr, cdb->buf);
- cdebbuf_free(cdb);
- } else
- printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n",
- ctr->cnr);
- goto error;
- }
-
- cmd = CAPIMSG_COMMAND(skb->data);
- subcmd = CAPIMSG_SUBCOMMAND(skb->data);
- if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
- ctr->nrecvdatapkt++;
- if (ctr->traceflag > 2)
- showctl |= 2;
- } else {
- ctr->nrecvctlpkt++;
- if (ctr->traceflag)
- showctl |= 2;
- }
- showctl |= (ctr->traceflag & 1);
- if (showctl & 2) {
- if (showctl & 1) {
- printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n",
- ctr->cnr, CAPIMSG_APPID(skb->data),
- capi_cmd2str(cmd, subcmd),
- CAPIMSG_LEN(skb->data));
- } else {
- cdb = capi_message2str(skb->data);
- if (cdb) {
- printk(KERN_DEBUG "kcapi: got [%03d] %s\n",
- ctr->cnr, cdb->buf);
- cdebbuf_free(cdb);
- } else
- printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n",
- ctr->cnr, CAPIMSG_APPID(skb->data),
- capi_cmd2str(cmd, subcmd),
- CAPIMSG_LEN(skb->data));
- }
-
- }
-
- rcu_read_lock();
- ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
- if (!ap) {
- rcu_read_unlock();
- cdb = capi_message2str(skb->data);
- if (cdb) {
- printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
- CAPIMSG_APPID(skb->data), cdb->buf);
- cdebbuf_free(cdb);
- } else
- printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n",
- CAPIMSG_APPID(skb->data),
- capi_cmd2str(cmd, subcmd));
- goto error;
- }
- skb_queue_tail(&ap->recv_queue, skb);
- queue_work(kcapi_wq, &ap->recv_work);
- rcu_read_unlock();
-
- return;
-
-error:
- kfree_skb(skb);
-}
-
-EXPORT_SYMBOL(capi_ctr_handle_message);
-
-/**
- * capi_ctr_ready() - signal CAPI controller ready
- * @ctr: controller descriptor structure.
- *
- * Called by hardware driver to signal that the controller is up and running.
- */
-
-void capi_ctr_ready(struct capi_ctr *ctr)
-{
- printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n",
- ctr->cnr, ctr->name);
-
- notify_push(CAPICTR_UP, ctr->cnr);
-}
-
-EXPORT_SYMBOL(capi_ctr_ready);
-
-/**
- * capi_ctr_down() - signal CAPI controller not ready
- * @ctr: controller descriptor structure.
- *
- * Called by hardware driver to signal that the controller is down and
- * unavailable for use.
- */
-
-void capi_ctr_down(struct capi_ctr *ctr)
-{
- printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr);
-
- notify_push(CAPICTR_DOWN, ctr->cnr);
-}
-
-EXPORT_SYMBOL(capi_ctr_down);
-
-/* ------------------------------------------------------------- */
-
-/**
- * attach_capi_ctr() - register CAPI controller
- * @ctr: controller descriptor structure.
- *
- * Called by hardware driver to register a controller with the CAPI subsystem.
- * Return value: 0 on success, error code < 0 on error
- */
-
-int attach_capi_ctr(struct capi_ctr *ctr)
-{
- int i;
-
- mutex_lock(&capi_controller_lock);
-
- for (i = 0; i < CAPI_MAXCONTR; i++) {
- if (!capi_controller[i])
- break;
- }
- if (i == CAPI_MAXCONTR) {
- mutex_unlock(&capi_controller_lock);
- printk(KERN_ERR "kcapi: out of controller slots\n");
- return -EBUSY;
- }
- capi_controller[i] = ctr;
-
- ctr->nrecvctlpkt = 0;
- ctr->nrecvdatapkt = 0;
- ctr->nsentctlpkt = 0;
- ctr->nsentdatapkt = 0;
- ctr->cnr = i + 1;
- ctr->state = CAPI_CTR_DETECTED;
- ctr->blocked = 0;
- ctr->traceflag = showcapimsgs;
-
- sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr);
- ctr->procent = proc_create_single_data(ctr->procfn, 0, NULL,
- ctr->proc_show, ctr);
-
- ncontrollers++;
-
- mutex_unlock(&capi_controller_lock);
-
- printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n",
- ctr->cnr, ctr->name);
- return 0;
-}
-
-EXPORT_SYMBOL(attach_capi_ctr);
-
-/**
- * detach_capi_ctr() - unregister CAPI controller
- * @ctr: controller descriptor structure.
- *
- * Called by hardware driver to remove the registration of a controller
- * with the CAPI subsystem.
- * Return value: 0 on success, error code < 0 on error
- */
-
-int detach_capi_ctr(struct capi_ctr *ctr)
-{
- int err = 0;
-
- mutex_lock(&capi_controller_lock);
-
- ctr_down(ctr, CAPI_CTR_DETACHED);
-
- if (ctr->cnr < 1 || ctr->cnr - 1 >= CAPI_MAXCONTR) {
- err = -EINVAL;
- goto unlock_out;
- }
-
- if (capi_controller[ctr->cnr - 1] != ctr) {
- err = -EINVAL;
- goto unlock_out;
- }
- capi_controller[ctr->cnr - 1] = NULL;
- ncontrollers--;
-
- if (ctr->procent)
- remove_proc_entry(ctr->procfn, NULL);
-
- printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n",
- ctr->cnr, ctr->name);
-
-unlock_out:
- mutex_unlock(&capi_controller_lock);
-
- return err;
-}
-
-EXPORT_SYMBOL(detach_capi_ctr);
-
-/* ------------------------------------------------------------- */
-/* -------- CAPI2.0 Interface ---------------------------------- */
-/* ------------------------------------------------------------- */
-
-/**
- * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED
- *
- * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller
- * is ready for use, CAPI_REGNOTINSTALLED otherwise)
- */
-
-u16 capi20_isinstalled(void)
-{
- u16 ret = CAPI_REGNOTINSTALLED;
- int i;
-
- mutex_lock(&capi_controller_lock);
-
- for (i = 0; i < CAPI_MAXCONTR; i++)
- if (capi_controller[i] &&
- capi_controller[i]->state == CAPI_CTR_RUNNING) {
- ret = CAPI_NOERROR;
- break;
- }
-
- mutex_unlock(&capi_controller_lock);
-
- return ret;
-}
-
-/**
- * capi20_register() - CAPI 2.0 operation CAPI_REGISTER
- * @ap: CAPI application descriptor structure.
- *
- * Register an application's presence with CAPI.
- * A unique application ID is assigned and stored in @ap->applid.
- * After this function returns successfully, the message receive
- * callback function @ap->recv_message() may be called at any time
- * until capi20_release() has been called for the same @ap.
- * Return value: CAPI result code
- */
-
-u16 capi20_register(struct capi20_appl *ap)
-{
- int i;
- u16 applid;
-
- DBG("");
-
- if (ap->rparam.datablklen < 128)
- return CAPI_LOGBLKSIZETOSMALL;
-
- ap->nrecvctlpkt = 0;
- ap->nrecvdatapkt = 0;
- ap->nsentctlpkt = 0;
- ap->nsentdatapkt = 0;
- mutex_init(&ap->recv_mtx);
- skb_queue_head_init(&ap->recv_queue);
- INIT_WORK(&ap->recv_work, recv_handler);
- ap->release_in_progress = 0;
-
- mutex_lock(&capi_controller_lock);
-
- for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
- if (capi_applications[applid - 1] == NULL)
- break;
- }
- if (applid > CAPI_MAXAPPL) {
- mutex_unlock(&capi_controller_lock);
- return CAPI_TOOMANYAPPLS;
- }
-
- ap->applid = applid;
- capi_applications[applid - 1] = ap;
-
- for (i = 0; i < CAPI_MAXCONTR; i++) {
- if (!capi_controller[i] ||
- capi_controller[i]->state != CAPI_CTR_RUNNING)
- continue;
- register_appl(capi_controller[i], applid, &ap->rparam);
- }
-
- mutex_unlock(&capi_controller_lock);
-
- if (showcapimsgs & 1) {
- printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
- }
-
- return CAPI_NOERROR;
-}
-
-/**
- * capi20_release() - CAPI 2.0 operation CAPI_RELEASE
- * @ap: CAPI application descriptor structure.
- *
- * Terminate an application's registration with CAPI.
- * After this function returns successfully, the message receive
- * callback function @ap->recv_message() will no longer be called.
- * Return value: CAPI result code
- */
-
-u16 capi20_release(struct capi20_appl *ap)
-{
- int i;
-
- DBG("applid %#x", ap->applid);
-
- mutex_lock(&capi_controller_lock);
-
- ap->release_in_progress = 1;
- capi_applications[ap->applid - 1] = NULL;
-
- synchronize_rcu();
-
- for (i = 0; i < CAPI_MAXCONTR; i++) {
- if (!capi_controller[i] ||
- capi_controller[i]->state != CAPI_CTR_RUNNING)
- continue;
- release_appl(capi_controller[i], ap->applid);
- }
-
- mutex_unlock(&capi_controller_lock);
-
- flush_workqueue(kcapi_wq);
- skb_queue_purge(&ap->recv_queue);
-
- if (showcapimsgs & 1) {
- printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
- }
-
- return CAPI_NOERROR;
-}
-
-/**
- * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE
- * @ap: CAPI application descriptor structure.
- * @skb: CAPI message.
- *
- * Transfer a single message to CAPI.
- * Return value: CAPI result code
- */
-
-u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
-{
- struct capi_ctr *ctr;
- int showctl = 0;
- u8 cmd, subcmd;
-
- DBG("applid %#x", ap->applid);
-
- if (ncontrollers == 0)
- return CAPI_REGNOTINSTALLED;
- if ((ap->applid == 0) || ap->release_in_progress)
- return CAPI_ILLAPPNR;
- if (skb->len < 12
- || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
- || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
- return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
-
- /*
- * The controller reference is protected by the existence of the
- * application passed to us. We assume that the caller properly
- * synchronizes this service with capi20_release.
- */
- ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
- if (!ctr || ctr->state != CAPI_CTR_RUNNING)
- return CAPI_REGNOTINSTALLED;
- if (ctr->blocked)
- return CAPI_SENDQUEUEFULL;
-
- cmd = CAPIMSG_COMMAND(skb->data);
- subcmd = CAPIMSG_SUBCOMMAND(skb->data);
-
- if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) {
- ctr->nsentdatapkt++;
- ap->nsentdatapkt++;
- if (ctr->traceflag > 2)
- showctl |= 2;
- } else {
- ctr->nsentctlpkt++;
- ap->nsentctlpkt++;
- if (ctr->traceflag)
- showctl |= 2;
- }
- showctl |= (ctr->traceflag & 1);
- if (showctl & 2) {
- if (showctl & 1) {
- printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
- CAPIMSG_CONTROLLER(skb->data),
- CAPIMSG_APPID(skb->data),
- capi_cmd2str(cmd, subcmd),
- CAPIMSG_LEN(skb->data));
- } else {
- _cdebbuf *cdb = capi_message2str(skb->data);
- if (cdb) {
- printk(KERN_DEBUG "kcapi: put [%03d] %s\n",
- CAPIMSG_CONTROLLER(skb->data),
- cdb->buf);
- cdebbuf_free(cdb);
- } else
- printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n",
- CAPIMSG_CONTROLLER(skb->data),
- CAPIMSG_APPID(skb->data),
- capi_cmd2str(cmd, subcmd),
- CAPIMSG_LEN(skb->data));
- }
- }
- return ctr->send_message(ctr, skb);
-}
-
-/**
- * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER
- * @contr: controller number.
- * @buf: result buffer (64 bytes).
- *
- * Retrieve information about the manufacturer of the specified ISDN controller
- * or (for @contr == 0) the driver itself.
- * Return value: CAPI result code
- */
-
-u16 capi20_get_manufacturer(u32 contr, u8 buf[CAPI_MANUFACTURER_LEN])
-{
- struct capi_ctr *ctr;
- u16 ret;
-
- if (contr == 0) {
- strscpy_pad(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
- return CAPI_NOERROR;
- }
-
- mutex_lock(&capi_controller_lock);
-
- ctr = get_capi_ctr_by_nr(contr);
- if (ctr && ctr->state == CAPI_CTR_RUNNING) {
- strscpy_pad(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
- ret = CAPI_NOERROR;
- } else
- ret = CAPI_REGNOTINSTALLED;
-
- mutex_unlock(&capi_controller_lock);
- return ret;
-}
-
-/**
- * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION
- * @contr: controller number.
- * @verp: result structure.
- *
- * Retrieve version information for the specified ISDN controller
- * or (for @contr == 0) the driver itself.
- * Return value: CAPI result code
- */
-
-u16 capi20_get_version(u32 contr, struct capi_version *verp)
-{
- struct capi_ctr *ctr;
- u16 ret;
-
- if (contr == 0) {
- *verp = driver_version;
- return CAPI_NOERROR;
- }
-
- mutex_lock(&capi_controller_lock);
-
- ctr = get_capi_ctr_by_nr(contr);
- if (ctr && ctr->state == CAPI_CTR_RUNNING) {
- memcpy(verp, &ctr->version, sizeof(capi_version));
- ret = CAPI_NOERROR;
- } else
- ret = CAPI_REGNOTINSTALLED;
-
- mutex_unlock(&capi_controller_lock);
- return ret;
-}
-
-/**
- * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER
- * @contr: controller number.
- * @serial: result buffer (8 bytes).
- *
- * Retrieve the serial number of the specified ISDN controller
- * or (for @contr == 0) the driver itself.
- * Return value: CAPI result code
- */
-
-u16 capi20_get_serial(u32 contr, u8 serial[CAPI_SERIAL_LEN])
-{
- struct capi_ctr *ctr;
- u16 ret;
-
- if (contr == 0) {
- strscpy(serial, driver_serial, CAPI_SERIAL_LEN);
- return CAPI_NOERROR;
- }
-
- mutex_lock(&capi_controller_lock);
-
- ctr = get_capi_ctr_by_nr(contr);
- if (ctr && ctr->state == CAPI_CTR_RUNNING) {
- strscpy(serial, ctr->serial, CAPI_SERIAL_LEN);
- ret = CAPI_NOERROR;
- } else
- ret = CAPI_REGNOTINSTALLED;
-
- mutex_unlock(&capi_controller_lock);
- return ret;
-}
-
-/**
- * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE
- * @contr: controller number.
- * @profp: result structure.
- *
- * Retrieve capability information for the specified ISDN controller
- * or (for @contr == 0) the number of installed controllers.
- * Return value: CAPI result code
- */
-
-u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
-{
- struct capi_ctr *ctr;
- u16 ret;
-
- if (contr == 0) {
- profp->ncontroller = ncontrollers;
- return CAPI_NOERROR;
- }
-
- mutex_lock(&capi_controller_lock);
-
- ctr = get_capi_ctr_by_nr(contr);
- if (ctr && ctr->state == CAPI_CTR_RUNNING) {
- memcpy(profp, &ctr->profile, sizeof(struct capi_profile));
- ret = CAPI_NOERROR;
- } else
- ret = CAPI_REGNOTINSTALLED;
-
- mutex_unlock(&capi_controller_lock);
- return ret;
-}
-
-/**
- * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
- * @cmd: command.
- * @data: parameter.
- *
- * Perform manufacturer specific command.
- * Return value: CAPI result code
- */
-
-int capi20_manufacturer(unsigned long cmd, void __user *data)
-{
- struct capi_ctr *ctr;
- int retval;
-
- switch (cmd) {
- case KCAPI_CMD_TRACE:
- {
- kcapi_flagdef fdef;
-
- if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
- return -EFAULT;
-
- mutex_lock(&capi_controller_lock);
-
- ctr = get_capi_ctr_by_nr(fdef.contr);
- if (ctr) {
- ctr->traceflag = fdef.flag;
- printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
- ctr->cnr, ctr->traceflag);
- retval = 0;
- } else
- retval = -ESRCH;
-
- mutex_unlock(&capi_controller_lock);
-
- return retval;
- }
-
- default:
- printk(KERN_ERR "kcapi: manufacturer command %lu unknown.\n",
- cmd);
- break;
-
- }
- return -EINVAL;
-}
-
-/* ------------------------------------------------------------- */
-/* -------- Init & Cleanup ------------------------------------- */
-/* ------------------------------------------------------------- */
-
-/*
- * init / exit functions
- */
-
-int __init kcapi_init(void)
-{
- int err;
-
- kcapi_wq = alloc_workqueue("kcapi", WQ_PERCPU, 0);
- if (!kcapi_wq)
- return -ENOMEM;
-
- err = cdebug_init();
- if (err) {
- destroy_workqueue(kcapi_wq);
- return err;
- }
-
- if (IS_ENABLED(CONFIG_PROC_FS))
- kcapi_proc_init();
-
- return 0;
-}
-
-void kcapi_exit(void)
-{
- if (IS_ENABLED(CONFIG_PROC_FS))
- kcapi_proc_exit();
-
- cdebug_exit();
- destroy_workqueue(kcapi_wq);
-}
+++ /dev/null
-/*
- * Kernel CAPI 2.0 Module
- *
- * Copyright 1999 by Carsten Paeth <calle@calle.de>
- * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/isdn/capilli.h>
-
-#ifdef KCAPI_DEBUG
-#define DBG(format, arg...) do { \
- printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \
- } while (0)
-#else
-#define DBG(format, arg...) /* */
-#endif
-
-enum {
- CAPI_CTR_DETACHED = 0,
- CAPI_CTR_DETECTED = 1,
- CAPI_CTR_LOADING = 2,
- CAPI_CTR_RUNNING = 3,
-};
-
-extern struct capi_ctr *capi_controller[CAPI_MAXCONTR];
-extern struct mutex capi_controller_lock;
-
-extern struct capi20_appl *capi_applications[CAPI_MAXAPPL];
-
-void kcapi_proc_init(void);
-void kcapi_proc_exit(void);
-
-struct capi20_appl {
- u16 applid;
- capi_register_params rparam;
- void (*recv_message)(struct capi20_appl *ap, struct sk_buff *skb);
- void *private;
-
- /* internal to kernelcapi.o */
- unsigned long nrecvctlpkt;
- unsigned long nrecvdatapkt;
- unsigned long nsentctlpkt;
- unsigned long nsentdatapkt;
- struct mutex recv_mtx;
- struct sk_buff_head recv_queue;
- struct work_struct recv_work;
- int release_in_progress;
-};
-
-u16 capi20_isinstalled(void);
-u16 capi20_register(struct capi20_appl *ap);
-u16 capi20_release(struct capi20_appl *ap);
-u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb);
-u16 capi20_get_manufacturer(u32 contr, u8 buf[CAPI_MANUFACTURER_LEN]);
-u16 capi20_get_version(u32 contr, struct capi_version *verp);
-u16 capi20_get_serial(u32 contr, u8 serial[CAPI_SERIAL_LEN]);
-u16 capi20_get_profile(u32 contr, struct capi_profile *profp);
-int capi20_manufacturer(unsigned long cmd, void __user *data);
-
-#define CAPICTR_UP 0
-#define CAPICTR_DOWN 1
-
-int kcapi_init(void);
-void kcapi_exit(void);
-
-/*----- basic-type definitions -----*/
-
-typedef __u8 *_cstruct;
-
-typedef enum {
- CAPI_COMPOSE,
- CAPI_DEFAULT
-} _cmstruct;
-
-/*
- The _cmsg structure contains all possible CAPI 2.0 parameter.
- All parameters are stored here first. The function CAPI_CMSG_2_MESSAGE
- assembles the parameter and builds CAPI2.0 conform messages.
- CAPI_MESSAGE_2_CMSG disassembles CAPI 2.0 messages and stores the
- parameter in the _cmsg structure
- */
-
-typedef struct {
- /* Header */
- __u16 ApplId;
- __u8 Command;
- __u8 Subcommand;
- __u16 Messagenumber;
-
- /* Parameter */
- union {
- __u32 adrController;
- __u32 adrPLCI;
- __u32 adrNCCI;
- } adr;
-
- _cmstruct AdditionalInfo;
- _cstruct B1configuration;
- __u16 B1protocol;
- _cstruct B2configuration;
- __u16 B2protocol;
- _cstruct B3configuration;
- __u16 B3protocol;
- _cstruct BC;
- _cstruct BChannelinformation;
- _cmstruct BProtocol;
- _cstruct CalledPartyNumber;
- _cstruct CalledPartySubaddress;
- _cstruct CallingPartyNumber;
- _cstruct CallingPartySubaddress;
- __u32 CIPmask;
- __u32 CIPmask2;
- __u16 CIPValue;
- __u32 Class;
- _cstruct ConnectedNumber;
- _cstruct ConnectedSubaddress;
- __u32 Data;
- __u16 DataHandle;
- __u16 DataLength;
- _cstruct FacilityConfirmationParameter;
- _cstruct Facilitydataarray;
- _cstruct FacilityIndicationParameter;
- _cstruct FacilityRequestParameter;
- __u16 FacilitySelector;
- __u16 Flags;
- __u32 Function;
- _cstruct HLC;
- __u16 Info;
- _cstruct InfoElement;
- __u32 InfoMask;
- __u16 InfoNumber;
- _cstruct Keypadfacility;
- _cstruct LLC;
- _cstruct ManuData;
- __u32 ManuID;
- _cstruct NCPI;
- __u16 Reason;
- __u16 Reason_B3;
- __u16 Reject;
- _cstruct Useruserdata;
-
- /* intern */
- unsigned l, p;
- unsigned char *par;
- __u8 *m;
-
- /* buffer to construct message */
- __u8 buf[180];
-
-} _cmsg;
-
-/*-----------------------------------------------------------------------*/
-
-/*
- * Debugging / Tracing functions
- */
-
-char *capi_cmd2str(__u8 cmd, __u8 subcmd);
-
-typedef struct {
- u_char *buf;
- u_char *p;
- size_t size;
- size_t pos;
-} _cdebbuf;
-
-#define CDEBUG_SIZE 1024
-#define CDEBUG_GSIZE 4096
-
-void cdebbuf_free(_cdebbuf *cdb);
-int cdebug_init(void);
-void cdebug_exit(void);
-
-_cdebbuf *capi_message2str(__u8 *msg);
+++ /dev/null
-/*
- * Kernel CAPI 2.0 Module - /proc/capi handling
- *
- * Copyright 1999 by Carsten Paeth <calle@calle.de>
- * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#include "kcapi.h"
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/init.h>
-#include <linux/export.h>
-
-static char *state2str(unsigned short state)
-{
- switch (state) {
- case CAPI_CTR_DETECTED: return "detected";
- case CAPI_CTR_LOADING: return "loading";
- case CAPI_CTR_RUNNING: return "running";
- default: return "???";
- }
-}
-
-// /proc/capi
-// ===========================================================================
-
-// /proc/capi/controller:
-// cnr driver cardstate name driverinfo
-// /proc/capi/contrstats:
-// cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
-// ---------------------------------------------------------------------------
-
-static void *controller_start(struct seq_file *seq, loff_t *pos)
- __acquires(capi_controller_lock)
-{
- mutex_lock(&capi_controller_lock);
-
- if (*pos < CAPI_MAXCONTR)
- return &capi_controller[*pos];
-
- return NULL;
-}
-
-static void *controller_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
- if (*pos < CAPI_MAXCONTR)
- return &capi_controller[*pos];
-
- return NULL;
-}
-
-static void controller_stop(struct seq_file *seq, void *v)
- __releases(capi_controller_lock)
-{
- mutex_unlock(&capi_controller_lock);
-}
-
-static int controller_show(struct seq_file *seq, void *v)
-{
- struct capi_ctr *ctr = *(struct capi_ctr **) v;
-
- if (!ctr)
- return 0;
-
- seq_printf(seq, "%d %-10s %-8s %-16s %s\n",
- ctr->cnr, ctr->driver_name,
- state2str(ctr->state),
- ctr->name,
- ctr->procinfo ? ctr->procinfo(ctr) : "");
-
- return 0;
-}
-
-static int contrstats_show(struct seq_file *seq, void *v)
-{
- struct capi_ctr *ctr = *(struct capi_ctr **) v;
-
- if (!ctr)
- return 0;
-
- seq_printf(seq, "%d %lu %lu %lu %lu\n",
- ctr->cnr,
- ctr->nrecvctlpkt,
- ctr->nrecvdatapkt,
- ctr->nsentctlpkt,
- ctr->nsentdatapkt);
-
- return 0;
-}
-
-static const struct seq_operations seq_controller_ops = {
- .start = controller_start,
- .next = controller_next,
- .stop = controller_stop,
- .show = controller_show,
-};
-
-static const struct seq_operations seq_contrstats_ops = {
- .start = controller_start,
- .next = controller_next,
- .stop = controller_stop,
- .show = contrstats_show,
-};
-
-// /proc/capi/applications:
-// applid l3cnt dblkcnt dblklen #ncci recvqueuelen
-// /proc/capi/applstats:
-// applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
-// ---------------------------------------------------------------------------
-
-static void *applications_start(struct seq_file *seq, loff_t *pos)
- __acquires(capi_controller_lock)
-{
- mutex_lock(&capi_controller_lock);
-
- if (*pos < CAPI_MAXAPPL)
- return &capi_applications[*pos];
-
- return NULL;
-}
-
-static void *
-applications_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
- if (*pos < CAPI_MAXAPPL)
- return &capi_applications[*pos];
-
- return NULL;
-}
-
-static void applications_stop(struct seq_file *seq, void *v)
- __releases(capi_controller_lock)
-{
- mutex_unlock(&capi_controller_lock);
-}
-
-static int
-applications_show(struct seq_file *seq, void *v)
-{
- struct capi20_appl *ap = *(struct capi20_appl **) v;
-
- if (!ap)
- return 0;
-
- seq_printf(seq, "%u %d %d %d\n",
- ap->applid,
- ap->rparam.level3cnt,
- ap->rparam.datablkcnt,
- ap->rparam.datablklen);
-
- return 0;
-}
-
-static int
-applstats_show(struct seq_file *seq, void *v)
-{
- struct capi20_appl *ap = *(struct capi20_appl **) v;
-
- if (!ap)
- return 0;
-
- seq_printf(seq, "%u %lu %lu %lu %lu\n",
- ap->applid,
- ap->nrecvctlpkt,
- ap->nrecvdatapkt,
- ap->nsentctlpkt,
- ap->nsentdatapkt);
-
- return 0;
-}
-
-static const struct seq_operations seq_applications_ops = {
- .start = applications_start,
- .next = applications_next,
- .stop = applications_stop,
- .show = applications_show,
-};
-
-static const struct seq_operations seq_applstats_ops = {
- .start = applications_start,
- .next = applications_next,
- .stop = applications_stop,
- .show = applstats_show,
-};
-
-// ---------------------------------------------------------------------------
-
-/* /proc/capi/drivers is always empty */
-static ssize_t empty_read(struct file *file, char __user *buf,
- size_t size, loff_t *off)
-{
- return 0;
-}
-
-static const struct proc_ops empty_proc_ops = {
- .proc_read = empty_read,
- .proc_lseek = default_llseek,
-};
-
-// ---------------------------------------------------------------------------
-
-void __init
-kcapi_proc_init(void)
-{
- proc_mkdir("capi", NULL);
- proc_mkdir("capi/controllers", NULL);
- proc_create_seq("capi/controller", 0, NULL, &seq_controller_ops);
- proc_create_seq("capi/contrstats", 0, NULL, &seq_contrstats_ops);
- proc_create_seq("capi/applications", 0, NULL, &seq_applications_ops);
- proc_create_seq("capi/applstats", 0, NULL, &seq_applstats_ops);
- proc_create("capi/driver", 0, NULL, &empty_proc_ops);
-}
-
-void
-kcapi_proc_exit(void)
-{
- remove_proc_entry("capi/driver", NULL);
- remove_proc_entry("capi/controller", NULL);
- remove_proc_entry("capi/contrstats", NULL);
- remove_proc_entry("capi/applications", NULL);
- remove_proc_entry("capi/applstats", NULL);
- remove_proc_entry("capi/controllers", NULL);
- remove_proc_entry("capi", NULL);
-}
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0-only
-# Makefile for the CAPI hardware drivers
-
-# Object files in subdirectories
-
-obj-$(CONFIG_MISDN) += mISDN/
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Hardware for mISDN
-#
-comment "mISDN hardware drivers"
-
-config MISDN_HFCPCI
- tristate "Support for HFC PCI cards"
- depends on MISDN
- depends on PCI
- help
- Enable support for cards with Cologne Chip AG's
- HFC PCI chip.
-
-config MISDN_HFCMULTI
- tristate "Support for HFC multiport cards (HFC-4S/8S/E1)"
- depends on (PCI || CPM1) && HAS_IOPORT
- depends on MISDN
- help
- Enable support for cards with Cologne Chip AG's HFC multiport
- chip. There are three types of chips that are quite similar,
- but the interface is different:
- * HFC-4S (4 S/T interfaces on one chip)
- * HFC-8S (8 S/T interfaces on one chip)
- * HFC-E1 (E1 interface for 2Mbit ISDN)
-
-config MISDN_HFCMULTI_8xx
- bool "Support for XHFC embedded board in HFC multiport driver"
- depends on MISDN
- depends on MISDN_HFCMULTI
- depends on CPM1
- default CPM1
- help
- Enable support for the XHFC embedded solution from Speech Design.
-
-config MISDN_HFCUSB
- tristate "Support for HFC-S USB based TAs"
- depends on USB
- help
- Enable support for USB ISDN TAs with Cologne Chip AG's
- HFC-S USB ISDN Controller
-
-config MISDN_AVMFRITZ
- tristate "Support for AVM FRITZ!CARD PCI"
- depends on MISDN
- depends on PCI && HAS_IOPORT
- select MISDN_IPAC
- help
- Enable support for AVMs FRITZ!CARD PCI cards
-
-config MISDN_SPEEDFAX
- tristate "Support for Sedlbauer Speedfax+"
- depends on MISDN
- depends on PCI && HAS_IOPORT
- select MISDN_IPAC
- select MISDN_ISAR
- help
- Enable support for Sedlbauer Speedfax+.
-
-config MISDN_INFINEON
- tristate "Support for cards with Infineon chipset"
- depends on MISDN
- depends on PCI && HAS_IOPORT
- select MISDN_IPAC
- help
- Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX
- chip from Infineon (former manufacturer Siemens).
-
-config MISDN_W6692
- tristate "Support for cards with Winbond 6692"
- depends on MISDN
- depends on PCI && HAS_IOPORT
- help
- Enable support for Winbond 6692 PCI chip based cards.
-
-config MISDN_NETJET
- tristate "Support for NETJet cards"
- depends on MISDN
- depends on PCI && HAS_IOPORT
- depends on TTY
- select MISDN_IPAC
- select MISDN_HDLC
- help
- Enable support for Traverse Technologies NETJet PCI cards.
-
-config MISDN_HDLC
- tristate
- select CRC_CCITT
- select BITREVERSE
-
-config MISDN_IPAC
- tristate
- depends on MISDN
-
-config MISDN_ISAR
- tristate
- depends on MISDN
-
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for the modular ISDN hardware drivers
-#
-#
-
-obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o
-obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o
-obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o
-obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o
-obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o
-obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o
-obj-$(CONFIG_MISDN_W6692) += w6692.o
-obj-$(CONFIG_MISDN_NETJET) += netjet.o
-# chip modules
-obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o
-obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o
-
-obj-$(CONFIG_MISDN_HDLC) += isdnhdlc.o
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * avm_fritz.c low level stuff for AVM FRITZ!CARD PCI ISDN cards
- * Thanks to AVM, Berlin for informations
- *
- * Author Karsten Keil <keil@isdn4linux.de>
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/mISDNhw.h>
-#include <linux/slab.h>
-#include <linux/unaligned.h>
-#include "ipac.h"
-
-
-#define AVMFRITZ_REV "2.3"
-
-static int AVM_cnt;
-static int debug;
-
-enum {
- AVM_FRITZ_PCI,
- AVM_FRITZ_PCIV2,
-};
-
-#define HDLC_FIFO 0x0
-#define HDLC_STATUS 0x4
-#define CHIP_WINDOW 0x10
-
-#define CHIP_INDEX 0x4
-#define AVM_HDLC_1 0x00
-#define AVM_HDLC_2 0x01
-#define AVM_ISAC_FIFO 0x02
-#define AVM_ISAC_REG_LOW 0x04
-#define AVM_ISAC_REG_HIGH 0x06
-
-#define AVM_STATUS0_IRQ_ISAC 0x01
-#define AVM_STATUS0_IRQ_HDLC 0x02
-#define AVM_STATUS0_IRQ_TIMER 0x04
-#define AVM_STATUS0_IRQ_MASK 0x07
-
-#define AVM_STATUS0_RESET 0x01
-#define AVM_STATUS0_DIS_TIMER 0x02
-#define AVM_STATUS0_RES_TIMER 0x04
-#define AVM_STATUS0_ENA_IRQ 0x08
-#define AVM_STATUS0_TESTBIT 0x10
-
-#define AVM_STATUS1_INT_SEL 0x0f
-#define AVM_STATUS1_ENA_IOM 0x80
-
-#define HDLC_MODE_ITF_FLG 0x01
-#define HDLC_MODE_TRANS 0x02
-#define HDLC_MODE_CCR_7 0x04
-#define HDLC_MODE_CCR_16 0x08
-#define HDLC_FIFO_SIZE_128 0x20
-#define HDLC_MODE_TESTLOOP 0x80
-
-#define HDLC_INT_XPR 0x80
-#define HDLC_INT_XDU 0x40
-#define HDLC_INT_RPR 0x20
-#define HDLC_INT_MASK 0xE0
-
-#define HDLC_STAT_RME 0x01
-#define HDLC_STAT_RDO 0x10
-#define HDLC_STAT_CRCVFRRAB 0x0E
-#define HDLC_STAT_CRCVFR 0x06
-#define HDLC_STAT_RML_MASK_V1 0x3f00
-#define HDLC_STAT_RML_MASK_V2 0x7f00
-
-#define HDLC_CMD_XRS 0x80
-#define HDLC_CMD_XME 0x01
-#define HDLC_CMD_RRS 0x20
-#define HDLC_CMD_XML_MASK 0x3f00
-
-#define HDLC_FIFO_SIZE_V1 32
-#define HDLC_FIFO_SIZE_V2 128
-
-/* Fritz PCI v2.0 */
-
-#define AVM_HDLC_FIFO_1 0x10
-#define AVM_HDLC_FIFO_2 0x18
-
-#define AVM_HDLC_STATUS_1 0x14
-#define AVM_HDLC_STATUS_2 0x1c
-
-#define AVM_ISACX_INDEX 0x04
-#define AVM_ISACX_DATA 0x08
-
-/* data struct */
-#define LOG_SIZE 63
-
-struct hdlc_stat_reg {
-#ifdef __BIG_ENDIAN
- u8 fill;
- u8 mode;
- u8 xml;
- u8 cmd;
-#else
- u8 cmd;
- u8 xml;
- u8 mode;
- u8 fill;
-#endif
-} __attribute__((packed));
-
-struct hdlc_hw {
- union {
- u32 ctrl;
- struct hdlc_stat_reg sr;
- } ctrl;
- u32 stat;
-};
-
-struct fritzcard {
- struct list_head list;
- struct pci_dev *pdev;
- char name[MISDN_MAX_IDLEN];
- u8 type;
- u8 ctrlreg;
- u16 irq;
- u32 irqcnt;
- u32 addr;
- spinlock_t lock; /* hw lock */
- struct isac_hw isac;
- struct hdlc_hw hdlc[2];
- struct bchannel bch[2];
- char log[LOG_SIZE + 1];
-};
-
-static LIST_HEAD(Cards);
-static DEFINE_RWLOCK(card_lock); /* protect Cards */
-
-static void
-_set_debug(struct fritzcard *card)
-{
- card->isac.dch.debug = debug;
- card->bch[0].debug = debug;
- card->bch[1].debug = debug;
-}
-
-static int
-set_debug(const char *val, const struct kernel_param *kp)
-{
- int ret;
- struct fritzcard *card;
-
- ret = param_set_uint(val, kp);
- if (!ret) {
- read_lock(&card_lock);
- list_for_each_entry(card, &Cards, list)
- _set_debug(card);
- read_unlock(&card_lock);
- }
- return ret;
-}
-
-MODULE_AUTHOR("Karsten Keil");
-MODULE_DESCRIPTION("mISDN driver for AVM FRITZ!CARD PCI ISDN cards");
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION(AVMFRITZ_REV);
-module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "avmfritz debug mask");
-
-/* Interface functions */
-
-static u8
-ReadISAC_V1(void *p, u8 offset)
-{
- struct fritzcard *fc = p;
- u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
-
- outb(idx, fc->addr + CHIP_INDEX);
- return inb(fc->addr + CHIP_WINDOW + (offset & 0xf));
-}
-
-static void
-WriteISAC_V1(void *p, u8 offset, u8 value)
-{
- struct fritzcard *fc = p;
- u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
-
- outb(idx, fc->addr + CHIP_INDEX);
- outb(value, fc->addr + CHIP_WINDOW + (offset & 0xf));
-}
-
-static void
-ReadFiFoISAC_V1(void *p, u8 off, u8 *data, int size)
-{
- struct fritzcard *fc = p;
-
- outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX);
- insb(fc->addr + CHIP_WINDOW, data, size);
-}
-
-static void
-WriteFiFoISAC_V1(void *p, u8 off, u8 *data, int size)
-{
- struct fritzcard *fc = p;
-
- outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX);
- outsb(fc->addr + CHIP_WINDOW, data, size);
-}
-
-static u8
-ReadISAC_V2(void *p, u8 offset)
-{
- struct fritzcard *fc = p;
-
- outl(offset, fc->addr + AVM_ISACX_INDEX);
- return 0xff & inl(fc->addr + AVM_ISACX_DATA);
-}
-
-static void
-WriteISAC_V2(void *p, u8 offset, u8 value)
-{
- struct fritzcard *fc = p;
-
- outl(offset, fc->addr + AVM_ISACX_INDEX);
- outl(value, fc->addr + AVM_ISACX_DATA);
-}
-
-static void
-ReadFiFoISAC_V2(void *p, u8 off, u8 *data, int size)
-{
- struct fritzcard *fc = p;
- int i;
-
- outl(off, fc->addr + AVM_ISACX_INDEX);
- for (i = 0; i < size; i++)
- data[i] = 0xff & inl(fc->addr + AVM_ISACX_DATA);
-}
-
-static void
-WriteFiFoISAC_V2(void *p, u8 off, u8 *data, int size)
-{
- struct fritzcard *fc = p;
- int i;
-
- outl(off, fc->addr + AVM_ISACX_INDEX);
- for (i = 0; i < size; i++)
- outl(data[i], fc->addr + AVM_ISACX_DATA);
-}
-
-static struct bchannel *
-Sel_BCS(struct fritzcard *fc, u32 channel)
-{
- if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) &&
- (fc->bch[0].nr & channel))
- return &fc->bch[0];
- else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) &&
- (fc->bch[1].nr & channel))
- return &fc->bch[1];
- else
- return NULL;
-}
-
-static inline void
-__write_ctrl_pci(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) {
- u32 idx = channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1;
-
- outl(idx, fc->addr + CHIP_INDEX);
- outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS);
-}
-
-static inline void
-__write_ctrl_pciv2(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) {
- outl(hdlc->ctrl.ctrl, fc->addr + (channel == 2 ? AVM_HDLC_STATUS_2 :
- AVM_HDLC_STATUS_1));
-}
-
-static void
-write_ctrl(struct bchannel *bch, int which) {
- struct fritzcard *fc = bch->hw;
- struct hdlc_hw *hdlc;
-
- hdlc = &fc->hdlc[(bch->nr - 1) & 1];
- pr_debug("%s: hdlc %c wr%x ctrl %x\n", fc->name, '@' + bch->nr,
- which, hdlc->ctrl.ctrl);
- switch (fc->type) {
- case AVM_FRITZ_PCIV2:
- __write_ctrl_pciv2(fc, hdlc, bch->nr);
- break;
- case AVM_FRITZ_PCI:
- __write_ctrl_pci(fc, hdlc, bch->nr);
- break;
- }
-}
-
-
-static inline u32
-__read_status_pci(u_long addr, u32 channel)
-{
- outl(channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX);
- return inl(addr + CHIP_WINDOW + HDLC_STATUS);
-}
-
-static inline u32
-__read_status_pciv2(u_long addr, u32 channel)
-{
- return inl(addr + (channel == 2 ? AVM_HDLC_STATUS_2 :
- AVM_HDLC_STATUS_1));
-}
-
-
-static u32
-read_status(struct fritzcard *fc, u32 channel)
-{
- switch (fc->type) {
- case AVM_FRITZ_PCIV2:
- return __read_status_pciv2(fc->addr, channel);
- case AVM_FRITZ_PCI:
- return __read_status_pci(fc->addr, channel);
- }
- /* dummy */
- return 0;
-}
-
-static void
-enable_hwirq(struct fritzcard *fc)
-{
- fc->ctrlreg |= AVM_STATUS0_ENA_IRQ;
- outb(fc->ctrlreg, fc->addr + 2);
-}
-
-static void
-disable_hwirq(struct fritzcard *fc)
-{
- fc->ctrlreg &= ~AVM_STATUS0_ENA_IRQ;
- outb(fc->ctrlreg, fc->addr + 2);
-}
-
-static int
-modehdlc(struct bchannel *bch, int protocol)
-{
- struct fritzcard *fc = bch->hw;
- struct hdlc_hw *hdlc;
- u8 mode;
-
- hdlc = &fc->hdlc[(bch->nr - 1) & 1];
- pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name,
- '@' + bch->nr, bch->state, protocol, bch->nr);
- hdlc->ctrl.ctrl = 0;
- mode = (fc->type == AVM_FRITZ_PCIV2) ? HDLC_FIFO_SIZE_128 : 0;
-
- switch (protocol) {
- case -1: /* used for init */
- bch->state = -1;
- fallthrough;
- case ISDN_P_NONE:
- if (bch->state == ISDN_P_NONE)
- break;
- hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
- hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS;
- write_ctrl(bch, 5);
- bch->state = ISDN_P_NONE;
- test_and_clear_bit(FLG_HDLC, &bch->Flags);
- test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
- break;
- case ISDN_P_B_RAW:
- bch->state = protocol;
- hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
- hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS;
- write_ctrl(bch, 5);
- hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
- write_ctrl(bch, 1);
- hdlc->ctrl.sr.cmd = 0;
- test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
- break;
- case ISDN_P_B_HDLC:
- bch->state = protocol;
- hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
- hdlc->ctrl.sr.mode = mode | HDLC_MODE_ITF_FLG;
- write_ctrl(bch, 5);
- hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
- write_ctrl(bch, 1);
- hdlc->ctrl.sr.cmd = 0;
- test_and_set_bit(FLG_HDLC, &bch->Flags);
- break;
- default:
- pr_info("%s: protocol not known %x\n", fc->name, protocol);
- return -ENOPROTOOPT;
- }
- return 0;
-}
-
-static void
-hdlc_empty_fifo(struct bchannel *bch, int count)
-{
- u32 *ptr;
- u8 *p;
- u32 val, addr;
- int cnt;
- struct fritzcard *fc = bch->hw;
-
- pr_debug("%s: %s %d\n", fc->name, __func__, count);
- if (test_bit(FLG_RX_OFF, &bch->Flags)) {
- p = NULL;
- bch->dropcnt += count;
- } else {
- cnt = bchannel_get_rxbuf(bch, count);
- if (cnt < 0) {
- pr_warn("%s.B%d: No bufferspace for %d bytes\n",
- fc->name, bch->nr, count);
- return;
- }
- p = skb_put(bch->rx_skb, count);
- }
- ptr = (u32 *)p;
- if (fc->type == AVM_FRITZ_PCIV2)
- addr = fc->addr + (bch->nr == 2 ?
- AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
- else {
- addr = fc->addr + CHIP_WINDOW;
- outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr);
- }
- cnt = 0;
- while (cnt < count) {
- val = le32_to_cpu(inl(addr));
- if (p) {
- put_unaligned(val, ptr);
- ptr++;
- }
- cnt += 4;
- }
- if (p && (debug & DEBUG_HW_BFIFO)) {
- snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ",
- bch->nr, fc->name, count);
- print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
- }
-}
-
-static void
-hdlc_fill_fifo(struct bchannel *bch)
-{
- struct fritzcard *fc = bch->hw;
- struct hdlc_hw *hdlc;
- int count, fs, cnt = 0, idx;
- bool fillempty = false;
- u8 *p;
- u32 *ptr, val, addr;
-
- idx = (bch->nr - 1) & 1;
- hdlc = &fc->hdlc[idx];
- fs = (fc->type == AVM_FRITZ_PCIV2) ?
- HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1;
- if (!bch->tx_skb) {
- if (!test_bit(FLG_TX_EMPTY, &bch->Flags))
- return;
- count = fs;
- p = bch->fill;
- fillempty = true;
- } else {
- count = bch->tx_skb->len - bch->tx_idx;
- if (count <= 0)
- return;
- p = bch->tx_skb->data + bch->tx_idx;
- }
- hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
- if (count > fs) {
- count = fs;
- } else {
- if (test_bit(FLG_HDLC, &bch->Flags))
- hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
- }
- ptr = (u32 *)p;
- if (!fillempty) {
- pr_debug("%s.B%d: %d/%d/%d", fc->name, bch->nr, count,
- bch->tx_idx, bch->tx_skb->len);
- bch->tx_idx += count;
- } else {
- pr_debug("%s.B%d: fillempty %d\n", fc->name, bch->nr, count);
- }
- hdlc->ctrl.sr.xml = ((count == fs) ? 0 : count);
- if (fc->type == AVM_FRITZ_PCIV2) {
- __write_ctrl_pciv2(fc, hdlc, bch->nr);
- addr = fc->addr + (bch->nr == 2 ?
- AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
- } else {
- __write_ctrl_pci(fc, hdlc, bch->nr);
- addr = fc->addr + CHIP_WINDOW;
- }
- if (fillempty) {
- while (cnt < count) {
- /* all bytes the same - no worry about endian */
- outl(*ptr, addr);
- cnt += 4;
- }
- } else {
- while (cnt < count) {
- val = get_unaligned(ptr);
- outl(cpu_to_le32(val), addr);
- ptr++;
- cnt += 4;
- }
- }
- if ((debug & DEBUG_HW_BFIFO) && !fillempty) {
- snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ",
- bch->nr, fc->name, count);
- print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
- }
-}
-
-static void
-HDLC_irq_xpr(struct bchannel *bch)
-{
- if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) {
- hdlc_fill_fifo(bch);
- } else {
- dev_kfree_skb(bch->tx_skb);
- if (get_next_bframe(bch)) {
- hdlc_fill_fifo(bch);
- test_and_clear_bit(FLG_TX_EMPTY, &bch->Flags);
- } else if (test_bit(FLG_TX_EMPTY, &bch->Flags)) {
- hdlc_fill_fifo(bch);
- }
- }
-}
-
-static void
-HDLC_irq(struct bchannel *bch, u32 stat)
-{
- struct fritzcard *fc = bch->hw;
- int len, fs;
- u32 rmlMask;
- struct hdlc_hw *hdlc;
-
- hdlc = &fc->hdlc[(bch->nr - 1) & 1];
- pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat);
- if (fc->type == AVM_FRITZ_PCIV2) {
- rmlMask = HDLC_STAT_RML_MASK_V2;
- fs = HDLC_FIFO_SIZE_V2;
- } else {
- rmlMask = HDLC_STAT_RML_MASK_V1;
- fs = HDLC_FIFO_SIZE_V1;
- }
- if (stat & HDLC_INT_RPR) {
- if (stat & HDLC_STAT_RDO) {
- pr_warn("%s: ch%d stat %x RDO\n",
- fc->name, bch->nr, stat);
- hdlc->ctrl.sr.xml = 0;
- hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS;
- write_ctrl(bch, 1);
- hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS;
- write_ctrl(bch, 1);
- if (bch->rx_skb)
- skb_trim(bch->rx_skb, 0);
- } else {
- len = (stat & rmlMask) >> 8;
- if (!len)
- len = fs;
- hdlc_empty_fifo(bch, len);
- if (!bch->rx_skb)
- goto handle_tx;
- if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
- recv_Bchannel(bch, 0, false);
- } else if (stat & HDLC_STAT_RME) {
- if ((stat & HDLC_STAT_CRCVFRRAB) ==
- HDLC_STAT_CRCVFR) {
- recv_Bchannel(bch, 0, false);
- } else {
- pr_warn("%s: got invalid frame\n",
- fc->name);
- skb_trim(bch->rx_skb, 0);
- }
- }
- }
- }
-handle_tx:
- if (stat & HDLC_INT_XDU) {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame on HDLC
- * in transparent mode we send the next data
- */
- pr_warn("%s: ch%d stat %x XDU %s\n", fc->name, bch->nr,
- stat, bch->tx_skb ? "tx_skb" : "no tx_skb");
- if (bch->tx_skb && bch->tx_skb->len) {
- if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
- bch->tx_idx = 0;
- } else if (test_bit(FLG_FILLEMPTY, &bch->Flags)) {
- test_and_set_bit(FLG_TX_EMPTY, &bch->Flags);
- }
- hdlc->ctrl.sr.xml = 0;
- hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS;
- write_ctrl(bch, 1);
- hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS;
- HDLC_irq_xpr(bch);
- return;
- } else if (stat & HDLC_INT_XPR)
- HDLC_irq_xpr(bch);
-}
-
-static inline void
-HDLC_irq_main(struct fritzcard *fc)
-{
- u32 stat;
- struct bchannel *bch;
-
- stat = read_status(fc, 1);
- if (stat & HDLC_INT_MASK) {
- bch = Sel_BCS(fc, 1);
- if (bch)
- HDLC_irq(bch, stat);
- else
- pr_debug("%s: spurious ch1 IRQ\n", fc->name);
- }
- stat = read_status(fc, 2);
- if (stat & HDLC_INT_MASK) {
- bch = Sel_BCS(fc, 2);
- if (bch)
- HDLC_irq(bch, stat);
- else
- pr_debug("%s: spurious ch2 IRQ\n", fc->name);
- }
-}
-
-static irqreturn_t
-avm_fritz_interrupt(int intno, void *dev_id)
-{
- struct fritzcard *fc = dev_id;
- u8 val;
- u8 sval;
-
- spin_lock(&fc->lock);
- sval = inb(fc->addr + 2);
- pr_debug("%s: irq stat0 %x\n", fc->name, sval);
- if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
- /* shared IRQ from other HW */
- spin_unlock(&fc->lock);
- return IRQ_NONE;
- }
- fc->irqcnt++;
-
- if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
- val = ReadISAC_V1(fc, ISAC_ISTA);
- mISDNisac_irq(&fc->isac, val);
- }
- if (!(sval & AVM_STATUS0_IRQ_HDLC))
- HDLC_irq_main(fc);
- spin_unlock(&fc->lock);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-avm_fritzv2_interrupt(int intno, void *dev_id)
-{
- struct fritzcard *fc = dev_id;
- u8 val;
- u8 sval;
-
- spin_lock(&fc->lock);
- sval = inb(fc->addr + 2);
- pr_debug("%s: irq stat0 %x\n", fc->name, sval);
- if (!(sval & AVM_STATUS0_IRQ_MASK)) {
- /* shared IRQ from other HW */
- spin_unlock(&fc->lock);
- return IRQ_NONE;
- }
- fc->irqcnt++;
-
- if (sval & AVM_STATUS0_IRQ_HDLC)
- HDLC_irq_main(fc);
- if (sval & AVM_STATUS0_IRQ_ISAC) {
- val = ReadISAC_V2(fc, ISACX_ISTA);
- mISDNisac_irq(&fc->isac, val);
- }
- if (sval & AVM_STATUS0_IRQ_TIMER) {
- pr_debug("%s: timer irq\n", fc->name);
- outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2);
- udelay(1);
- outb(fc->ctrlreg, fc->addr + 2);
- }
- spin_unlock(&fc->lock);
- return IRQ_HANDLED;
-}
-
-static int
-avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct fritzcard *fc = bch->hw;
- int ret = -EINVAL;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- unsigned long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- spin_lock_irqsave(&fc->lock, flags);
- ret = bchannel_senddata(bch, skb);
- if (ret > 0) { /* direct TX */
- hdlc_fill_fifo(bch);
- ret = 0;
- }
- spin_unlock_irqrestore(&fc->lock, flags);
- return ret;
- case PH_ACTIVATE_REQ:
- spin_lock_irqsave(&fc->lock, flags);
- if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
- ret = modehdlc(bch, ch->protocol);
- else
- ret = 0;
- spin_unlock_irqrestore(&fc->lock, flags);
- if (!ret)
- _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- break;
- case PH_DEACTIVATE_REQ:
- spin_lock_irqsave(&fc->lock, flags);
- mISDN_clear_bchannel(bch);
- modehdlc(bch, ISDN_P_NONE);
- spin_unlock_irqrestore(&fc->lock, flags);
- _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- ret = 0;
- break;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static void
-inithdlc(struct fritzcard *fc)
-{
- modehdlc(&fc->bch[0], -1);
- modehdlc(&fc->bch[1], -1);
-}
-
-static void
-clear_pending_hdlc_ints(struct fritzcard *fc)
-{
- u32 val;
-
- val = read_status(fc, 1);
- pr_debug("%s: HDLC 1 STA %x\n", fc->name, val);
- val = read_status(fc, 2);
- pr_debug("%s: HDLC 2 STA %x\n", fc->name, val);
-}
-
-static void
-reset_avm(struct fritzcard *fc)
-{
- switch (fc->type) {
- case AVM_FRITZ_PCI:
- fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER;
- break;
- case AVM_FRITZ_PCIV2:
- fc->ctrlreg = AVM_STATUS0_RESET;
- break;
- }
- if (debug & DEBUG_HW)
- pr_notice("%s: reset\n", fc->name);
- disable_hwirq(fc);
- mdelay(5);
- switch (fc->type) {
- case AVM_FRITZ_PCI:
- fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER;
- disable_hwirq(fc);
- outb(AVM_STATUS1_ENA_IOM, fc->addr + 3);
- break;
- case AVM_FRITZ_PCIV2:
- fc->ctrlreg = 0;
- disable_hwirq(fc);
- break;
- }
- mdelay(1);
- if (debug & DEBUG_HW)
- pr_notice("%s: S0/S1 %x/%x\n", fc->name,
- inb(fc->addr + 2), inb(fc->addr + 3));
-}
-
-static int
-init_card(struct fritzcard *fc)
-{
- int ret, cnt = 3;
- u_long flags;
-
- reset_avm(fc); /* disable IRQ */
- if (fc->type == AVM_FRITZ_PCIV2)
- ret = request_irq(fc->irq, avm_fritzv2_interrupt,
- IRQF_SHARED, fc->name, fc);
- else
- ret = request_irq(fc->irq, avm_fritz_interrupt,
- IRQF_SHARED, fc->name, fc);
- if (ret) {
- pr_info("%s: couldn't get interrupt %d\n",
- fc->name, fc->irq);
- return ret;
- }
- while (cnt--) {
- spin_lock_irqsave(&fc->lock, flags);
- ret = fc->isac.init(&fc->isac);
- if (ret) {
- spin_unlock_irqrestore(&fc->lock, flags);
- pr_info("%s: ISAC init failed with %d\n",
- fc->name, ret);
- break;
- }
- clear_pending_hdlc_ints(fc);
- inithdlc(fc);
- enable_hwirq(fc);
- /* RESET Receiver and Transmitter */
- if (fc->type == AVM_FRITZ_PCIV2) {
- WriteISAC_V2(fc, ISACX_MASK, 0);
- WriteISAC_V2(fc, ISACX_CMDRD, 0x41);
- } else {
- WriteISAC_V1(fc, ISAC_MASK, 0);
- WriteISAC_V1(fc, ISAC_CMDR, 0x41);
- }
- spin_unlock_irqrestore(&fc->lock, flags);
- /* Timeout 10ms */
- msleep_interruptible(10);
- if (debug & DEBUG_HW)
- pr_notice("%s: IRQ %d count %d\n", fc->name,
- fc->irq, fc->irqcnt);
- if (!fc->irqcnt) {
- pr_info("%s: IRQ(%d) getting no IRQs during init %d\n",
- fc->name, fc->irq, 3 - cnt);
- reset_avm(fc);
- } else
- return 0;
- }
- free_irq(fc->irq, fc);
- return -EIO;
-}
-
-static int
-channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
-{
- return mISDN_ctrl_bchannel(bch, cq);
-}
-
-static int
-avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct fritzcard *fc = bch->hw;
- int ret = -EINVAL;
- u_long flags;
-
- pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg);
- switch (cmd) {
- case CLOSE_CHANNEL:
- test_and_clear_bit(FLG_OPEN, &bch->Flags);
- cancel_work_sync(&bch->workq);
- spin_lock_irqsave(&fc->lock, flags);
- mISDN_clear_bchannel(bch);
- modehdlc(bch, ISDN_P_NONE);
- spin_unlock_irqrestore(&fc->lock, flags);
- ch->protocol = ISDN_P_NONE;
- ch->peer = NULL;
- module_put(THIS_MODULE);
- ret = 0;
- break;
- case CONTROL_CHANNEL:
- ret = channel_bctrl(bch, arg);
- break;
- default:
- pr_info("%s: %s unknown prim(%x)\n", fc->name, __func__, cmd);
- }
- return ret;
-}
-
-static int
-channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq)
-{
- int ret = 0;
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3;
- break;
- case MISDN_CTRL_LOOP:
- /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
- if (cq->channel < 0 || cq->channel > 3) {
- ret = -EINVAL;
- break;
- }
- ret = fc->isac.ctrl(&fc->isac, HW_TESTLOOP, cq->channel);
- break;
- case MISDN_CTRL_L1_TIMER3:
- ret = fc->isac.ctrl(&fc->isac, HW_TIMER3_VALUE, cq->p1);
- break;
- default:
- pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int
-open_bchannel(struct fritzcard *fc, struct channel_req *rq)
-{
- struct bchannel *bch;
-
- if (rq->adr.channel == 0 || rq->adr.channel > 2)
- return -EINVAL;
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
- bch = &fc->bch[rq->adr.channel - 1];
- if (test_and_set_bit(FLG_OPEN, &bch->Flags))
- return -EBUSY; /* b-channel can be only open once */
- bch->ch.protocol = rq->protocol;
- rq->ch = &bch->ch;
- return 0;
-}
-
-/*
- * device control function
- */
-static int
-avm_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct fritzcard *fc = dch->hw;
- struct channel_req *rq;
- int err = 0;
-
- pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg);
- switch (cmd) {
- case OPEN_CHANNEL:
- rq = arg;
- if (rq->protocol == ISDN_P_TE_S0)
- err = fc->isac.open(&fc->isac, rq);
- else
- err = open_bchannel(fc, rq);
- if (err)
- break;
- if (!try_module_get(THIS_MODULE))
- pr_info("%s: cannot get module\n", fc->name);
- break;
- case CLOSE_CHANNEL:
- pr_debug("%s: dev(%d) close from %p\n", fc->name, dch->dev.id,
- __builtin_return_address(0));
- module_put(THIS_MODULE);
- break;
- case CONTROL_CHANNEL:
- err = channel_ctrl(fc, arg);
- break;
- default:
- pr_debug("%s: %s unknown command %x\n",
- fc->name, __func__, cmd);
- return -EINVAL;
- }
- return err;
-}
-
-static int
-setup_fritz(struct fritzcard *fc)
-{
- u32 val, ver;
-
- if (!request_region(fc->addr, 32, fc->name)) {
- pr_info("%s: AVM config port %x-%x already in use\n",
- fc->name, fc->addr, fc->addr + 31);
- return -EIO;
- }
- switch (fc->type) {
- case AVM_FRITZ_PCI:
- val = inl(fc->addr);
- outl(AVM_HDLC_1, fc->addr + CHIP_INDEX);
- ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24;
- if (debug & DEBUG_HW) {
- pr_notice("%s: PCI stat %#x\n", fc->name, val);
- pr_notice("%s: PCI Class %X Rev %d\n", fc->name,
- val & 0xff, (val >> 8) & 0xff);
- pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf);
- }
- ASSIGN_FUNC(V1, ISAC, fc->isac);
- fc->isac.type = IPAC_TYPE_ISAC;
- break;
- case AVM_FRITZ_PCIV2:
- val = inl(fc->addr);
- ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24;
- if (debug & DEBUG_HW) {
- pr_notice("%s: PCI V2 stat %#x\n", fc->name, val);
- pr_notice("%s: PCI V2 Class %X Rev %d\n", fc->name,
- val & 0xff, (val >> 8) & 0xff);
- pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf);
- }
- ASSIGN_FUNC(V2, ISAC, fc->isac);
- fc->isac.type = IPAC_TYPE_ISACX;
- break;
- default:
- release_region(fc->addr, 32);
- pr_info("%s: AVM unknown type %d\n", fc->name, fc->type);
- return -ENODEV;
- }
- pr_notice("%s: %s config irq:%d base:0x%X\n", fc->name,
- (fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!CARD PCI" :
- "AVM Fritz!CARD PCIv2", fc->irq, fc->addr);
- return 0;
-}
-
-static void
-release_card(struct fritzcard *card)
-{
- u_long flags;
-
- disable_hwirq(card);
- spin_lock_irqsave(&card->lock, flags);
- modehdlc(&card->bch[0], ISDN_P_NONE);
- modehdlc(&card->bch[1], ISDN_P_NONE);
- spin_unlock_irqrestore(&card->lock, flags);
- card->isac.release(&card->isac);
- free_irq(card->irq, card);
- mISDN_freebchannel(&card->bch[1]);
- mISDN_freebchannel(&card->bch[0]);
- mISDN_unregister_device(&card->isac.dch.dev);
- release_region(card->addr, 32);
- pci_disable_device(card->pdev);
- pci_set_drvdata(card->pdev, NULL);
- write_lock_irqsave(&card_lock, flags);
- list_del(&card->list);
- write_unlock_irqrestore(&card_lock, flags);
- kfree(card);
- AVM_cnt--;
-}
-
-static int
-setup_instance(struct fritzcard *card)
-{
- int i, err;
- unsigned short minsize;
- u_long flags;
-
- snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1);
- write_lock_irqsave(&card_lock, flags);
- list_add_tail(&card->list, &Cards);
- write_unlock_irqrestore(&card_lock, flags);
-
- _set_debug(card);
- card->isac.name = card->name;
- spin_lock_init(&card->lock);
- card->isac.hwlock = &card->lock;
- mISDNisac_init(&card->isac, card);
-
- card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
- card->isac.dch.dev.D.ctrl = avm_dctrl;
- for (i = 0; i < 2; i++) {
- card->bch[i].nr = i + 1;
- set_channelmap(i + 1, card->isac.dch.dev.channelmap);
- if (AVM_FRITZ_PCIV2 == card->type)
- minsize = HDLC_FIFO_SIZE_V2;
- else
- minsize = HDLC_FIFO_SIZE_V1;
- mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, minsize);
- card->bch[i].hw = card;
- card->bch[i].ch.send = avm_l2l1B;
- card->bch[i].ch.ctrl = avm_bctrl;
- card->bch[i].ch.nr = i + 1;
- list_add(&card->bch[i].ch.list, &card->isac.dch.dev.bchannels);
- }
- err = setup_fritz(card);
- if (err)
- goto error;
- err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev,
- card->name);
- if (err)
- goto error_reg;
- err = init_card(card);
- if (!err) {
- AVM_cnt++;
- pr_notice("AVM %d cards installed DEBUG\n", AVM_cnt);
- return 0;
- }
- mISDN_unregister_device(&card->isac.dch.dev);
-error_reg:
- release_region(card->addr, 32);
-error:
- card->isac.release(&card->isac);
- mISDN_freebchannel(&card->bch[1]);
- mISDN_freebchannel(&card->bch[0]);
- write_lock_irqsave(&card_lock, flags);
- list_del(&card->list);
- write_unlock_irqrestore(&card_lock, flags);
- kfree(card);
- return err;
-}
-
-static int
-fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int err = -ENOMEM;
- struct fritzcard *card;
-
- card = kzalloc_obj(struct fritzcard);
- if (!card) {
- pr_info("No kmem for fritzcard\n");
- return err;
- }
- if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2)
- card->type = AVM_FRITZ_PCIV2;
- else
- card->type = AVM_FRITZ_PCI;
- card->pdev = pdev;
- err = pci_enable_device(pdev);
- if (err) {
- kfree(card);
- return err;
- }
-
- pr_notice("mISDN: found adapter %s at %s\n",
- (char *) ent->driver_data, pci_name(pdev));
-
- card->addr = pci_resource_start(pdev, 1);
- card->irq = pdev->irq;
- pci_set_drvdata(pdev, card);
- err = setup_instance(card);
- if (err)
- pci_set_drvdata(pdev, NULL);
- return err;
-}
-
-static void
-fritz_remove_pci(struct pci_dev *pdev)
-{
- struct fritzcard *card = pci_get_drvdata(pdev);
-
- if (card)
- release_card(card);
- else
- if (debug)
- pr_info("%s: drvdata already removed\n", __func__);
-}
-
-static const struct pci_device_id fcpci_ids[] = {
- { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, (unsigned long) "Fritz!Card PCI"},
- { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, (unsigned long) "Fritz!Card PCI v2" },
- { }
-};
-MODULE_DEVICE_TABLE(pci, fcpci_ids);
-
-static struct pci_driver fcpci_driver = {
- .name = "fcpci",
- .probe = fritzpci_probe,
- .remove = fritz_remove_pci,
- .id_table = fcpci_ids,
-};
-
-static int __init AVM_init(void)
-{
- int err;
-
- pr_notice("AVM Fritz PCI driver Rev. %s\n", AVMFRITZ_REV);
- err = pci_register_driver(&fcpci_driver);
- return err;
-}
-
-static void __exit AVM_cleanup(void)
-{
- pci_unregister_driver(&fcpci_driver);
-}
-
-module_init(AVM_init);
-module_exit(AVM_cleanup);
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * see notice in hfc_multi.c
- */
-
-#define DEBUG_HFCMULTI_FIFO 0x00010000
-#define DEBUG_HFCMULTI_CRC 0x00020000
-#define DEBUG_HFCMULTI_INIT 0x00040000
-#define DEBUG_HFCMULTI_PLXSD 0x00080000
-#define DEBUG_HFCMULTI_MODE 0x00100000
-#define DEBUG_HFCMULTI_MSG 0x00200000
-#define DEBUG_HFCMULTI_STATE 0x00400000
-#define DEBUG_HFCMULTI_FILL 0x00800000
-#define DEBUG_HFCMULTI_SYNC 0x01000000
-#define DEBUG_HFCMULTI_DTMF 0x02000000
-#define DEBUG_HFCMULTI_LOCK 0x80000000
-
-#define PCI_ENA_REGIO 0x01
-#define PCI_ENA_MEMIO 0x02
-
-#define XHFC_IRQ 4 /* SIU_IRQ2 */
-#define XHFC_MEMBASE 0xFE000000
-#define XHFC_MEMSIZE 0x00001000
-#define XHFC_OFFSET 0x00001000
-#define PA_XHFC_A0 0x0020 /* PA10 */
-#define PB_XHFC_IRQ1 0x00000100 /* PB23 */
-#define PB_XHFC_IRQ2 0x00000200 /* PB22 */
-#define PB_XHFC_IRQ3 0x00000400 /* PB21 */
-#define PB_XHFC_IRQ4 0x00000800 /* PB20 */
-
-/*
- * NOTE: some registers are assigned multiple times due to different modes
- * also registers are assigned differen for HFC-4s/8s and HFC-E1
- */
-
-/*
- #define MAX_FRAME_SIZE 2048
-*/
-
-struct hfc_chan {
- struct dchannel *dch; /* link if channel is a D-channel */
- struct bchannel *bch; /* link if channel is a B-channel */
- int port; /* the interface port this */
- /* channel is associated with */
- int nt_timer; /* -1 if off, 0 if elapsed, >0 if running */
- int los, ais, slip_tx, slip_rx, rdi; /* current alarms */
- int jitter;
- u_long cfg; /* port configuration */
- int sync; /* sync state (used by E1) */
- u_int protocol; /* current protocol */
- int slot_tx; /* current pcm slot */
- int bank_tx; /* current pcm bank */
- int slot_rx;
- int bank_rx;
- int conf; /* conference setting of TX slot */
- int txpending; /* if there is currently data in */
- /* the FIFO 0=no, 1=yes, 2=splloop */
- int Zfill; /* rx-fifo level on last hfcmulti_tx */
- int rx_off; /* set to turn fifo receive off */
- int coeff_count; /* curren coeff block */
- s32 *coeff; /* memory pointer to 8 coeff blocks */
-};
-
-
-struct hfcm_hw {
- u_char r_ctrl;
- u_char r_irq_ctrl;
- u_char r_cirm;
- u_char r_ram_sz;
- u_char r_pcm_md0;
- u_char r_irqmsk_misc;
- u_char r_dtmf;
- u_char r_st_sync;
- u_char r_sci_msk;
- u_char r_tx0, r_tx1;
- u_char a_st_ctrl0[8];
- u_char r_bert_wd_md;
- timer_t timer;
-};
-
-
-/* for each stack these flags are used (cfg) */
-#define HFC_CFG_NONCAP_TX 1 /* S/T TX interface has less capacity */
-#define HFC_CFG_DIS_ECHANNEL 2 /* disable E-channel processing */
-#define HFC_CFG_REG_ECHANNEL 3 /* register E-channel */
-#define HFC_CFG_OPTICAL 4 /* the E1 interface is optical */
-#define HFC_CFG_REPORT_LOS 5 /* the card should report loss of signal */
-#define HFC_CFG_REPORT_AIS 6 /* the card should report alarm ind. sign. */
-#define HFC_CFG_REPORT_SLIP 7 /* the card should report bit slips */
-#define HFC_CFG_REPORT_RDI 8 /* the card should report remote alarm */
-#define HFC_CFG_DTMF 9 /* enable DTMF-detection */
-#define HFC_CFG_CRC4 10 /* disable CRC-4 Multiframe mode, */
-/* use double frame instead. */
-
-#define HFC_TYPE_E1 1 /* controller is HFC-E1 */
-#define HFC_TYPE_4S 4 /* controller is HFC-4S */
-#define HFC_TYPE_8S 8 /* controller is HFC-8S */
-#define HFC_TYPE_XHFC 5 /* controller is XHFC */
-
-#define HFC_CHIP_EXRAM_128 0 /* external ram 128k */
-#define HFC_CHIP_EXRAM_512 1 /* external ram 256k */
-#define HFC_CHIP_REVISION0 2 /* old fifo handling */
-#define HFC_CHIP_PCM_SLAVE 3 /* PCM is slave */
-#define HFC_CHIP_PCM_MASTER 4 /* PCM is master */
-#define HFC_CHIP_RX_SYNC 5 /* disable pll sync for pcm */
-#define HFC_CHIP_DTMF 6 /* DTMF decoding is enabled */
-#define HFC_CHIP_CONF 7 /* conference handling is enabled */
-#define HFC_CHIP_ULAW 8 /* ULAW mode */
-#define HFC_CHIP_CLOCK2 9 /* double clock mode */
-#define HFC_CHIP_E1CLOCK_GET 10 /* always get clock from E1 interface */
-#define HFC_CHIP_E1CLOCK_PUT 11 /* always put clock from E1 interface */
-#define HFC_CHIP_WATCHDOG 12 /* whether we should send signals */
-/* to the watchdog */
-#define HFC_CHIP_B410P 13 /* whether we have a b410p with echocan in */
-/* hw */
-#define HFC_CHIP_PLXSD 14 /* whether we have a Speech-Design PLX */
-#define HFC_CHIP_EMBSD 15 /* whether we have a SD Embedded board */
-
-#define HFC_IO_MODE_PCIMEM 0x00 /* normal memory mapped IO */
-#define HFC_IO_MODE_REGIO 0x01 /* PCI io access */
-#define HFC_IO_MODE_PLXSD 0x02 /* access HFC via PLX9030 */
-#define HFC_IO_MODE_EMBSD 0x03 /* direct access */
-
-/* table entry in the PCI devices list */
-struct hm_map {
- char *vendor_name;
- char *card_name;
- int type;
- int ports;
- int clock2;
- int leds;
- int opticalsupport;
- int dip_type;
- int io_mode;
- int irq;
-};
-
-struct hfc_multi {
- struct list_head list;
- struct hm_map *mtyp;
- int id;
- int pcm; /* id of pcm bus */
- int ctype; /* controller type */
- int ports;
-
- u_int irq; /* irq used by card */
- u_int irqcnt;
- struct pci_dev *pci_dev;
- int io_mode; /* selects mode */
-#ifdef HFC_REGISTER_DEBUG
- void (*HFC_outb)(struct hfc_multi *hc, u_char reg,
- u_char val, const char *function, int line);
- void (*HFC_outb_nodebug)(struct hfc_multi *hc, u_char reg,
- u_char val, const char *function, int line);
- u_char (*HFC_inb)(struct hfc_multi *hc, u_char reg,
- const char *function, int line);
- u_char (*HFC_inb_nodebug)(struct hfc_multi *hc, u_char reg,
- const char *function, int line);
- u_short (*HFC_inw)(struct hfc_multi *hc, u_char reg,
- const char *function, int line);
- u_short (*HFC_inw_nodebug)(struct hfc_multi *hc, u_char reg,
- const char *function, int line);
- void (*HFC_wait)(struct hfc_multi *hc,
- const char *function, int line);
- void (*HFC_wait_nodebug)(struct hfc_multi *hc,
- const char *function, int line);
-#else
- void (*HFC_outb)(struct hfc_multi *hc, u_char reg,
- u_char val);
- void (*HFC_outb_nodebug)(struct hfc_multi *hc, u_char reg,
- u_char val);
- u_char (*HFC_inb)(struct hfc_multi *hc, u_char reg);
- u_char (*HFC_inb_nodebug)(struct hfc_multi *hc, u_char reg);
- u_short (*HFC_inw)(struct hfc_multi *hc, u_char reg);
- u_short (*HFC_inw_nodebug)(struct hfc_multi *hc, u_char reg);
- void (*HFC_wait)(struct hfc_multi *hc);
- void (*HFC_wait_nodebug)(struct hfc_multi *hc);
-#endif
- void (*read_fifo)(struct hfc_multi *hc, u_char *data,
- int len);
- void (*write_fifo)(struct hfc_multi *hc, u_char *data,
- int len);
- u_long pci_origmembase, plx_origmembase;
- void __iomem *pci_membase; /* PCI memory */
- void __iomem *plx_membase; /* PLX memory */
- u_long xhfc_origmembase;
- u_char *xhfc_membase;
- u_long *xhfc_memaddr, *xhfc_memdata;
-#ifdef CONFIG_MISDN_HFCMULTI_8xx
- struct immap *immap;
-#endif
- u_long pb_irqmsk; /* Portbit mask to check the IRQ line */
- u_long pci_iobase; /* PCI IO */
- struct hfcm_hw hw; /* remember data of write-only-registers */
-
- u_long chip; /* chip configuration */
- int masterclk; /* port that provides master clock -1=off */
- unsigned char silence;/* silence byte */
- unsigned char silence_data[128];/* silence block */
- int dtmf; /* flag that dtmf is currently in process */
- int Flen; /* F-buffer size */
- int Zlen; /* Z-buffer size (must be int for calculation)*/
- int max_trans; /* maximum transparent fifo fill */
- int Zmin; /* Z-buffer offset */
- int DTMFbase; /* base address of DTMF coefficients */
-
- u_int slots; /* number of PCM slots */
- u_int leds; /* type of leds */
- u_long ledstate; /* save last state of leds */
- int opticalsupport; /* has the e1 board */
- /* an optical Interface */
-
- u_int bmask[32]; /* bitmask of bchannels for port */
- u_char dnum[32]; /* array of used dchannel numbers for port */
- u_char created[32]; /* what port is created */
- u_int activity_tx; /* if there is data TX / RX */
- u_int activity_rx; /* bitmask according to port number */
- /* (will be cleared after */
- /* showing led-states) */
- u_int flash[8]; /* counter for flashing 8 leds on activity */
-
- u_long wdcount; /* every 500 ms we need to */
- /* send the watchdog a signal */
- u_char wdbyte; /* watchdog toggle byte */
- int e1_state; /* keep track of last state */
- int e1_getclock; /* if sync is retrieved from interface */
- int syncronized; /* keep track of existing sync interface */
- int e1_resync; /* resync jobs */
-
- spinlock_t lock; /* the lock */
-
- struct mISDNclock *iclock; /* isdn clock support */
- int iclock_on;
-
- /*
- * the channel index is counted from 0, regardless where the channel
- * is located on the hfc-channel.
- * the bch->channel is equvalent to the hfc-channel
- */
- struct hfc_chan chan[32];
- signed char slot_owner[256]; /* owner channel of slot */
-};
-
-/* PLX GPIOs */
-#define PLX_GPIO4_DIR_BIT 13
-#define PLX_GPIO4_BIT 14
-#define PLX_GPIO5_DIR_BIT 16
-#define PLX_GPIO5_BIT 17
-#define PLX_GPIO6_DIR_BIT 19
-#define PLX_GPIO6_BIT 20
-#define PLX_GPIO7_DIR_BIT 22
-#define PLX_GPIO7_BIT 23
-#define PLX_GPIO8_DIR_BIT 25
-#define PLX_GPIO8_BIT 26
-
-#define PLX_GPIO4 (1 << PLX_GPIO4_BIT)
-#define PLX_GPIO5 (1 << PLX_GPIO5_BIT)
-#define PLX_GPIO6 (1 << PLX_GPIO6_BIT)
-#define PLX_GPIO7 (1 << PLX_GPIO7_BIT)
-#define PLX_GPIO8 (1 << PLX_GPIO8_BIT)
-
-#define PLX_GPIO4_DIR (1 << PLX_GPIO4_DIR_BIT)
-#define PLX_GPIO5_DIR (1 << PLX_GPIO5_DIR_BIT)
-#define PLX_GPIO6_DIR (1 << PLX_GPIO6_DIR_BIT)
-#define PLX_GPIO7_DIR (1 << PLX_GPIO7_DIR_BIT)
-#define PLX_GPIO8_DIR (1 << PLX_GPIO8_DIR_BIT)
-
-#define PLX_TERM_ON PLX_GPIO7
-#define PLX_SLAVE_EN_N PLX_GPIO5
-#define PLX_MASTER_EN PLX_GPIO6
-#define PLX_SYNC_O_EN PLX_GPIO4
-#define PLX_DSP_RES_N PLX_GPIO8
-/* GPIO4..8 Enable & Set to OUT, SLAVE_EN_N = 1 */
-#define PLX_GPIOC_INIT (PLX_GPIO4_DIR | PLX_GPIO5_DIR | PLX_GPIO6_DIR \
- | PLX_GPIO7_DIR | PLX_GPIO8_DIR | PLX_SLAVE_EN_N)
-
-/* PLX Interrupt Control/STATUS */
-#define PLX_INTCSR_LINTI1_ENABLE 0x01
-#define PLX_INTCSR_LINTI1_STATUS 0x04
-#define PLX_INTCSR_LINTI2_ENABLE 0x08
-#define PLX_INTCSR_LINTI2_STATUS 0x20
-#define PLX_INTCSR_PCIINT_ENABLE 0x40
-
-/* PLX Registers */
-#define PLX_INTCSR 0x4c
-#define PLX_CNTRL 0x50
-#define PLX_GPIOC 0x54
-
-
-/*
- * REGISTER SETTING FOR HFC-4S/8S AND HFC-E1
- */
-
-/* write only registers */
-#define R_CIRM 0x00
-#define R_CTRL 0x01
-#define R_BRG_PCM_CFG 0x02
-#define R_RAM_ADDR0 0x08
-#define R_RAM_ADDR1 0x09
-#define R_RAM_ADDR2 0x0A
-#define R_FIRST_FIFO 0x0B
-#define R_RAM_SZ 0x0C
-#define R_FIFO_MD 0x0D
-#define R_INC_RES_FIFO 0x0E
-#define R_FSM_IDX 0x0F
-#define R_FIFO 0x0F
-#define R_SLOT 0x10
-#define R_IRQMSK_MISC 0x11
-#define R_SCI_MSK 0x12
-#define R_IRQ_CTRL 0x13
-#define R_PCM_MD0 0x14
-#define R_PCM_MD1 0x15
-#define R_PCM_MD2 0x15
-#define R_SH0H 0x15
-#define R_SH1H 0x15
-#define R_SH0L 0x15
-#define R_SH1L 0x15
-#define R_SL_SEL0 0x15
-#define R_SL_SEL1 0x15
-#define R_SL_SEL2 0x15
-#define R_SL_SEL3 0x15
-#define R_SL_SEL4 0x15
-#define R_SL_SEL5 0x15
-#define R_SL_SEL6 0x15
-#define R_SL_SEL7 0x15
-#define R_ST_SEL 0x16
-#define R_ST_SYNC 0x17
-#define R_CONF_EN 0x18
-#define R_TI_WD 0x1A
-#define R_BERT_WD_MD 0x1B
-#define R_DTMF 0x1C
-#define R_DTMF_N 0x1D
-#define R_E1_WR_STA 0x20
-#define R_E1_RD_STA 0x20
-#define R_LOS0 0x22
-#define R_LOS1 0x23
-#define R_RX0 0x24
-#define R_RX_FR0 0x25
-#define R_RX_FR1 0x26
-#define R_TX0 0x28
-#define R_TX1 0x29
-#define R_TX_FR0 0x2C
-
-#define R_TX_FR1 0x2D
-#define R_TX_FR2 0x2E
-#define R_JATT_ATT 0x2F /* undocumented */
-#define A_ST_RD_STATE 0x30
-#define A_ST_WR_STATE 0x30
-#define R_RX_OFF 0x30
-#define A_ST_CTRL0 0x31
-#define R_SYNC_OUT 0x31
-#define A_ST_CTRL1 0x32
-#define A_ST_CTRL2 0x33
-#define A_ST_SQ_WR 0x34
-#define R_TX_OFF 0x34
-#define R_SYNC_CTRL 0x35
-#define A_ST_CLK_DLY 0x37
-#define R_PWM0 0x38
-#define R_PWM1 0x39
-#define A_ST_B1_TX 0x3C
-#define A_ST_B2_TX 0x3D
-#define A_ST_D_TX 0x3E
-#define R_GPIO_OUT0 0x40
-#define R_GPIO_OUT1 0x41
-#define R_GPIO_EN0 0x42
-#define R_GPIO_EN1 0x43
-#define R_GPIO_SEL 0x44
-#define R_BRG_CTRL 0x45
-#define R_PWM_MD 0x46
-#define R_BRG_MD 0x47
-#define R_BRG_TIM0 0x48
-#define R_BRG_TIM1 0x49
-#define R_BRG_TIM2 0x4A
-#define R_BRG_TIM3 0x4B
-#define R_BRG_TIM_SEL01 0x4C
-#define R_BRG_TIM_SEL23 0x4D
-#define R_BRG_TIM_SEL45 0x4E
-#define R_BRG_TIM_SEL67 0x4F
-#define A_SL_CFG 0xD0
-#define A_CONF 0xD1
-#define A_CH_MSK 0xF4
-#define A_CON_HDLC 0xFA
-#define A_SUBCH_CFG 0xFB
-#define A_CHANNEL 0xFC
-#define A_FIFO_SEQ 0xFD
-#define A_IRQ_MSK 0xFF
-
-/* read only registers */
-#define A_Z12 0x04
-#define A_Z1L 0x04
-#define A_Z1 0x04
-#define A_Z1H 0x05
-#define A_Z2L 0x06
-#define A_Z2 0x06
-#define A_Z2H 0x07
-#define A_F1 0x0C
-#define A_F12 0x0C
-#define A_F2 0x0D
-#define R_IRQ_OVIEW 0x10
-#define R_IRQ_MISC 0x11
-#define R_IRQ_STATECH 0x12
-#define R_CONF_OFLOW 0x14
-#define R_RAM_USE 0x15
-#define R_CHIP_ID 0x16
-#define R_BERT_STA 0x17
-#define R_F0_CNTL 0x18
-#define R_F0_CNTH 0x19
-#define R_BERT_EC 0x1A
-#define R_BERT_ECL 0x1A
-#define R_BERT_ECH 0x1B
-#define R_STATUS 0x1C
-#define R_CHIP_RV 0x1F
-#define R_STATE 0x20
-#define R_SYNC_STA 0x24
-#define R_RX_SL0_0 0x25
-#define R_RX_SL0_1 0x26
-#define R_RX_SL0_2 0x27
-#define R_JATT_DIR 0x2b /* undocumented */
-#define R_SLIP 0x2c
-#define A_ST_RD_STA 0x30
-#define R_FAS_EC 0x30
-#define R_FAS_ECL 0x30
-#define R_FAS_ECH 0x31
-#define R_VIO_EC 0x32
-#define R_VIO_ECL 0x32
-#define R_VIO_ECH 0x33
-#define A_ST_SQ_RD 0x34
-#define R_CRC_EC 0x34
-#define R_CRC_ECL 0x34
-#define R_CRC_ECH 0x35
-#define R_E_EC 0x36
-#define R_E_ECL 0x36
-#define R_E_ECH 0x37
-#define R_SA6_SA13_EC 0x38
-#define R_SA6_SA13_ECL 0x38
-#define R_SA6_SA13_ECH 0x39
-#define R_SA6_SA23_EC 0x3A
-#define R_SA6_SA23_ECL 0x3A
-#define R_SA6_SA23_ECH 0x3B
-#define A_ST_B1_RX 0x3C
-#define A_ST_B2_RX 0x3D
-#define A_ST_D_RX 0x3E
-#define A_ST_E_RX 0x3F
-#define R_GPIO_IN0 0x40
-#define R_GPIO_IN1 0x41
-#define R_GPI_IN0 0x44
-#define R_GPI_IN1 0x45
-#define R_GPI_IN2 0x46
-#define R_GPI_IN3 0x47
-#define R_INT_DATA 0x88
-#define R_IRQ_FIFO_BL0 0xC8
-#define R_IRQ_FIFO_BL1 0xC9
-#define R_IRQ_FIFO_BL2 0xCA
-#define R_IRQ_FIFO_BL3 0xCB
-#define R_IRQ_FIFO_BL4 0xCC
-#define R_IRQ_FIFO_BL5 0xCD
-#define R_IRQ_FIFO_BL6 0xCE
-#define R_IRQ_FIFO_BL7 0xCF
-
-/* read and write registers */
-#define A_FIFO_DATA0 0x80
-#define A_FIFO_DATA1 0x80
-#define A_FIFO_DATA2 0x80
-#define A_FIFO_DATA0_NOINC 0x84
-#define A_FIFO_DATA1_NOINC 0x84
-#define A_FIFO_DATA2_NOINC 0x84
-#define R_RAM_DATA 0xC0
-
-
-/*
- * BIT SETTING FOR HFC-4S/8S AND HFC-E1
- */
-
-/* chapter 2: universal bus interface */
-/* R_CIRM */
-#define V_IRQ_SEL 0x01
-#define V_SRES 0x08
-#define V_HFCRES 0x10
-#define V_PCMRES 0x20
-#define V_STRES 0x40
-#define V_ETRES 0x40
-#define V_RLD_EPR 0x80
-/* R_CTRL */
-#define V_FIFO_LPRIO 0x02
-#define V_SLOW_RD 0x04
-#define V_EXT_RAM 0x08
-#define V_CLK_OFF 0x20
-#define V_ST_CLK 0x40
-/* R_RAM_ADDR0 */
-#define V_RAM_ADDR2 0x01
-#define V_ADDR_RES 0x40
-#define V_ADDR_INC 0x80
-/* R_RAM_SZ */
-#define V_RAM_SZ 0x01
-#define V_PWM0_16KHZ 0x10
-#define V_PWM1_16KHZ 0x20
-#define V_FZ_MD 0x80
-/* R_CHIP_ID */
-#define V_PNP_IRQ 0x01
-#define V_CHIP_ID 0x10
-
-/* chapter 3: data flow */
-/* R_FIRST_FIFO */
-#define V_FIRST_FIRO_DIR 0x01
-#define V_FIRST_FIFO_NUM 0x02
-/* R_FIFO_MD */
-#define V_FIFO_MD 0x01
-#define V_CSM_MD 0x04
-#define V_FSM_MD 0x08
-#define V_FIFO_SZ 0x10
-/* R_FIFO */
-#define V_FIFO_DIR 0x01
-#define V_FIFO_NUM 0x02
-#define V_REV 0x80
-/* R_SLOT */
-#define V_SL_DIR 0x01
-#define V_SL_NUM 0x02
-/* A_SL_CFG */
-#define V_CH_DIR 0x01
-#define V_CH_SEL 0x02
-#define V_ROUTING 0x40
-/* A_CON_HDLC */
-#define V_IFF 0x01
-#define V_HDLC_TRP 0x02
-#define V_TRP_IRQ 0x04
-#define V_DATA_FLOW 0x20
-/* A_SUBCH_CFG */
-#define V_BIT_CNT 0x01
-#define V_START_BIT 0x08
-#define V_LOOP_FIFO 0x40
-#define V_INV_DATA 0x80
-/* A_CHANNEL */
-#define V_CH_DIR0 0x01
-#define V_CH_NUM0 0x02
-/* A_FIFO_SEQ */
-#define V_NEXT_FIFO_DIR 0x01
-#define V_NEXT_FIFO_NUM 0x02
-#define V_SEQ_END 0x40
-
-/* chapter 4: FIFO handling and HDLC controller */
-/* R_INC_RES_FIFO */
-#define V_INC_F 0x01
-#define V_RES_F 0x02
-#define V_RES_LOST 0x04
-
-/* chapter 5: S/T interface */
-/* R_SCI_MSK */
-#define V_SCI_MSK_ST0 0x01
-#define V_SCI_MSK_ST1 0x02
-#define V_SCI_MSK_ST2 0x04
-#define V_SCI_MSK_ST3 0x08
-#define V_SCI_MSK_ST4 0x10
-#define V_SCI_MSK_ST5 0x20
-#define V_SCI_MSK_ST6 0x40
-#define V_SCI_MSK_ST7 0x80
-/* R_ST_SEL */
-#define V_ST_SEL 0x01
-#define V_MULT_ST 0x08
-/* R_ST_SYNC */
-#define V_SYNC_SEL 0x01
-#define V_AUTO_SYNC 0x08
-/* A_ST_WR_STA */
-#define V_ST_SET_STA 0x01
-#define V_ST_LD_STA 0x10
-#define V_ST_ACT 0x20
-#define V_SET_G2_G3 0x80
-/* A_ST_CTRL0 */
-#define V_B1_EN 0x01
-#define V_B2_EN 0x02
-#define V_ST_MD 0x04
-#define V_D_PRIO 0x08
-#define V_SQ_EN 0x10
-#define V_96KHZ 0x20
-#define V_TX_LI 0x40
-#define V_ST_STOP 0x80
-/* A_ST_CTRL1 */
-#define V_G2_G3_EN 0x01
-#define V_D_HI 0x04
-#define V_E_IGNO 0x08
-#define V_E_LO 0x10
-#define V_B12_SWAP 0x80
-/* A_ST_CTRL2 */
-#define V_B1_RX_EN 0x01
-#define V_B2_RX_EN 0x02
-#define V_ST_TRIS 0x40
-/* A_ST_CLK_DLY */
-#define V_ST_CK_DLY 0x01
-#define V_ST_SMPL 0x10
-/* A_ST_D_TX */
-#define V_ST_D_TX 0x40
-/* R_IRQ_STATECH */
-#define V_SCI_ST0 0x01
-#define V_SCI_ST1 0x02
-#define V_SCI_ST2 0x04
-#define V_SCI_ST3 0x08
-#define V_SCI_ST4 0x10
-#define V_SCI_ST5 0x20
-#define V_SCI_ST6 0x40
-#define V_SCI_ST7 0x80
-/* A_ST_RD_STA */
-#define V_ST_STA 0x01
-#define V_FR_SYNC_ST 0x10
-#define V_TI2_EXP 0x20
-#define V_INFO0 0x40
-#define V_G2_G3 0x80
-/* A_ST_SQ_RD */
-#define V_ST_SQ 0x01
-#define V_MF_RX_RDY 0x10
-#define V_MF_TX_RDY 0x80
-/* A_ST_D_RX */
-#define V_ST_D_RX 0x40
-/* A_ST_E_RX */
-#define V_ST_E_RX 0x40
-
-/* chapter 5: E1 interface */
-/* R_E1_WR_STA */
-/* R_E1_RD_STA */
-#define V_E1_SET_STA 0x01
-#define V_E1_LD_STA 0x10
-/* R_RX0 */
-#define V_RX_CODE 0x01
-#define V_RX_FBAUD 0x04
-#define V_RX_CMI 0x08
-#define V_RX_INV_CMI 0x10
-#define V_RX_INV_CLK 0x20
-#define V_RX_INV_DATA 0x40
-#define V_AIS_ITU 0x80
-/* R_RX_FR0 */
-#define V_NO_INSYNC 0x01
-#define V_AUTO_RESYNC 0x02
-#define V_AUTO_RECO 0x04
-#define V_SWORD_COND 0x08
-#define V_SYNC_LOSS 0x10
-#define V_XCRC_SYNC 0x20
-#define V_MF_RESYNC 0x40
-#define V_RESYNC 0x80
-/* R_RX_FR1 */
-#define V_RX_MF 0x01
-#define V_RX_MF_SYNC 0x02
-#define V_RX_SL0_RAM 0x04
-#define V_ERR_SIM 0x20
-#define V_RES_NMF 0x40
-/* R_TX0 */
-#define V_TX_CODE 0x01
-#define V_TX_FBAUD 0x04
-#define V_TX_CMI_CODE 0x08
-#define V_TX_INV_CMI_CODE 0x10
-#define V_TX_INV_CLK 0x20
-#define V_TX_INV_DATA 0x40
-#define V_OUT_EN 0x80
-/* R_TX1 */
-#define V_INV_CLK 0x01
-#define V_EXCHG_DATA_LI 0x02
-#define V_AIS_OUT 0x04
-#define V_ATX 0x20
-#define V_NTRI 0x40
-#define V_AUTO_ERR_RES 0x80
-/* R_TX_FR0 */
-#define V_TRP_FAS 0x01
-#define V_TRP_NFAS 0x02
-#define V_TRP_RAL 0x04
-#define V_TRP_SA 0x08
-/* R_TX_FR1 */
-#define V_TX_FAS 0x01
-#define V_TX_NFAS 0x02
-#define V_TX_RAL 0x04
-#define V_TX_SA 0x08
-/* R_TX_FR2 */
-#define V_TX_MF 0x01
-#define V_TRP_SL0 0x02
-#define V_TX_SL0_RAM 0x04
-#define V_TX_E 0x10
-#define V_NEG_E 0x20
-#define V_XS12_ON 0x40
-#define V_XS15_ON 0x80
-/* R_RX_OFF */
-#define V_RX_SZ 0x01
-#define V_RX_INIT 0x04
-/* R_SYNC_OUT */
-#define V_SYNC_E1_RX 0x01
-#define V_IPATS0 0x20
-#define V_IPATS1 0x40
-#define V_IPATS2 0x80
-/* R_TX_OFF */
-#define V_TX_SZ 0x01
-#define V_TX_INIT 0x04
-/* R_SYNC_CTRL */
-#define V_EXT_CLK_SYNC 0x01
-#define V_SYNC_OFFS 0x02
-#define V_PCM_SYNC 0x04
-#define V_NEG_CLK 0x08
-#define V_HCLK 0x10
-/*
- #define V_JATT_AUTO_DEL 0x20
- #define V_JATT_AUTO 0x40
-*/
-#define V_JATT_OFF 0x80
-/* R_STATE */
-#define V_E1_STA 0x01
-#define V_ALT_FR_RX 0x40
-#define V_ALT_FR_TX 0x80
-/* R_SYNC_STA */
-#define V_RX_STA 0x01
-#define V_FR_SYNC_E1 0x04
-#define V_SIG_LOS 0x08
-#define V_MFA_STA 0x10
-#define V_AIS 0x40
-#define V_NO_MF_SYNC 0x80
-/* R_RX_SL0_0 */
-#define V_SI_FAS 0x01
-#define V_SI_NFAS 0x02
-#define V_A 0x04
-#define V_CRC_OK 0x08
-#define V_TX_E1 0x10
-#define V_TX_E2 0x20
-#define V_RX_E1 0x40
-#define V_RX_E2 0x80
-/* R_SLIP */
-#define V_SLIP_RX 0x01
-#define V_FOSLIP_RX 0x08
-#define V_SLIP_TX 0x10
-#define V_FOSLIP_TX 0x80
-
-/* chapter 6: PCM interface */
-/* R_PCM_MD0 */
-#define V_PCM_MD 0x01
-#define V_C4_POL 0x02
-#define V_F0_NEG 0x04
-#define V_F0_LEN 0x08
-#define V_PCM_ADDR 0x10
-/* R_SL_SEL0 */
-#define V_SL_SEL0 0x01
-#define V_SH_SEL0 0x80
-/* R_SL_SEL1 */
-#define V_SL_SEL1 0x01
-#define V_SH_SEL1 0x80
-/* R_SL_SEL2 */
-#define V_SL_SEL2 0x01
-#define V_SH_SEL2 0x80
-/* R_SL_SEL3 */
-#define V_SL_SEL3 0x01
-#define V_SH_SEL3 0x80
-/* R_SL_SEL4 */
-#define V_SL_SEL4 0x01
-#define V_SH_SEL4 0x80
-/* R_SL_SEL5 */
-#define V_SL_SEL5 0x01
-#define V_SH_SEL5 0x80
-/* R_SL_SEL6 */
-#define V_SL_SEL6 0x01
-#define V_SH_SEL6 0x80
-/* R_SL_SEL7 */
-#define V_SL_SEL7 0x01
-#define V_SH_SEL7 0x80
-/* R_PCM_MD1 */
-#define V_ODEC_CON 0x01
-#define V_PLL_ADJ 0x04
-#define V_PCM_DR 0x10
-#define V_PCM_LOOP 0x40
-/* R_PCM_MD2 */
-#define V_SYNC_PLL 0x02
-#define V_SYNC_SRC 0x04
-#define V_SYNC_OUT 0x08
-#define V_ICR_FR_TIME 0x40
-#define V_EN_PLL 0x80
-
-/* chapter 7: pulse width modulation */
-/* R_PWM_MD */
-#define V_EXT_IRQ_EN 0x08
-#define V_PWM0_MD 0x10
-#define V_PWM1_MD 0x40
-
-/* chapter 8: multiparty audio conferences */
-/* R_CONF_EN */
-#define V_CONF_EN 0x01
-#define V_ULAW 0x80
-/* A_CONF */
-#define V_CONF_NUM 0x01
-#define V_NOISE_SUPPR 0x08
-#define V_ATT_LEV 0x20
-#define V_CONF_SL 0x80
-/* R_CONF_OFLOW */
-#define V_CONF_OFLOW0 0x01
-#define V_CONF_OFLOW1 0x02
-#define V_CONF_OFLOW2 0x04
-#define V_CONF_OFLOW3 0x08
-#define V_CONF_OFLOW4 0x10
-#define V_CONF_OFLOW5 0x20
-#define V_CONF_OFLOW6 0x40
-#define V_CONF_OFLOW7 0x80
-
-/* chapter 9: DTMF contoller */
-/* R_DTMF0 */
-#define V_DTMF_EN 0x01
-#define V_HARM_SEL 0x02
-#define V_DTMF_RX_CH 0x04
-#define V_DTMF_STOP 0x08
-#define V_CHBL_SEL 0x10
-#define V_RST_DTMF 0x40
-#define V_ULAW_SEL 0x80
-
-/* chapter 10: BERT */
-/* R_BERT_WD_MD */
-#define V_PAT_SEQ 0x01
-#define V_BERT_ERR 0x08
-#define V_AUTO_WD_RES 0x20
-#define V_WD_RES 0x80
-/* R_BERT_STA */
-#define V_BERT_SYNC_SRC 0x01
-#define V_BERT_SYNC 0x10
-#define V_BERT_INV_DATA 0x20
-
-/* chapter 11: auxiliary interface */
-/* R_BRG_PCM_CFG */
-#define V_BRG_EN 0x01
-#define V_BRG_MD 0x02
-#define V_PCM_CLK 0x20
-#define V_ADDR_WRDLY 0x40
-/* R_BRG_CTRL */
-#define V_BRG_CS 0x01
-#define V_BRG_ADDR 0x08
-#define V_BRG_CS_SRC 0x80
-/* R_BRG_MD */
-#define V_BRG_MD0 0x01
-#define V_BRG_MD1 0x02
-#define V_BRG_MD2 0x04
-#define V_BRG_MD3 0x08
-#define V_BRG_MD4 0x10
-#define V_BRG_MD5 0x20
-#define V_BRG_MD6 0x40
-#define V_BRG_MD7 0x80
-/* R_BRG_TIM0 */
-#define V_BRG_TIM0_IDLE 0x01
-#define V_BRG_TIM0_CLK 0x10
-/* R_BRG_TIM1 */
-#define V_BRG_TIM1_IDLE 0x01
-#define V_BRG_TIM1_CLK 0x10
-/* R_BRG_TIM2 */
-#define V_BRG_TIM2_IDLE 0x01
-#define V_BRG_TIM2_CLK 0x10
-/* R_BRG_TIM3 */
-#define V_BRG_TIM3_IDLE 0x01
-#define V_BRG_TIM3_CLK 0x10
-/* R_BRG_TIM_SEL01 */
-#define V_BRG_WR_SEL0 0x01
-#define V_BRG_RD_SEL0 0x04
-#define V_BRG_WR_SEL1 0x10
-#define V_BRG_RD_SEL1 0x40
-/* R_BRG_TIM_SEL23 */
-#define V_BRG_WR_SEL2 0x01
-#define V_BRG_RD_SEL2 0x04
-#define V_BRG_WR_SEL3 0x10
-#define V_BRG_RD_SEL3 0x40
-/* R_BRG_TIM_SEL45 */
-#define V_BRG_WR_SEL4 0x01
-#define V_BRG_RD_SEL4 0x04
-#define V_BRG_WR_SEL5 0x10
-#define V_BRG_RD_SEL5 0x40
-/* R_BRG_TIM_SEL67 */
-#define V_BRG_WR_SEL6 0x01
-#define V_BRG_RD_SEL6 0x04
-#define V_BRG_WR_SEL7 0x10
-#define V_BRG_RD_SEL7 0x40
-
-/* chapter 12: clock, reset, interrupt, timer and watchdog */
-/* R_IRQMSK_MISC */
-#define V_STA_IRQMSK 0x01
-#define V_TI_IRQMSK 0x02
-#define V_PROC_IRQMSK 0x04
-#define V_DTMF_IRQMSK 0x08
-#define V_IRQ1S_MSK 0x10
-#define V_SA6_IRQMSK 0x20
-#define V_RX_EOMF_MSK 0x40
-#define V_TX_EOMF_MSK 0x80
-/* R_IRQ_CTRL */
-#define V_FIFO_IRQ 0x01
-#define V_GLOB_IRQ_EN 0x08
-#define V_IRQ_POL 0x10
-/* R_TI_WD */
-#define V_EV_TS 0x01
-#define V_WD_TS 0x10
-/* A_IRQ_MSK */
-#define V_IRQ 0x01
-#define V_BERT_EN 0x02
-#define V_MIX_IRQ 0x04
-/* R_IRQ_OVIEW */
-#define V_IRQ_FIFO_BL0 0x01
-#define V_IRQ_FIFO_BL1 0x02
-#define V_IRQ_FIFO_BL2 0x04
-#define V_IRQ_FIFO_BL3 0x08
-#define V_IRQ_FIFO_BL4 0x10
-#define V_IRQ_FIFO_BL5 0x20
-#define V_IRQ_FIFO_BL6 0x40
-#define V_IRQ_FIFO_BL7 0x80
-/* R_IRQ_MISC */
-#define V_STA_IRQ 0x01
-#define V_TI_IRQ 0x02
-#define V_IRQ_PROC 0x04
-#define V_DTMF_IRQ 0x08
-#define V_IRQ1S 0x10
-#define V_SA6_IRQ 0x20
-#define V_RX_EOMF 0x40
-#define V_TX_EOMF 0x80
-/* R_STATUS */
-#define V_BUSY 0x01
-#define V_PROC 0x02
-#define V_DTMF_STA 0x04
-#define V_LOST_STA 0x08
-#define V_SYNC_IN 0x10
-#define V_EXT_IRQSTA 0x20
-#define V_MISC_IRQSTA 0x40
-#define V_FR_IRQSTA 0x80
-/* R_IRQ_FIFO_BL0 */
-#define V_IRQ_FIFO0_TX 0x01
-#define V_IRQ_FIFO0_RX 0x02
-#define V_IRQ_FIFO1_TX 0x04
-#define V_IRQ_FIFO1_RX 0x08
-#define V_IRQ_FIFO2_TX 0x10
-#define V_IRQ_FIFO2_RX 0x20
-#define V_IRQ_FIFO3_TX 0x40
-#define V_IRQ_FIFO3_RX 0x80
-/* R_IRQ_FIFO_BL1 */
-#define V_IRQ_FIFO4_TX 0x01
-#define V_IRQ_FIFO4_RX 0x02
-#define V_IRQ_FIFO5_TX 0x04
-#define V_IRQ_FIFO5_RX 0x08
-#define V_IRQ_FIFO6_TX 0x10
-#define V_IRQ_FIFO6_RX 0x20
-#define V_IRQ_FIFO7_TX 0x40
-#define V_IRQ_FIFO7_RX 0x80
-/* R_IRQ_FIFO_BL2 */
-#define V_IRQ_FIFO8_TX 0x01
-#define V_IRQ_FIFO8_RX 0x02
-#define V_IRQ_FIFO9_TX 0x04
-#define V_IRQ_FIFO9_RX 0x08
-#define V_IRQ_FIFO10_TX 0x10
-#define V_IRQ_FIFO10_RX 0x20
-#define V_IRQ_FIFO11_TX 0x40
-#define V_IRQ_FIFO11_RX 0x80
-/* R_IRQ_FIFO_BL3 */
-#define V_IRQ_FIFO12_TX 0x01
-#define V_IRQ_FIFO12_RX 0x02
-#define V_IRQ_FIFO13_TX 0x04
-#define V_IRQ_FIFO13_RX 0x08
-#define V_IRQ_FIFO14_TX 0x10
-#define V_IRQ_FIFO14_RX 0x20
-#define V_IRQ_FIFO15_TX 0x40
-#define V_IRQ_FIFO15_RX 0x80
-/* R_IRQ_FIFO_BL4 */
-#define V_IRQ_FIFO16_TX 0x01
-#define V_IRQ_FIFO16_RX 0x02
-#define V_IRQ_FIFO17_TX 0x04
-#define V_IRQ_FIFO17_RX 0x08
-#define V_IRQ_FIFO18_TX 0x10
-#define V_IRQ_FIFO18_RX 0x20
-#define V_IRQ_FIFO19_TX 0x40
-#define V_IRQ_FIFO19_RX 0x80
-/* R_IRQ_FIFO_BL5 */
-#define V_IRQ_FIFO20_TX 0x01
-#define V_IRQ_FIFO20_RX 0x02
-#define V_IRQ_FIFO21_TX 0x04
-#define V_IRQ_FIFO21_RX 0x08
-#define V_IRQ_FIFO22_TX 0x10
-#define V_IRQ_FIFO22_RX 0x20
-#define V_IRQ_FIFO23_TX 0x40
-#define V_IRQ_FIFO23_RX 0x80
-/* R_IRQ_FIFO_BL6 */
-#define V_IRQ_FIFO24_TX 0x01
-#define V_IRQ_FIFO24_RX 0x02
-#define V_IRQ_FIFO25_TX 0x04
-#define V_IRQ_FIFO25_RX 0x08
-#define V_IRQ_FIFO26_TX 0x10
-#define V_IRQ_FIFO26_RX 0x20
-#define V_IRQ_FIFO27_TX 0x40
-#define V_IRQ_FIFO27_RX 0x80
-/* R_IRQ_FIFO_BL7 */
-#define V_IRQ_FIFO28_TX 0x01
-#define V_IRQ_FIFO28_RX 0x02
-#define V_IRQ_FIFO29_TX 0x04
-#define V_IRQ_FIFO29_RX 0x08
-#define V_IRQ_FIFO30_TX 0x10
-#define V_IRQ_FIFO30_RX 0x20
-#define V_IRQ_FIFO31_TX 0x40
-#define V_IRQ_FIFO31_RX 0x80
-
-/* chapter 13: general purpose I/O pins (GPIO) and input pins (GPI) */
-/* R_GPIO_OUT0 */
-#define V_GPIO_OUT0 0x01
-#define V_GPIO_OUT1 0x02
-#define V_GPIO_OUT2 0x04
-#define V_GPIO_OUT3 0x08
-#define V_GPIO_OUT4 0x10
-#define V_GPIO_OUT5 0x20
-#define V_GPIO_OUT6 0x40
-#define V_GPIO_OUT7 0x80
-/* R_GPIO_OUT1 */
-#define V_GPIO_OUT8 0x01
-#define V_GPIO_OUT9 0x02
-#define V_GPIO_OUT10 0x04
-#define V_GPIO_OUT11 0x08
-#define V_GPIO_OUT12 0x10
-#define V_GPIO_OUT13 0x20
-#define V_GPIO_OUT14 0x40
-#define V_GPIO_OUT15 0x80
-/* R_GPIO_EN0 */
-#define V_GPIO_EN0 0x01
-#define V_GPIO_EN1 0x02
-#define V_GPIO_EN2 0x04
-#define V_GPIO_EN3 0x08
-#define V_GPIO_EN4 0x10
-#define V_GPIO_EN5 0x20
-#define V_GPIO_EN6 0x40
-#define V_GPIO_EN7 0x80
-/* R_GPIO_EN1 */
-#define V_GPIO_EN8 0x01
-#define V_GPIO_EN9 0x02
-#define V_GPIO_EN10 0x04
-#define V_GPIO_EN11 0x08
-#define V_GPIO_EN12 0x10
-#define V_GPIO_EN13 0x20
-#define V_GPIO_EN14 0x40
-#define V_GPIO_EN15 0x80
-/* R_GPIO_SEL */
-#define V_GPIO_SEL0 0x01
-#define V_GPIO_SEL1 0x02
-#define V_GPIO_SEL2 0x04
-#define V_GPIO_SEL3 0x08
-#define V_GPIO_SEL4 0x10
-#define V_GPIO_SEL5 0x20
-#define V_GPIO_SEL6 0x40
-#define V_GPIO_SEL7 0x80
-/* R_GPIO_IN0 */
-#define V_GPIO_IN0 0x01
-#define V_GPIO_IN1 0x02
-#define V_GPIO_IN2 0x04
-#define V_GPIO_IN3 0x08
-#define V_GPIO_IN4 0x10
-#define V_GPIO_IN5 0x20
-#define V_GPIO_IN6 0x40
-#define V_GPIO_IN7 0x80
-/* R_GPIO_IN1 */
-#define V_GPIO_IN8 0x01
-#define V_GPIO_IN9 0x02
-#define V_GPIO_IN10 0x04
-#define V_GPIO_IN11 0x08
-#define V_GPIO_IN12 0x10
-#define V_GPIO_IN13 0x20
-#define V_GPIO_IN14 0x40
-#define V_GPIO_IN15 0x80
-/* R_GPI_IN0 */
-#define V_GPI_IN0 0x01
-#define V_GPI_IN1 0x02
-#define V_GPI_IN2 0x04
-#define V_GPI_IN3 0x08
-#define V_GPI_IN4 0x10
-#define V_GPI_IN5 0x20
-#define V_GPI_IN6 0x40
-#define V_GPI_IN7 0x80
-/* R_GPI_IN1 */
-#define V_GPI_IN8 0x01
-#define V_GPI_IN9 0x02
-#define V_GPI_IN10 0x04
-#define V_GPI_IN11 0x08
-#define V_GPI_IN12 0x10
-#define V_GPI_IN13 0x20
-#define V_GPI_IN14 0x40
-#define V_GPI_IN15 0x80
-/* R_GPI_IN2 */
-#define V_GPI_IN16 0x01
-#define V_GPI_IN17 0x02
-#define V_GPI_IN18 0x04
-#define V_GPI_IN19 0x08
-#define V_GPI_IN20 0x10
-#define V_GPI_IN21 0x20
-#define V_GPI_IN22 0x40
-#define V_GPI_IN23 0x80
-/* R_GPI_IN3 */
-#define V_GPI_IN24 0x01
-#define V_GPI_IN25 0x02
-#define V_GPI_IN26 0x04
-#define V_GPI_IN27 0x08
-#define V_GPI_IN28 0x10
-#define V_GPI_IN29 0x20
-#define V_GPI_IN30 0x40
-#define V_GPI_IN31 0x80
-
-/* map of all registers, used for debugging */
-
-#ifdef HFC_REGISTER_DEBUG
-struct hfc_register_names {
- char *name;
- u_char reg;
-} hfc_register_names[] = {
- /* write registers */
- {"R_CIRM", 0x00},
- {"R_CTRL", 0x01},
- {"R_BRG_PCM_CFG ", 0x02},
- {"R_RAM_ADDR0", 0x08},
- {"R_RAM_ADDR1", 0x09},
- {"R_RAM_ADDR2", 0x0A},
- {"R_FIRST_FIFO", 0x0B},
- {"R_RAM_SZ", 0x0C},
- {"R_FIFO_MD", 0x0D},
- {"R_INC_RES_FIFO", 0x0E},
- {"R_FIFO / R_FSM_IDX", 0x0F},
- {"R_SLOT", 0x10},
- {"R_IRQMSK_MISC", 0x11},
- {"R_SCI_MSK", 0x12},
- {"R_IRQ_CTRL", 0x13},
- {"R_PCM_MD0", 0x14},
- {"R_0x15", 0x15},
- {"R_ST_SEL", 0x16},
- {"R_ST_SYNC", 0x17},
- {"R_CONF_EN", 0x18},
- {"R_TI_WD", 0x1A},
- {"R_BERT_WD_MD", 0x1B},
- {"R_DTMF", 0x1C},
- {"R_DTMF_N", 0x1D},
- {"R_E1_XX_STA", 0x20},
- {"R_LOS0", 0x22},
- {"R_LOS1", 0x23},
- {"R_RX0", 0x24},
- {"R_RX_FR0", 0x25},
- {"R_RX_FR1", 0x26},
- {"R_TX0", 0x28},
- {"R_TX1", 0x29},
- {"R_TX_FR0", 0x2C},
- {"R_TX_FR1", 0x2D},
- {"R_TX_FR2", 0x2E},
- {"R_JATT_ATT", 0x2F},
- {"A_ST_xx_STA/R_RX_OFF", 0x30},
- {"A_ST_CTRL0/R_SYNC_OUT", 0x31},
- {"A_ST_CTRL1", 0x32},
- {"A_ST_CTRL2", 0x33},
- {"A_ST_SQ_WR", 0x34},
- {"R_TX_OFF", 0x34},
- {"R_SYNC_CTRL", 0x35},
- {"A_ST_CLK_DLY", 0x37},
- {"R_PWM0", 0x38},
- {"R_PWM1", 0x39},
- {"A_ST_B1_TX", 0x3C},
- {"A_ST_B2_TX", 0x3D},
- {"A_ST_D_TX", 0x3E},
- {"R_GPIO_OUT0", 0x40},
- {"R_GPIO_OUT1", 0x41},
- {"R_GPIO_EN0", 0x42},
- {"R_GPIO_EN1", 0x43},
- {"R_GPIO_SEL", 0x44},
- {"R_BRG_CTRL", 0x45},
- {"R_PWM_MD", 0x46},
- {"R_BRG_MD", 0x47},
- {"R_BRG_TIM0", 0x48},
- {"R_BRG_TIM1", 0x49},
- {"R_BRG_TIM2", 0x4A},
- {"R_BRG_TIM3", 0x4B},
- {"R_BRG_TIM_SEL01", 0x4C},
- {"R_BRG_TIM_SEL23", 0x4D},
- {"R_BRG_TIM_SEL45", 0x4E},
- {"R_BRG_TIM_SEL67", 0x4F},
- {"A_FIFO_DATA0-2", 0x80},
- {"A_FIFO_DATA0-2_NOINC", 0x84},
- {"R_RAM_DATA", 0xC0},
- {"A_SL_CFG", 0xD0},
- {"A_CONF", 0xD1},
- {"A_CH_MSK", 0xF4},
- {"A_CON_HDLC", 0xFA},
- {"A_SUBCH_CFG", 0xFB},
- {"A_CHANNEL", 0xFC},
- {"A_FIFO_SEQ", 0xFD},
- {"A_IRQ_MSK", 0xFF},
- {NULL, 0},
-
- /* read registers */
- {"A_Z1", 0x04},
- {"A_Z1H", 0x05},
- {"A_Z2", 0x06},
- {"A_Z2H", 0x07},
- {"A_F1", 0x0C},
- {"A_F2", 0x0D},
- {"R_IRQ_OVIEW", 0x10},
- {"R_IRQ_MISC", 0x11},
- {"R_IRQ_STATECH", 0x12},
- {"R_CONF_OFLOW", 0x14},
- {"R_RAM_USE", 0x15},
- {"R_CHIP_ID", 0x16},
- {"R_BERT_STA", 0x17},
- {"R_F0_CNTL", 0x18},
- {"R_F0_CNTH", 0x19},
- {"R_BERT_ECL", 0x1A},
- {"R_BERT_ECH", 0x1B},
- {"R_STATUS", 0x1C},
- {"R_CHIP_RV", 0x1F},
- {"R_STATE", 0x20},
- {"R_SYNC_STA", 0x24},
- {"R_RX_SL0_0", 0x25},
- {"R_RX_SL0_1", 0x26},
- {"R_RX_SL0_2", 0x27},
- {"R_JATT_DIR", 0x2b},
- {"R_SLIP", 0x2c},
- {"A_ST_RD_STA", 0x30},
- {"R_FAS_ECL", 0x30},
- {"R_FAS_ECH", 0x31},
- {"R_VIO_ECL", 0x32},
- {"R_VIO_ECH", 0x33},
- {"R_CRC_ECL / A_ST_SQ_RD", 0x34},
- {"R_CRC_ECH", 0x35},
- {"R_E_ECL", 0x36},
- {"R_E_ECH", 0x37},
- {"R_SA6_SA13_ECL", 0x38},
- {"R_SA6_SA13_ECH", 0x39},
- {"R_SA6_SA23_ECL", 0x3A},
- {"R_SA6_SA23_ECH", 0x3B},
- {"A_ST_B1_RX", 0x3C},
- {"A_ST_B2_RX", 0x3D},
- {"A_ST_D_RX", 0x3E},
- {"A_ST_E_RX", 0x3F},
- {"R_GPIO_IN0", 0x40},
- {"R_GPIO_IN1", 0x41},
- {"R_GPI_IN0", 0x44},
- {"R_GPI_IN1", 0x45},
- {"R_GPI_IN2", 0x46},
- {"R_GPI_IN3", 0x47},
- {"A_FIFO_DATA0-2", 0x80},
- {"A_FIFO_DATA0-2_NOINC", 0x84},
- {"R_INT_DATA", 0x88},
- {"R_RAM_DATA", 0xC0},
- {"R_IRQ_FIFO_BL0", 0xC8},
- {"R_IRQ_FIFO_BL1", 0xC9},
- {"R_IRQ_FIFO_BL2", 0xCA},
- {"R_IRQ_FIFO_BL3", 0xCB},
- {"R_IRQ_FIFO_BL4", 0xCC},
- {"R_IRQ_FIFO_BL5", 0xCD},
- {"R_IRQ_FIFO_BL6", 0xCE},
- {"R_IRQ_FIFO_BL7", 0xCF},
-};
-#endif /* HFC_REGISTER_DEBUG */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * For License see notice in hfc_multi.c
- *
- * special IO and init functions for the embedded XHFC board
- * from Speech Design
- *
- */
-
-#include <asm/cpm1.h>
-
-/* Change this to the value used by your board */
-#ifndef IMAP_ADDR
-#define IMAP_ADDR 0xFFF00000
-#endif
-
-static void
-#ifdef HFC_REGISTER_DEBUG
-HFC_outb_embsd(struct hfc_multi *hc, u_char reg, u_char val,
- const char *function, int line)
-#else
- HFC_outb_embsd(struct hfc_multi *hc, u_char reg, u_char val)
-#endif
-{
- hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
- writeb(reg, hc->xhfc_memaddr);
- hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
- writeb(val, hc->xhfc_memdata);
-}
-static u_char
-#ifdef HFC_REGISTER_DEBUG
-HFC_inb_embsd(struct hfc_multi *hc, u_char reg, const char *function, int line)
-#else
- HFC_inb_embsd(struct hfc_multi *hc, u_char reg)
-#endif
-{
- hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
- writeb(reg, hc->xhfc_memaddr);
- hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
- return readb(hc->xhfc_memdata);
-}
-static u_short
-#ifdef HFC_REGISTER_DEBUG
-HFC_inw_embsd(struct hfc_multi *hc, u_char reg, const char *function, int line)
-#else
- HFC_inw_embsd(struct hfc_multi *hc, u_char reg)
-#endif
-{
- hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
- writeb(reg, hc->xhfc_memaddr);
- hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
- return readb(hc->xhfc_memdata);
-}
-static void
-#ifdef HFC_REGISTER_DEBUG
-HFC_wait_embsd(struct hfc_multi *hc, const char *function, int line)
-#else
- HFC_wait_embsd(struct hfc_multi *hc)
-#endif
-{
- hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
- writeb(R_STATUS, hc->xhfc_memaddr);
- hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
- while (readb(hc->xhfc_memdata) & V_BUSY)
- cpu_relax();
-}
-
-/* write fifo data (EMBSD) */
-void
-write_fifo_embsd(struct hfc_multi *hc, u_char *data, int len)
-{
- hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
- *hc->xhfc_memaddr = A_FIFO_DATA0;
- hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
- while (len) {
- *hc->xhfc_memdata = *data;
- data++;
- len--;
- }
-}
-
-/* read fifo data (EMBSD) */
-void
-read_fifo_embsd(struct hfc_multi *hc, u_char *data, int len)
-{
- hc->immap->im_ioport.iop_padat |= PA_XHFC_A0;
- *hc->xhfc_memaddr = A_FIFO_DATA0;
- hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0);
- while (len) {
- *data = (u_char)(*hc->xhfc_memdata);
- data++;
- len--;
- }
-}
-
-static int
-setup_embedded(struct hfc_multi *hc, struct hm_map *m)
-{
- printk(KERN_INFO
- "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n",
- m->vendor_name, m->card_name, m->clock2 ? "double" : "normal");
-
- hc->pci_dev = NULL;
- if (m->clock2)
- test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip);
-
- hc->leds = m->leds;
- hc->ledstate = 0xAFFEAFFE;
- hc->opticalsupport = m->opticalsupport;
-
- hc->pci_iobase = 0;
- hc->pci_membase = 0;
- hc->xhfc_membase = NULL;
- hc->xhfc_memaddr = NULL;
- hc->xhfc_memdata = NULL;
-
- /* set memory access methods */
- if (m->io_mode) /* use mode from card config */
- hc->io_mode = m->io_mode;
- switch (hc->io_mode) {
- case HFC_IO_MODE_EMBSD:
- test_and_set_bit(HFC_CHIP_EMBSD, &hc->chip);
- hc->slots = 128; /* required */
- hc->HFC_outb = HFC_outb_embsd;
- hc->HFC_inb = HFC_inb_embsd;
- hc->HFC_inw = HFC_inw_embsd;
- hc->HFC_wait = HFC_wait_embsd;
- hc->read_fifo = read_fifo_embsd;
- hc->write_fifo = write_fifo_embsd;
- hc->xhfc_origmembase = XHFC_MEMBASE + XHFC_OFFSET * hc->id;
- hc->xhfc_membase = (u_char *)ioremap(hc->xhfc_origmembase,
- XHFC_MEMSIZE);
- if (!hc->xhfc_membase) {
- printk(KERN_WARNING
- "HFC-multi: failed to remap xhfc address space. "
- "(internal error)\n");
- return -EIO;
- }
- hc->xhfc_memaddr = (u_long *)(hc->xhfc_membase + 4);
- hc->xhfc_memdata = (u_long *)(hc->xhfc_membase);
- printk(KERN_INFO
- "HFC-multi: xhfc_membase:%#lx xhfc_origmembase:%#lx "
- "xhfc_memaddr:%#lx xhfc_memdata:%#lx\n",
- (u_long)hc->xhfc_membase, hc->xhfc_origmembase,
- (u_long)hc->xhfc_memaddr, (u_long)hc->xhfc_memdata);
- break;
- default:
- printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n");
- return -EIO;
- }
-
- /* Prepare the MPC8XX PortA 10 as output (address/data selector) */
- hc->immap = (struct immap *)(IMAP_ADDR);
- hc->immap->im_ioport.iop_papar &= ~(PA_XHFC_A0);
- hc->immap->im_ioport.iop_paodr &= ~(PA_XHFC_A0);
- hc->immap->im_ioport.iop_padir |= PA_XHFC_A0;
-
- /* Prepare the MPC8xx PortB __X__ as input (ISDN__X__IRQ) */
- hc->pb_irqmsk = (PB_XHFC_IRQ1 << hc->id);
- hc->immap->im_cpm.cp_pbpar &= ~(hc->pb_irqmsk);
- hc->immap->im_cpm.cp_pbodr &= ~(hc->pb_irqmsk);
- hc->immap->im_cpm.cp_pbdir &= ~(hc->pb_irqmsk);
-
- /* At this point the needed config is done */
- /* fifos are still not enabled */
- return 0;
-}
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * specific defines for CCD's HFC 2BDS0 PCI chips
- *
- * Author Werner Cornelius (werner@isdn4linux.de)
- *
- * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
- */
-
-/*
- * thresholds for transparent B-channel mode
- * change mask and threshold simultaneously
- */
-#define HFCPCI_BTRANS_THRESHOLD 128
-#define HFCPCI_FILLEMPTY 64
-#define HFCPCI_BTRANS_THRESMASK 0x00
-
-/* defines for PCI config */
-#define PCI_ENA_MEMIO 0x02
-#define PCI_ENA_MASTER 0x04
-
-/* GCI/IOM bus monitor registers */
-#define HCFPCI_C_I 0x08
-#define HFCPCI_TRxR 0x0C
-#define HFCPCI_MON1_D 0x28
-#define HFCPCI_MON2_D 0x2C
-
-/* GCI/IOM bus timeslot registers */
-#define HFCPCI_B1_SSL 0x80
-#define HFCPCI_B2_SSL 0x84
-#define HFCPCI_AUX1_SSL 0x88
-#define HFCPCI_AUX2_SSL 0x8C
-#define HFCPCI_B1_RSL 0x90
-#define HFCPCI_B2_RSL 0x94
-#define HFCPCI_AUX1_RSL 0x98
-#define HFCPCI_AUX2_RSL 0x9C
-
-/* GCI/IOM bus data registers */
-#define HFCPCI_B1_D 0xA0
-#define HFCPCI_B2_D 0xA4
-#define HFCPCI_AUX1_D 0xA8
-#define HFCPCI_AUX2_D 0xAC
-
-/* GCI/IOM bus configuration registers */
-#define HFCPCI_MST_EMOD 0xB4
-#define HFCPCI_MST_MODE 0xB8
-#define HFCPCI_CONNECT 0xBC
-
-
-/* Interrupt and status registers */
-#define HFCPCI_FIFO_EN 0x44
-#define HFCPCI_TRM 0x48
-#define HFCPCI_B_MODE 0x4C
-#define HFCPCI_CHIP_ID 0x58
-#define HFCPCI_CIRM 0x60
-#define HFCPCI_CTMT 0x64
-#define HFCPCI_INT_M1 0x68
-#define HFCPCI_INT_M2 0x6C
-#define HFCPCI_INT_S1 0x78
-#define HFCPCI_INT_S2 0x7C
-#define HFCPCI_STATUS 0x70
-
-/* S/T section registers */
-#define HFCPCI_STATES 0xC0
-#define HFCPCI_SCTRL 0xC4
-#define HFCPCI_SCTRL_E 0xC8
-#define HFCPCI_SCTRL_R 0xCC
-#define HFCPCI_SQ 0xD0
-#define HFCPCI_CLKDEL 0xDC
-#define HFCPCI_B1_REC 0xF0
-#define HFCPCI_B1_SEND 0xF0
-#define HFCPCI_B2_REC 0xF4
-#define HFCPCI_B2_SEND 0xF4
-#define HFCPCI_D_REC 0xF8
-#define HFCPCI_D_SEND 0xF8
-#define HFCPCI_E_REC 0xFC
-
-
-/* bits in status register (READ) */
-#define HFCPCI_PCI_PROC 0x02
-#define HFCPCI_NBUSY 0x04
-#define HFCPCI_TIMER_ELAP 0x10
-#define HFCPCI_STATINT 0x20
-#define HFCPCI_FRAMEINT 0x40
-#define HFCPCI_ANYINT 0x80
-
-/* bits in CTMT (Write) */
-#define HFCPCI_CLTIMER 0x80
-#define HFCPCI_TIM3_125 0x04
-#define HFCPCI_TIM25 0x10
-#define HFCPCI_TIM50 0x14
-#define HFCPCI_TIM400 0x18
-#define HFCPCI_TIM800 0x1C
-#define HFCPCI_AUTO_TIMER 0x20
-#define HFCPCI_TRANSB2 0x02
-#define HFCPCI_TRANSB1 0x01
-
-/* bits in CIRM (Write) */
-#define HFCPCI_AUX_MSK 0x07
-#define HFCPCI_RESET 0x08
-#define HFCPCI_B1_REV 0x40
-#define HFCPCI_B2_REV 0x80
-
-/* bits in INT_M1 and INT_S1 */
-#define HFCPCI_INTS_B1TRANS 0x01
-#define HFCPCI_INTS_B2TRANS 0x02
-#define HFCPCI_INTS_DTRANS 0x04
-#define HFCPCI_INTS_B1REC 0x08
-#define HFCPCI_INTS_B2REC 0x10
-#define HFCPCI_INTS_DREC 0x20
-#define HFCPCI_INTS_L1STATE 0x40
-#define HFCPCI_INTS_TIMER 0x80
-
-/* bits in INT_M2 */
-#define HFCPCI_PROC_TRANS 0x01
-#define HFCPCI_GCI_I_CHG 0x02
-#define HFCPCI_GCI_MON_REC 0x04
-#define HFCPCI_IRQ_ENABLE 0x08
-#define HFCPCI_PMESEL 0x80
-
-/* bits in STATES */
-#define HFCPCI_STATE_MSK 0x0F
-#define HFCPCI_LOAD_STATE 0x10
-#define HFCPCI_ACTIVATE 0x20
-#define HFCPCI_DO_ACTION 0x40
-#define HFCPCI_NT_G2_G3 0x80
-
-/* bits in HFCD_MST_MODE */
-#define HFCPCI_MASTER 0x01
-#define HFCPCI_SLAVE 0x00
-#define HFCPCI_F0IO_POSITIV 0x02
-#define HFCPCI_F0_NEGATIV 0x04
-#define HFCPCI_F0_2C4 0x08
-/* remaining bits are for codecs control */
-
-/* bits in HFCD_SCTRL */
-#define SCTRL_B1_ENA 0x01
-#define SCTRL_B2_ENA 0x02
-#define SCTRL_MODE_TE 0x00
-#define SCTRL_MODE_NT 0x04
-#define SCTRL_LOW_PRIO 0x08
-#define SCTRL_SQ_ENA 0x10
-#define SCTRL_TEST 0x20
-#define SCTRL_NONE_CAP 0x40
-#define SCTRL_PWR_DOWN 0x80
-
-/* bits in SCTRL_E */
-#define HFCPCI_AUTO_AWAKE 0x01
-#define HFCPCI_DBIT_1 0x04
-#define HFCPCI_IGNORE_COL 0x08
-#define HFCPCI_CHG_B1_B2 0x80
-
-/* bits in FIFO_EN register */
-#define HFCPCI_FIFOEN_B1 0x03
-#define HFCPCI_FIFOEN_B2 0x0C
-#define HFCPCI_FIFOEN_DTX 0x10
-#define HFCPCI_FIFOEN_B1TX 0x01
-#define HFCPCI_FIFOEN_B1RX 0x02
-#define HFCPCI_FIFOEN_B2TX 0x04
-#define HFCPCI_FIFOEN_B2RX 0x08
-
-
-/* definitions of fifo memory area */
-#define MAX_D_FRAMES 15
-#define MAX_B_FRAMES 31
-#define B_SUB_VAL 0x200
-#define B_FIFO_SIZE (0x2000 - B_SUB_VAL)
-#define D_FIFO_SIZE 512
-#define D_FREG_MASK 0xF
-
-struct zt {
- __le16 z1; /* Z1 pointer 16 Bit */
- __le16 z2; /* Z2 pointer 16 Bit */
-};
-
-struct dfifo {
- u_char data[D_FIFO_SIZE]; /* FIFO data space */
- u_char fill1[0x20A0 - D_FIFO_SIZE]; /* reserved, do not use */
- u_char f1, f2; /* f pointers */
- u_char fill2[0x20C0 - 0x20A2]; /* reserved, do not use */
- /* mask index with D_FREG_MASK for access */
- struct zt za[MAX_D_FRAMES + 1];
- u_char fill3[0x4000 - 0x2100]; /* align 16K */
-};
-
-struct bzfifo {
- struct zt za[MAX_B_FRAMES + 1]; /* only range 0x0..0x1F allowed */
- u_char f1, f2; /* f pointers */
- u_char fill[0x2100 - 0x2082]; /* alignment */
-};
-
-
-union fifo_area {
- struct {
- struct dfifo d_tx; /* D-send channel */
- struct dfifo d_rx; /* D-receive channel */
- } d_chan;
- struct {
- u_char fill1[0x200];
- u_char txdat_b1[B_FIFO_SIZE];
- struct bzfifo txbz_b1;
- struct bzfifo txbz_b2;
- u_char txdat_b2[B_FIFO_SIZE];
- u_char fill2[D_FIFO_SIZE];
- u_char rxdat_b1[B_FIFO_SIZE];
- struct bzfifo rxbz_b1;
- struct bzfifo rxbz_b2;
- u_char rxdat_b2[B_FIFO_SIZE];
- } b_chans;
- u_char fill[32768];
-};
-
-#define Write_hfc(a, b, c) (writeb(c, (a->hw.pci_io) + b))
-#define Read_hfc(a, b) (readb((a->hw.pci_io) + b))
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * hfcmulti.c low level driver for hfc-4s/hfc-8s/hfc-e1 based cards
- *
- * Author Andreas Eversberg (jolly@eversberg.eu)
- * ported to mqueue mechanism:
- * Peter Sprenger (sprengermoving-bytes.de)
- *
- * inspired by existing hfc-pci driver:
- * Copyright 1999 by Werner Cornelius (werner@isdn-development.de)
- * Copyright 2008 by Karsten Keil (kkeil@suse.de)
- * Copyright 2008 by Andreas Eversberg (jolly@eversberg.eu)
- *
- * Thanks to Cologne Chip AG for this great controller!
- */
-
-/*
- * module parameters:
- * type:
- * By default (0), the card is automatically detected.
- * Or use the following combinations:
- * Bit 0-7 = 0x00001 = HFC-E1 (1 port)
- * or Bit 0-7 = 0x00004 = HFC-4S (4 ports)
- * or Bit 0-7 = 0x00008 = HFC-8S (8 ports)
- * Bit 8 = 0x00100 = uLaw (instead of aLaw)
- * Bit 9 = 0x00200 = Disable DTMF detect on all B-channels via hardware
- * Bit 10 = spare
- * Bit 11 = 0x00800 = Force PCM bus into slave mode. (otherwise auto)
- * or Bit 12 = 0x01000 = Force PCM bus into master mode. (otherwise auto)
- * Bit 13 = spare
- * Bit 14 = 0x04000 = Use external ram (128K)
- * Bit 15 = 0x08000 = Use external ram (512K)
- * Bit 16 = 0x10000 = Use 64 timeslots instead of 32
- * or Bit 17 = 0x20000 = Use 128 timeslots instead of anything else
- * Bit 18 = spare
- * Bit 19 = 0x80000 = Send the Watchdog a Signal (Dual E1 with Watchdog)
- * (all other bits are reserved and shall be 0)
- * example: 0x20204 one HFC-4S with dtmf detection and 128 timeslots on PCM
- * bus (PCM master)
- *
- * port: (optional or required for all ports on all installed cards)
- * HFC-4S/HFC-8S only bits:
- * Bit 0 = 0x001 = Use master clock for this S/T interface
- * (only once per chip).
- * Bit 1 = 0x002 = transmitter line setup (non capacitive mode)
- * Don't use this unless you know what you are doing!
- * Bit 2 = 0x004 = Disable E-channel. (No E-channel processing)
- * example: 0x0001,0x0000,0x0000,0x0000 one HFC-4S with master clock
- * received from port 1
- *
- * HFC-E1 only bits:
- * Bit 0 = 0x0001 = interface: 0=copper, 1=optical
- * Bit 1 = 0x0002 = reserved (later for 32 B-channels transparent mode)
- * Bit 2 = 0x0004 = Report LOS
- * Bit 3 = 0x0008 = Report AIS
- * Bit 4 = 0x0010 = Report SLIP
- * Bit 5 = 0x0020 = Report RDI
- * Bit 8 = 0x0100 = Turn off CRC-4 Multiframe Mode, use double frame
- * mode instead.
- * Bit 9 = 0x0200 = Force get clock from interface, even in NT mode.
- * or Bit 10 = 0x0400 = Force put clock to interface, even in TE mode.
- * Bit 11 = 0x0800 = Use direct RX clock for PCM sync rather than PLL.
- * (E1 only)
- * Bit 12-13 = 0xX000 = elastic jitter buffer (1-3), Set both bits to 0
- * for default.
- * (all other bits are reserved and shall be 0)
- *
- * debug:
- * NOTE: only one debug value must be given for all cards
- * enable debugging (see hfc_multi.h for debug options)
- *
- * poll:
- * NOTE: only one poll value must be given for all cards
- * Give the number of samples for each fifo process.
- * By default 128 is used. Decrease to reduce delay, increase to
- * reduce cpu load. If unsure, don't mess with it!
- * Valid is 8, 16, 32, 64, 128, 256.
- *
- * pcm:
- * NOTE: only one pcm value must be given for every card.
- * The PCM bus id tells the mISDNdsp module about the connected PCM bus.
- * By default (0), the PCM bus id is 100 for the card that is PCM master.
- * If multiple cards are PCM master (because they are not interconnected),
- * each card with PCM master will have increasing PCM id.
- * All PCM buses with the same ID are expected to be connected and have
- * common time slots slots.
- * Only one chip of the PCM bus must be master, the others slave.
- * -1 means no support of PCM bus not even.
- * Omit this value, if all cards are interconnected or none is connected.
- * If unsure, don't give this parameter.
- *
- * dmask and bmask:
- * NOTE: One dmask value must be given for every HFC-E1 card.
- * If omitted, the E1 card has D-channel on time slot 16, which is default.
- * dmask is a 32 bit mask. The bit must be set for an alternate time slot.
- * If multiple bits are set, multiple virtual card fragments are created.
- * For each bit set, a bmask value must be given. Each bit on the bmask
- * value stands for a B-channel. The bmask may not overlap with dmask or
- * with other bmask values for that card.
- * Example: dmask=0x00020002 bmask=0x0000fffc,0xfffc0000
- * This will create one fragment with D-channel on slot 1 with
- * B-channels on slots 2..15, and a second fragment with D-channel
- * on slot 17 with B-channels on slot 18..31. Slot 16 is unused.
- * If bit 0 is set (dmask=0x00000001) the D-channel is on slot 0 and will
- * not function.
- * Example: dmask=0x00000001 bmask=0xfffffffe
- * This will create a port with all 31 usable timeslots as
- * B-channels.
- * If no bits are set on bmask, no B-channel is created for that fragment.
- * Example: dmask=0xfffffffe bmask=0,0,0,0.... (31 0-values for bmask)
- * This will create 31 ports with one D-channel only.
- * If you don't know how to use it, you don't need it!
- *
- * iomode:
- * NOTE: only one mode value must be given for every card.
- * -> See hfc_multi.h for HFC_IO_MODE_* values
- * By default, the IO mode is pci memory IO (MEMIO).
- * Some cards require specific IO mode, so it cannot be changed.
- * It may be useful to set IO mode to register io (REGIO) to solve
- * PCI bridge problems.
- * If unsure, don't give this parameter.
- *
- * clockdelay_nt:
- * NOTE: only one clockdelay_nt value must be given once for all cards.
- * Give the value of the clock control register (A_ST_CLK_DLY)
- * of the S/T interfaces in NT mode.
- * This register is needed for the TBR3 certification, so don't change it.
- *
- * clockdelay_te:
- * NOTE: only one clockdelay_te value must be given once
- * Give the value of the clock control register (A_ST_CLK_DLY)
- * of the S/T interfaces in TE mode.
- * This register is needed for the TBR3 certification, so don't change it.
- *
- * clock:
- * NOTE: only one clock value must be given once
- * Selects interface with clock source for mISDN and applications.
- * Set to card number starting with 1. Set to -1 to disable.
- * By default, the first card is used as clock source.
- *
- * hwid:
- * NOTE: only one hwid value must be given once
- * Enable special embedded devices with XHFC controllers.
- */
-
-/*
- * debug register access (never use this, it will flood your system log)
- * #define HFC_REGISTER_DEBUG
- */
-
-#define HFC_MULTI_VERSION "2.03"
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/mISDNhw.h>
-#include <linux/mISDNdsp.h>
-
-/*
- #define IRQCOUNT_DEBUG
- #define IRQ_DEBUG
-*/
-
-#include "hfc_multi.h"
-#ifdef ECHOPREP
-#include "gaintab.h"
-#endif
-
-#define MAX_CARDS 8
-#define MAX_PORTS (8 * MAX_CARDS)
-#define MAX_FRAGS (32 * MAX_CARDS)
-
-static LIST_HEAD(HFClist);
-static DEFINE_SPINLOCK(HFClock); /* global hfc list lock */
-
-static void ph_state_change(struct dchannel *);
-
-static struct hfc_multi *syncmaster;
-static int plxsd_master; /* if we have a master card (yet) */
-static DEFINE_SPINLOCK(plx_lock); /* may not acquire other lock inside */
-
-#define TYP_E1 1
-#define TYP_4S 4
-#define TYP_8S 8
-
-static int poll_timer = 6; /* default = 128 samples = 16ms */
-/* number of POLL_TIMER interrupts for G2 timeout (ca 1s) */
-static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 };
-#define CLKDEL_TE 0x0f /* CLKDEL in TE mode */
-#define CLKDEL_NT 0x6c /* CLKDEL in NT mode
- (0x60 MUST be included!) */
-
-#define DIP_4S 0x1 /* DIP Switches for Beronet 1S/2S/4S cards */
-#define DIP_8S 0x2 /* DIP Switches for Beronet 8S+ cards */
-#define DIP_E1 0x3 /* DIP Switches for Beronet E1 cards */
-
-/*
- * module stuff
- */
-
-static uint type[MAX_CARDS];
-static int pcm[MAX_CARDS];
-static uint dmask[MAX_CARDS];
-static uint bmask[MAX_FRAGS];
-static uint iomode[MAX_CARDS];
-static uint port[MAX_PORTS];
-static uint debug;
-static uint poll;
-static int clock;
-static uint timer;
-static uint clockdelay_te = CLKDEL_TE;
-static uint clockdelay_nt = CLKDEL_NT;
-#define HWID_NONE 0
-#define HWID_MINIP4 1
-#define HWID_MINIP8 2
-#define HWID_MINIP16 3
-static uint hwid = HWID_NONE;
-
-static int HFC_cnt, E1_cnt, bmask_cnt, Port_cnt, PCM_cnt = 99;
-
-MODULE_AUTHOR("Andreas Eversberg");
-MODULE_DESCRIPTION("mISDN driver for hfc-4s/hfc-8s/hfc-e1 based cards");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(HFC_MULTI_VERSION);
-module_param(debug, uint, S_IRUGO | S_IWUSR);
-module_param(poll, uint, S_IRUGO | S_IWUSR);
-module_param(clock, int, S_IRUGO | S_IWUSR);
-module_param(timer, uint, S_IRUGO | S_IWUSR);
-module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR);
-module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR);
-module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(dmask, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(bmask, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR);
-module_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */
-
-#ifdef HFC_REGISTER_DEBUG
-#define HFC_outb(hc, reg, val) \
- (hc->HFC_outb(hc, reg, val, __func__, __LINE__))
-#define HFC_outb_nodebug(hc, reg, val) \
- (hc->HFC_outb_nodebug(hc, reg, val, __func__, __LINE__))
-#define HFC_inb(hc, reg) \
- (hc->HFC_inb(hc, reg, __func__, __LINE__))
-#define HFC_inb_nodebug(hc, reg) \
- (hc->HFC_inb_nodebug(hc, reg, __func__, __LINE__))
-#define HFC_inw(hc, reg) \
- (hc->HFC_inw(hc, reg, __func__, __LINE__))
-#define HFC_inw_nodebug(hc, reg) \
- (hc->HFC_inw_nodebug(hc, reg, __func__, __LINE__))
-#define HFC_wait(hc) \
- (hc->HFC_wait(hc, __func__, __LINE__))
-#define HFC_wait_nodebug(hc) \
- (hc->HFC_wait_nodebug(hc, __func__, __LINE__))
-#else
-#define HFC_outb(hc, reg, val) (hc->HFC_outb(hc, reg, val))
-#define HFC_outb_nodebug(hc, reg, val) (hc->HFC_outb_nodebug(hc, reg, val))
-#define HFC_inb(hc, reg) (hc->HFC_inb(hc, reg))
-#define HFC_inb_nodebug(hc, reg) (hc->HFC_inb_nodebug(hc, reg))
-#define HFC_inw(hc, reg) (hc->HFC_inw(hc, reg))
-#define HFC_inw_nodebug(hc, reg) (hc->HFC_inw_nodebug(hc, reg))
-#define HFC_wait(hc) (hc->HFC_wait(hc))
-#define HFC_wait_nodebug(hc) (hc->HFC_wait_nodebug(hc))
-#endif
-
-#ifdef CONFIG_MISDN_HFCMULTI_8xx
-#include "hfc_multi_8xx.h"
-#endif
-
-/* HFC_IO_MODE_PCIMEM */
-static void
-#ifdef HFC_REGISTER_DEBUG
-HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val,
- const char *function, int line)
-#else
- HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val)
-#endif
-{
- writeb(val, hc->pci_membase + reg);
-}
-static u_char
-#ifdef HFC_REGISTER_DEBUG
-HFC_inb_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line)
-#else
- HFC_inb_pcimem(struct hfc_multi *hc, u_char reg)
-#endif
-{
- return readb(hc->pci_membase + reg);
-}
-static u_short
-#ifdef HFC_REGISTER_DEBUG
-HFC_inw_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line)
-#else
- HFC_inw_pcimem(struct hfc_multi *hc, u_char reg)
-#endif
-{
- return readw(hc->pci_membase + reg);
-}
-static void
-#ifdef HFC_REGISTER_DEBUG
-HFC_wait_pcimem(struct hfc_multi *hc, const char *function, int line)
-#else
- HFC_wait_pcimem(struct hfc_multi *hc)
-#endif
-{
- while (readb(hc->pci_membase + R_STATUS) & V_BUSY)
- cpu_relax();
-}
-
-/* HFC_IO_MODE_REGIO */
-static void
-#ifdef HFC_REGISTER_DEBUG
-HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val,
- const char *function, int line)
-#else
- HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val)
-#endif
-{
- outb(reg, hc->pci_iobase + 4);
- outb(val, hc->pci_iobase);
-}
-static u_char
-#ifdef HFC_REGISTER_DEBUG
-HFC_inb_regio(struct hfc_multi *hc, u_char reg, const char *function, int line)
-#else
- HFC_inb_regio(struct hfc_multi *hc, u_char reg)
-#endif
-{
- outb(reg, hc->pci_iobase + 4);
- return inb(hc->pci_iobase);
-}
-static u_short
-#ifdef HFC_REGISTER_DEBUG
-HFC_inw_regio(struct hfc_multi *hc, u_char reg, const char *function, int line)
-#else
- HFC_inw_regio(struct hfc_multi *hc, u_char reg)
-#endif
-{
- outb(reg, hc->pci_iobase + 4);
- return inw(hc->pci_iobase);
-}
-static void
-#ifdef HFC_REGISTER_DEBUG
-HFC_wait_regio(struct hfc_multi *hc, const char *function, int line)
-#else
- HFC_wait_regio(struct hfc_multi *hc)
-#endif
-{
- outb(R_STATUS, hc->pci_iobase + 4);
- while (inb(hc->pci_iobase) & V_BUSY)
- cpu_relax();
-}
-
-#ifdef HFC_REGISTER_DEBUG
-static void
-HFC_outb_debug(struct hfc_multi *hc, u_char reg, u_char val,
- const char *function, int line)
-{
- char regname[256] = "", bits[9] = "xxxxxxxx";
- int i;
-
- i = -1;
- while (hfc_register_names[++i].name) {
- if (hfc_register_names[i].reg == reg)
- strcat(regname, hfc_register_names[i].name);
- }
- if (regname[0] == '\0')
- strcpy(regname, "register");
-
- bits[7] = '0' + (!!(val & 1));
- bits[6] = '0' + (!!(val & 2));
- bits[5] = '0' + (!!(val & 4));
- bits[4] = '0' + (!!(val & 8));
- bits[3] = '0' + (!!(val & 16));
- bits[2] = '0' + (!!(val & 32));
- bits[1] = '0' + (!!(val & 64));
- bits[0] = '0' + (!!(val & 128));
- printk(KERN_DEBUG
- "HFC_outb(chip %d, %02x=%s, 0x%02x=%s); in %s() line %d\n",
- hc->id, reg, regname, val, bits, function, line);
- HFC_outb_nodebug(hc, reg, val);
-}
-static u_char
-HFC_inb_debug(struct hfc_multi *hc, u_char reg, const char *function, int line)
-{
- char regname[256] = "", bits[9] = "xxxxxxxx";
- u_char val = HFC_inb_nodebug(hc, reg);
- int i;
-
- i = 0;
- while (hfc_register_names[i++].name)
- ;
- while (hfc_register_names[++i].name) {
- if (hfc_register_names[i].reg == reg)
- strcat(regname, hfc_register_names[i].name);
- }
- if (regname[0] == '\0')
- strcpy(regname, "register");
-
- bits[7] = '0' + (!!(val & 1));
- bits[6] = '0' + (!!(val & 2));
- bits[5] = '0' + (!!(val & 4));
- bits[4] = '0' + (!!(val & 8));
- bits[3] = '0' + (!!(val & 16));
- bits[2] = '0' + (!!(val & 32));
- bits[1] = '0' + (!!(val & 64));
- bits[0] = '0' + (!!(val & 128));
- printk(KERN_DEBUG
- "HFC_inb(chip %d, %02x=%s) = 0x%02x=%s; in %s() line %d\n",
- hc->id, reg, regname, val, bits, function, line);
- return val;
-}
-static u_short
-HFC_inw_debug(struct hfc_multi *hc, u_char reg, const char *function, int line)
-{
- char regname[256] = "";
- u_short val = HFC_inw_nodebug(hc, reg);
- int i;
-
- i = 0;
- while (hfc_register_names[i++].name)
- ;
- while (hfc_register_names[++i].name) {
- if (hfc_register_names[i].reg == reg)
- strcat(regname, hfc_register_names[i].name);
- }
- if (regname[0] == '\0')
- strcpy(regname, "register");
-
- printk(KERN_DEBUG
- "HFC_inw(chip %d, %02x=%s) = 0x%04x; in %s() line %d\n",
- hc->id, reg, regname, val, function, line);
- return val;
-}
-static void
-HFC_wait_debug(struct hfc_multi *hc, const char *function, int line)
-{
- printk(KERN_DEBUG "HFC_wait(chip %d); in %s() line %d\n",
- hc->id, function, line);
- HFC_wait_nodebug(hc);
-}
-#endif
-
-/* write fifo data (REGIO) */
-static void
-write_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
-{
- outb(A_FIFO_DATA0, (hc->pci_iobase) + 4);
- while (len >> 2) {
- outl(cpu_to_le32(*(u32 *)data), hc->pci_iobase);
- data += 4;
- len -= 4;
- }
- while (len >> 1) {
- outw(cpu_to_le16(*(u16 *)data), hc->pci_iobase);
- data += 2;
- len -= 2;
- }
- while (len) {
- outb(*data, hc->pci_iobase);
- data++;
- len--;
- }
-}
-/* write fifo data (PCIMEM) */
-static void
-write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len)
-{
- while (len >> 2) {
- writel(cpu_to_le32(*(u32 *)data),
- hc->pci_membase + A_FIFO_DATA0);
- data += 4;
- len -= 4;
- }
- while (len >> 1) {
- writew(cpu_to_le16(*(u16 *)data),
- hc->pci_membase + A_FIFO_DATA0);
- data += 2;
- len -= 2;
- }
- while (len) {
- writeb(*data, hc->pci_membase + A_FIFO_DATA0);
- data++;
- len--;
- }
-}
-
-/* read fifo data (REGIO) */
-static void
-read_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
-{
- outb(A_FIFO_DATA0, (hc->pci_iobase) + 4);
- while (len >> 2) {
- *(u32 *)data = le32_to_cpu(inl(hc->pci_iobase));
- data += 4;
- len -= 4;
- }
- while (len >> 1) {
- *(u16 *)data = le16_to_cpu(inw(hc->pci_iobase));
- data += 2;
- len -= 2;
- }
- while (len) {
- *data = inb(hc->pci_iobase);
- data++;
- len--;
- }
-}
-
-/* read fifo data (PCIMEM) */
-static void
-read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len)
-{
- while (len >> 2) {
- *(u32 *)data =
- le32_to_cpu(readl(hc->pci_membase + A_FIFO_DATA0));
- data += 4;
- len -= 4;
- }
- while (len >> 1) {
- *(u16 *)data =
- le16_to_cpu(readw(hc->pci_membase + A_FIFO_DATA0));
- data += 2;
- len -= 2;
- }
- while (len) {
- *data = readb(hc->pci_membase + A_FIFO_DATA0);
- data++;
- len--;
- }
-}
-
-static void
-enable_hwirq(struct hfc_multi *hc)
-{
- hc->hw.r_irq_ctrl |= V_GLOB_IRQ_EN;
- HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl);
-}
-
-static void
-disable_hwirq(struct hfc_multi *hc)
-{
- hc->hw.r_irq_ctrl &= ~((u_char)V_GLOB_IRQ_EN);
- HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl);
-}
-
-#define NUM_EC 2
-#define MAX_TDM_CHAN 32
-
-
-static inline void
-enablepcibridge(struct hfc_multi *c)
-{
- HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); /* was _io before */
-}
-
-static inline void
-disablepcibridge(struct hfc_multi *c)
-{
- HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x2); /* was _io before */
-}
-
-static inline unsigned char
-readpcibridge(struct hfc_multi *hc, unsigned char address)
-{
- unsigned short cipv;
- unsigned char data;
-
- if (!hc->pci_iobase)
- return 0;
-
- /* slow down a PCI read access by 1 PCI clock cycle */
- HFC_outb(hc, R_CTRL, 0x4); /*was _io before*/
-
- if (address == 0)
- cipv = 0x4000;
- else
- cipv = 0x5800;
-
- /* select local bridge port address by writing to CIP port */
- /* data = HFC_inb(c, cipv); * was _io before */
- outw(cipv, hc->pci_iobase + 4);
- data = inb(hc->pci_iobase);
-
- /* restore R_CTRL for normal PCI read cycle speed */
- HFC_outb(hc, R_CTRL, 0x0); /* was _io before */
-
- return data;
-}
-
-static inline void
-writepcibridge(struct hfc_multi *hc, unsigned char address, unsigned char data)
-{
- unsigned short cipv;
- unsigned int datav;
-
- if (!hc->pci_iobase)
- return;
-
- if (address == 0)
- cipv = 0x4000;
- else
- cipv = 0x5800;
-
- /* select local bridge port address by writing to CIP port */
- outw(cipv, hc->pci_iobase + 4);
- /* define a 32 bit dword with 4 identical bytes for write sequence */
- datav = data | ((__u32) data << 8) | ((__u32) data << 16) |
- ((__u32) data << 24);
-
- /*
- * write this 32 bit dword to the bridge data port
- * this will initiate a write sequence of up to 4 writes to the same
- * address on the local bus interface the number of write accesses
- * is undefined but >=1 and depends on the next PCI transaction
- * during write sequence on the local bus
- */
- outl(datav, hc->pci_iobase);
-}
-
-static inline void
-cpld_set_reg(struct hfc_multi *hc, unsigned char reg)
-{
- /* Do data pin read low byte */
- HFC_outb(hc, R_GPIO_OUT1, reg);
-}
-
-static inline void
-cpld_write_reg(struct hfc_multi *hc, unsigned char reg, unsigned char val)
-{
- cpld_set_reg(hc, reg);
-
- enablepcibridge(hc);
- writepcibridge(hc, 1, val);
- disablepcibridge(hc);
-
- return;
-}
-
-static inline void
-vpm_write_address(struct hfc_multi *hc, unsigned short addr)
-{
- cpld_write_reg(hc, 0, 0xff & addr);
- cpld_write_reg(hc, 1, 0x01 & (addr >> 8));
-}
-
-static inline unsigned char
-vpm_in(struct hfc_multi *c, int which, unsigned short addr)
-{
- unsigned char res;
-
- vpm_write_address(c, addr);
-
- if (!which)
- cpld_set_reg(c, 2);
- else
- cpld_set_reg(c, 3);
-
- enablepcibridge(c);
- res = readpcibridge(c, 1);
- disablepcibridge(c);
-
- cpld_set_reg(c, 0);
-
- return res;
-}
-
-static inline void
-vpm_out(struct hfc_multi *c, int which, unsigned short addr,
- unsigned char data)
-{
- vpm_write_address(c, addr);
-
- enablepcibridge(c);
-
- if (!which)
- cpld_set_reg(c, 2);
- else
- cpld_set_reg(c, 3);
-
- writepcibridge(c, 1, data);
-
- cpld_set_reg(c, 0);
-
- disablepcibridge(c);
-
- {
- unsigned char regin;
- regin = vpm_in(c, which, addr);
- if (regin != data)
- printk(KERN_DEBUG "Wrote 0x%x to register 0x%x but got back "
- "0x%x\n", data, addr, regin);
- }
-
-}
-
-
-static void
-vpm_init(struct hfc_multi *wc)
-{
- unsigned char reg;
- unsigned int mask;
- unsigned int i, x, y;
- unsigned int ver;
-
- for (x = 0; x < NUM_EC; x++) {
- /* Setup GPIO's */
- if (!x) {
- ver = vpm_in(wc, x, 0x1a0);
- printk(KERN_DEBUG "VPM: Chip %d: ver %02x\n", x, ver);
- }
-
- for (y = 0; y < 4; y++) {
- vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */
- vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */
- vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */
- }
-
- /* Setup TDM path - sets fsync and tdm_clk as inputs */
- reg = vpm_in(wc, x, 0x1a3); /* misc_con */
- vpm_out(wc, x, 0x1a3, reg & ~2);
-
- /* Setup Echo length (256 taps) */
- vpm_out(wc, x, 0x022, 1);
- vpm_out(wc, x, 0x023, 0xff);
-
- /* Setup timeslots */
- vpm_out(wc, x, 0x02f, 0x00);
- mask = 0x02020202 << (x * 4);
-
- /* Setup the tdm channel masks for all chips */
- for (i = 0; i < 4; i++)
- vpm_out(wc, x, 0x33 - i, (mask >> (i << 3)) & 0xff);
-
- /* Setup convergence rate */
- printk(KERN_DEBUG "VPM: A-law mode\n");
- reg = 0x00 | 0x10 | 0x01;
- vpm_out(wc, x, 0x20, reg);
- printk(KERN_DEBUG "VPM reg 0x20 is %x\n", reg);
- /*vpm_out(wc, x, 0x20, (0x00 | 0x08 | 0x20 | 0x10)); */
-
- vpm_out(wc, x, 0x24, 0x02);
- reg = vpm_in(wc, x, 0x24);
- printk(KERN_DEBUG "NLP Thresh is set to %d (0x%x)\n", reg, reg);
-
- /* Initialize echo cans */
- for (i = 0; i < MAX_TDM_CHAN; i++) {
- if (mask & (0x00000001 << i))
- vpm_out(wc, x, i, 0x00);
- }
-
- /*
- * ARM arch at least disallows a udelay of
- * more than 2ms... it gives a fake "__bad_udelay"
- * reference at link-time.
- * long delays in kernel code are pretty sucky anyway
- * for now work around it using 5 x 2ms instead of 1 x 10ms
- */
-
- udelay(2000);
- udelay(2000);
- udelay(2000);
- udelay(2000);
- udelay(2000);
-
- /* Put in bypass mode */
- for (i = 0; i < MAX_TDM_CHAN; i++) {
- if (mask & (0x00000001 << i))
- vpm_out(wc, x, i, 0x01);
- }
-
- /* Enable bypass */
- for (i = 0; i < MAX_TDM_CHAN; i++) {
- if (mask & (0x00000001 << i))
- vpm_out(wc, x, 0x78 + i, 0x01);
- }
-
- }
-}
-
-#ifdef UNUSED
-static void
-vpm_check(struct hfc_multi *hctmp)
-{
- unsigned char gpi2;
-
- gpi2 = HFC_inb(hctmp, R_GPI_IN2);
-
- if ((gpi2 & 0x3) != 0x3)
- printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2);
-}
-#endif /* UNUSED */
-
-
-/*
- * Interface to enable/disable the HW Echocan
- *
- * these functions are called within a spin_lock_irqsave on
- * the channel instance lock, so we are not disturbed by irqs
- *
- * we can later easily change the interface to make other
- * things configurable, for now we configure the taps
- *
- */
-
-static void
-vpm_echocan_on(struct hfc_multi *hc, int ch, int taps)
-{
- unsigned int timeslot;
- unsigned int unit;
- struct bchannel *bch = hc->chan[ch].bch;
-#ifdef TXADJ
- int txadj = -4;
- struct sk_buff *skb;
-#endif
- if (hc->chan[ch].protocol != ISDN_P_B_RAW)
- return;
-
- if (!bch)
- return;
-
-#ifdef TXADJ
- skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX,
- sizeof(int), &txadj, GFP_ATOMIC);
- if (skb)
- recv_Bchannel_skb(bch, skb);
-#endif
-
- timeslot = ((ch / 4) * 8) + ((ch % 4) * 4) + 1;
- unit = ch % 4;
-
- printk(KERN_NOTICE "vpm_echocan_on called taps [%d] on timeslot %d\n",
- taps, timeslot);
-
- vpm_out(hc, unit, timeslot, 0x7e);
-}
-
-static void
-vpm_echocan_off(struct hfc_multi *hc, int ch)
-{
- unsigned int timeslot;
- unsigned int unit;
- struct bchannel *bch = hc->chan[ch].bch;
-#ifdef TXADJ
- int txadj = 0;
- struct sk_buff *skb;
-#endif
-
- if (hc->chan[ch].protocol != ISDN_P_B_RAW)
- return;
-
- if (!bch)
- return;
-
-#ifdef TXADJ
- skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX,
- sizeof(int), &txadj, GFP_ATOMIC);
- if (skb)
- recv_Bchannel_skb(bch, skb);
-#endif
-
- timeslot = ((ch / 4) * 8) + ((ch % 4) * 4) + 1;
- unit = ch % 4;
-
- printk(KERN_NOTICE "vpm_echocan_off called on timeslot %d\n",
- timeslot);
- /* FILLME */
- vpm_out(hc, unit, timeslot, 0x01);
-}
-
-
-/*
- * Speech Design resync feature
- * NOTE: This is called sometimes outside interrupt handler.
- * We must lock irqsave, so no other interrupt (other card) will occur!
- * Also multiple interrupts may nest, so must lock each access (lists, card)!
- */
-static inline void
-hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm)
-{
- struct hfc_multi *hc, *next, *pcmmaster = NULL;
- void __iomem *plx_acc_32;
- u_int pv;
- u_long flags;
-
- spin_lock_irqsave(&HFClock, flags);
- spin_lock(&plx_lock); /* must be locked inside other locks */
-
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "%s: RESYNC(syncmaster=0x%p)\n",
- __func__, syncmaster);
-
- /* select new master */
- if (newmaster) {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "using provided controller\n");
- } else {
- list_for_each_entry_safe(hc, next, &HFClist, list) {
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- if (hc->syncronized) {
- newmaster = hc;
- break;
- }
- }
- }
- }
-
- /* Disable sync of all cards */
- list_for_each_entry_safe(hc, next, &HFClist, list) {
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- plx_acc_32 = hc->plx_membase + PLX_GPIOC;
- pv = readl(plx_acc_32);
- pv &= ~PLX_SYNC_O_EN;
- writel(pv, plx_acc_32);
- if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) {
- pcmmaster = hc;
- if (hc->ctype == HFC_TYPE_E1) {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG
- "Schedule SYNC_I\n");
- hc->e1_resync |= 1; /* get SYNC_I */
- }
- }
- }
- }
-
- if (newmaster) {
- hc = newmaster;
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "id=%d (0x%p) = synchronized with "
- "interface.\n", hc->id, hc);
- /* Enable new sync master */
- plx_acc_32 = hc->plx_membase + PLX_GPIOC;
- pv = readl(plx_acc_32);
- pv |= PLX_SYNC_O_EN;
- writel(pv, plx_acc_32);
- /* switch to jatt PLL, if not disabled by RX_SYNC */
- if (hc->ctype == HFC_TYPE_E1
- && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "Schedule jatt PLL\n");
- hc->e1_resync |= 2; /* switch to jatt */
- }
- } else {
- if (pcmmaster) {
- hc = pcmmaster;
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG
- "id=%d (0x%p) = PCM master synchronized "
- "with QUARTZ\n", hc->id, hc);
- if (hc->ctype == HFC_TYPE_E1) {
- /* Use the crystal clock for the PCM
- master card */
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG
- "Schedule QUARTZ for HFC-E1\n");
- hc->e1_resync |= 4; /* switch quartz */
- } else {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG
- "QUARTZ is automatically "
- "enabled by HFC-%dS\n", hc->ctype);
- }
- plx_acc_32 = hc->plx_membase + PLX_GPIOC;
- pv = readl(plx_acc_32);
- pv |= PLX_SYNC_O_EN;
- writel(pv, plx_acc_32);
- } else
- if (!rm)
- printk(KERN_ERR "%s no pcm master, this MUST "
- "not happen!\n", __func__);
- }
- syncmaster = newmaster;
-
- spin_unlock(&plx_lock);
- spin_unlock_irqrestore(&HFClock, flags);
-}
-
-/* This must be called AND hc must be locked irqsave!!! */
-static inline void
-plxsd_checksync(struct hfc_multi *hc, int rm)
-{
- if (hc->syncronized) {
- if (syncmaster == NULL) {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "%s: GOT sync on card %d"
- " (id=%d)\n", __func__, hc->id + 1,
- hc->id);
- hfcmulti_resync(hc, hc, rm);
- }
- } else {
- if (syncmaster == hc) {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "%s: LOST sync on card %d"
- " (id=%d)\n", __func__, hc->id + 1,
- hc->id);
- hfcmulti_resync(hc, NULL, rm);
- }
- }
-}
-
-
-/*
- * free hardware resources used by driver
- */
-static void
-release_io_hfcmulti(struct hfc_multi *hc)
-{
- void __iomem *plx_acc_32;
- u_int pv;
- u_long plx_flags;
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: entered\n", __func__);
-
- /* soft reset also masks all interrupts */
- hc->hw.r_cirm |= V_SRES;
- HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
- udelay(1000);
- hc->hw.r_cirm &= ~V_SRES;
- HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
- udelay(1000); /* instead of 'wait' that may cause locking */
-
- /* release Speech Design card, if PLX was initialized */
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && hc->plx_membase) {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "%s: release PLXSD card %d\n",
- __func__, hc->id + 1);
- spin_lock_irqsave(&plx_lock, plx_flags);
- plx_acc_32 = hc->plx_membase + PLX_GPIOC;
- writel(PLX_GPIOC_INIT, plx_acc_32);
- pv = readl(plx_acc_32);
- /* Termination off */
- pv &= ~PLX_TERM_ON;
- /* Disconnect the PCM */
- pv |= PLX_SLAVE_EN_N;
- pv &= ~PLX_MASTER_EN;
- pv &= ~PLX_SYNC_O_EN;
- /* Put the DSP in Reset */
- pv &= ~PLX_DSP_RES_N;
- writel(pv, plx_acc_32);
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: PCM off: PLX_GPIO=%x\n",
- __func__, pv);
- spin_unlock_irqrestore(&plx_lock, plx_flags);
- }
-
- /* disable memory mapped ports / io ports */
- test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */
- if (hc->pci_dev)
- pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0);
- if (hc->pci_membase)
- iounmap(hc->pci_membase);
- if (hc->plx_membase)
- iounmap(hc->plx_membase);
- if (hc->pci_iobase)
- release_region(hc->pci_iobase, 8);
- if (hc->xhfc_membase)
- iounmap((void *)hc->xhfc_membase);
-
- if (hc->pci_dev) {
- pci_disable_device(hc->pci_dev);
- pci_set_drvdata(hc->pci_dev, NULL);
- }
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: done\n", __func__);
-}
-
-/*
- * function called to reset the HFC chip. A complete software reset of chip
- * and fifos is done. All configuration of the chip is done.
- */
-
-static int
-init_chip(struct hfc_multi *hc)
-{
- u_long flags, val, val2 = 0, rev;
- int i, err = 0;
- u_char r_conf_en, rval;
- void __iomem *plx_acc_32;
- u_int pv;
- u_long plx_flags, hfc_flags;
- int plx_count;
- struct hfc_multi *pos, *next, *plx_last_hc;
-
- spin_lock_irqsave(&hc->lock, flags);
- /* reset all registers */
- memset(&hc->hw, 0, sizeof(struct hfcm_hw));
-
- /* revision check */
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: entered\n", __func__);
- val = HFC_inb(hc, R_CHIP_ID);
- if ((val >> 4) != 0x8 && (val >> 4) != 0xc && (val >> 4) != 0xe &&
- (val >> 1) != 0x31) {
- printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val);
- err = -EIO;
- goto out;
- }
- rev = HFC_inb(hc, R_CHIP_RV);
- printk(KERN_INFO
- "HFC_multi: detected HFC with chip ID=0x%lx revision=%ld%s\n",
- val, rev, (rev == 0 && (hc->ctype != HFC_TYPE_XHFC)) ?
- " (old FIFO handling)" : "");
- if (hc->ctype != HFC_TYPE_XHFC && rev == 0) {
- test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip);
- printk(KERN_WARNING
- "HFC_multi: NOTE: Your chip is revision 0, "
- "ask Cologne Chip for update. Newer chips "
- "have a better FIFO handling. Old chips "
- "still work but may have slightly lower "
- "HDLC transmit performance.\n");
- }
- if (rev > 1) {
- printk(KERN_WARNING "HFC_multi: WARNING: This driver doesn't "
- "consider chip revision = %ld. The chip / "
- "bridge may not work.\n", rev);
- }
-
- /* set s-ram size */
- hc->Flen = 0x10;
- hc->Zmin = 0x80;
- hc->Zlen = 384;
- hc->DTMFbase = 0x1000;
- if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: changing to 128K external RAM\n",
- __func__);
- hc->hw.r_ctrl |= V_EXT_RAM;
- hc->hw.r_ram_sz = 1;
- hc->Flen = 0x20;
- hc->Zmin = 0xc0;
- hc->Zlen = 1856;
- hc->DTMFbase = 0x2000;
- }
- if (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: changing to 512K external RAM\n",
- __func__);
- hc->hw.r_ctrl |= V_EXT_RAM;
- hc->hw.r_ram_sz = 2;
- hc->Flen = 0x20;
- hc->Zmin = 0xc0;
- hc->Zlen = 8000;
- hc->DTMFbase = 0x2000;
- }
- if (hc->ctype == HFC_TYPE_XHFC) {
- hc->Flen = 0x8;
- hc->Zmin = 0x0;
- hc->Zlen = 64;
- hc->DTMFbase = 0x0;
- }
- hc->max_trans = poll << 1;
- if (hc->max_trans > hc->Zlen)
- hc->max_trans = hc->Zlen;
-
- /* Speech Design PLX bridge */
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "%s: initializing PLXSD card %d\n",
- __func__, hc->id + 1);
- spin_lock_irqsave(&plx_lock, plx_flags);
- plx_acc_32 = hc->plx_membase + PLX_GPIOC;
- writel(PLX_GPIOC_INIT, plx_acc_32);
- pv = readl(plx_acc_32);
- /* The first and the last cards are terminating the PCM bus */
- pv |= PLX_TERM_ON; /* hc is currently the last */
- /* Disconnect the PCM */
- pv |= PLX_SLAVE_EN_N;
- pv &= ~PLX_MASTER_EN;
- pv &= ~PLX_SYNC_O_EN;
- /* Put the DSP in Reset */
- pv &= ~PLX_DSP_RES_N;
- writel(pv, plx_acc_32);
- spin_unlock_irqrestore(&plx_lock, plx_flags);
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: slave/term: PLX_GPIO=%x\n",
- __func__, pv);
- /*
- * If we are the 3rd PLXSD card or higher, we must turn
- * termination of last PLXSD card off.
- */
- spin_lock_irqsave(&HFClock, hfc_flags);
- plx_count = 0;
- plx_last_hc = NULL;
- list_for_each_entry_safe(pos, next, &HFClist, list) {
- if (test_bit(HFC_CHIP_PLXSD, &pos->chip)) {
- plx_count++;
- if (pos != hc)
- plx_last_hc = pos;
- }
- }
- if (plx_count >= 3) {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "%s: card %d is between, so "
- "we disable termination\n",
- __func__, plx_last_hc->id + 1);
- spin_lock_irqsave(&plx_lock, plx_flags);
- plx_acc_32 = plx_last_hc->plx_membase + PLX_GPIOC;
- pv = readl(plx_acc_32);
- pv &= ~PLX_TERM_ON;
- writel(pv, plx_acc_32);
- spin_unlock_irqrestore(&plx_lock, plx_flags);
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: term off: PLX_GPIO=%x\n",
- __func__, pv);
- }
- spin_unlock_irqrestore(&HFClock, hfc_flags);
- hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */
- }
-
- if (test_bit(HFC_CHIP_EMBSD, &hc->chip))
- hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */
-
- /* we only want the real Z2 read-pointer for revision > 0 */
- if (!test_bit(HFC_CHIP_REVISION0, &hc->chip))
- hc->hw.r_ram_sz |= V_FZ_MD;
-
- /* select pcm mode */
- if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: setting PCM into slave mode\n",
- __func__);
- } else
- if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) && !plxsd_master) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: setting PCM into master mode\n",
- __func__);
- hc->hw.r_pcm_md0 |= V_PCM_MD;
- } else {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: performing PCM auto detect\n",
- __func__);
- }
-
- /* soft reset */
- HFC_outb(hc, R_CTRL, hc->hw.r_ctrl);
- if (hc->ctype == HFC_TYPE_XHFC)
- HFC_outb(hc, 0x0C /* R_FIFO_THRES */,
- 0x11 /* 16 Bytes TX/RX */);
- else
- HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz);
- HFC_outb(hc, R_FIFO_MD, 0);
- if (hc->ctype == HFC_TYPE_XHFC)
- hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES;
- else
- hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES
- | V_RLD_EPR;
- HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
- udelay(100);
- hc->hw.r_cirm = 0;
- HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
- udelay(100);
- if (hc->ctype != HFC_TYPE_XHFC)
- HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz);
-
- /* Speech Design PLX bridge pcm and sync mode */
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- spin_lock_irqsave(&plx_lock, plx_flags);
- plx_acc_32 = hc->plx_membase + PLX_GPIOC;
- pv = readl(plx_acc_32);
- /* Connect PCM */
- if (hc->hw.r_pcm_md0 & V_PCM_MD) {
- pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N;
- pv |= PLX_SYNC_O_EN;
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: master: PLX_GPIO=%x\n",
- __func__, pv);
- } else {
- pv &= ~(PLX_MASTER_EN | PLX_SLAVE_EN_N);
- pv &= ~PLX_SYNC_O_EN;
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: slave: PLX_GPIO=%x\n",
- __func__, pv);
- }
- writel(pv, plx_acc_32);
- spin_unlock_irqrestore(&plx_lock, plx_flags);
- }
-
- /* PCM setup */
- HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x90);
- if (hc->slots == 32)
- HFC_outb(hc, R_PCM_MD1, 0x00);
- if (hc->slots == 64)
- HFC_outb(hc, R_PCM_MD1, 0x10);
- if (hc->slots == 128)
- HFC_outb(hc, R_PCM_MD1, 0x20);
- HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0);
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip))
- HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */
- else if (test_bit(HFC_CHIP_EMBSD, &hc->chip))
- HFC_outb(hc, R_PCM_MD2, 0x10); /* V_C2O_EN */
- else
- HFC_outb(hc, R_PCM_MD2, 0x00); /* sync from interface */
- HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00);
- for (i = 0; i < 256; i++) {
- HFC_outb_nodebug(hc, R_SLOT, i);
- HFC_outb_nodebug(hc, A_SL_CFG, 0);
- if (hc->ctype != HFC_TYPE_XHFC)
- HFC_outb_nodebug(hc, A_CONF, 0);
- hc->slot_owner[i] = -1;
- }
-
- /* set clock speed */
- if (test_bit(HFC_CHIP_CLOCK2, &hc->chip)) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: setting double clock\n", __func__);
- HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK);
- }
-
- if (test_bit(HFC_CHIP_EMBSD, &hc->chip))
- HFC_outb(hc, 0x02 /* R_CLK_CFG */, 0x40 /* V_CLKO_OFF */);
-
- /* B410P GPIO */
- if (test_bit(HFC_CHIP_B410P, &hc->chip)) {
- printk(KERN_NOTICE "Setting GPIOs\n");
- HFC_outb(hc, R_GPIO_SEL, 0x30);
- HFC_outb(hc, R_GPIO_EN1, 0x3);
- udelay(1000);
- printk(KERN_NOTICE "calling vpm_init\n");
- vpm_init(hc);
- }
-
- /* check if R_F0_CNT counts (8 kHz frame count) */
- val = HFC_inb(hc, R_F0_CNTL);
- val += HFC_inb(hc, R_F0_CNTH) << 8;
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "HFC_multi F0_CNT %ld after reset\n", val);
- spin_unlock_irqrestore(&hc->lock, flags);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((HZ / 100) ? : 1); /* Timeout minimum 10ms */
- spin_lock_irqsave(&hc->lock, flags);
- val2 = HFC_inb(hc, R_F0_CNTL);
- val2 += HFC_inb(hc, R_F0_CNTH) << 8;
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "HFC_multi F0_CNT %ld after 10 ms (1st try)\n",
- val2);
- if (val2 >= val + 8) { /* 1 ms */
- /* it counts, so we keep the pcm mode */
- if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip))
- printk(KERN_INFO "controller is PCM bus MASTER\n");
- else
- if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip))
- printk(KERN_INFO "controller is PCM bus SLAVE\n");
- else {
- test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip);
- printk(KERN_INFO "controller is PCM bus SLAVE "
- "(auto detected)\n");
- }
- } else {
- /* does not count */
- if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) {
- controller_fail:
- printk(KERN_ERR "HFC_multi ERROR, getting no 125us "
- "pulse. Seems that controller fails.\n");
- err = -EIO;
- goto out;
- }
- if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
- printk(KERN_INFO "controller is PCM bus SLAVE "
- "(ignoring missing PCM clock)\n");
- } else {
- /* only one pcm master */
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)
- && plxsd_master) {
- printk(KERN_ERR "HFC_multi ERROR, no clock "
- "on another Speech Design card found. "
- "Please be sure to connect PCM cable.\n");
- err = -EIO;
- goto out;
- }
- /* retry with master clock */
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- spin_lock_irqsave(&plx_lock, plx_flags);
- plx_acc_32 = hc->plx_membase + PLX_GPIOC;
- pv = readl(plx_acc_32);
- pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N;
- pv |= PLX_SYNC_O_EN;
- writel(pv, plx_acc_32);
- spin_unlock_irqrestore(&plx_lock, plx_flags);
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: master: "
- "PLX_GPIO=%x\n", __func__, pv);
- }
- hc->hw.r_pcm_md0 |= V_PCM_MD;
- HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00);
- spin_unlock_irqrestore(&hc->lock, flags);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((HZ / 100) ?: 1); /* Timeout min. 10ms */
- spin_lock_irqsave(&hc->lock, flags);
- val2 = HFC_inb(hc, R_F0_CNTL);
- val2 += HFC_inb(hc, R_F0_CNTH) << 8;
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "HFC_multi F0_CNT %ld after "
- "10 ms (2nd try)\n", val2);
- if (val2 >= val + 8) { /* 1 ms */
- test_and_set_bit(HFC_CHIP_PCM_MASTER,
- &hc->chip);
- printk(KERN_INFO "controller is PCM bus MASTER "
- "(auto detected)\n");
- } else
- goto controller_fail;
- }
- }
-
- /* Release the DSP Reset */
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip))
- plxsd_master = 1;
- spin_lock_irqsave(&plx_lock, plx_flags);
- plx_acc_32 = hc->plx_membase + PLX_GPIOC;
- pv = readl(plx_acc_32);
- pv |= PLX_DSP_RES_N;
- writel(pv, plx_acc_32);
- spin_unlock_irqrestore(&plx_lock, plx_flags);
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: reset off: PLX_GPIO=%x\n",
- __func__, pv);
- }
-
- /* pcm id */
- if (hc->pcm)
- printk(KERN_INFO "controller has given PCM BUS ID %d\n",
- hc->pcm);
- else {
- if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)
- || test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- PCM_cnt++; /* SD has proprietary bridging */
- }
- hc->pcm = PCM_cnt;
- printk(KERN_INFO "controller has PCM BUS ID %d "
- "(auto selected)\n", hc->pcm);
- }
-
- /* set up timer */
- HFC_outb(hc, R_TI_WD, poll_timer);
- hc->hw.r_irqmsk_misc |= V_TI_IRQMSK;
-
- /* set E1 state machine IRQ */
- if (hc->ctype == HFC_TYPE_E1)
- hc->hw.r_irqmsk_misc |= V_STA_IRQMSK;
-
- /* set DTMF detection */
- if (test_bit(HFC_CHIP_DTMF, &hc->chip)) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: enabling DTMF detection "
- "for all B-channel\n", __func__);
- hc->hw.r_dtmf = V_DTMF_EN | V_DTMF_STOP;
- if (test_bit(HFC_CHIP_ULAW, &hc->chip))
- hc->hw.r_dtmf |= V_ULAW_SEL;
- HFC_outb(hc, R_DTMF_N, 102 - 1);
- hc->hw.r_irqmsk_misc |= V_DTMF_IRQMSK;
- }
-
- /* conference engine */
- if (test_bit(HFC_CHIP_ULAW, &hc->chip))
- r_conf_en = V_CONF_EN | V_ULAW;
- else
- r_conf_en = V_CONF_EN;
- if (hc->ctype != HFC_TYPE_XHFC)
- HFC_outb(hc, R_CONF_EN, r_conf_en);
-
- /* setting leds */
- switch (hc->leds) {
- case 1: /* HFC-E1 OEM */
- if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip))
- HFC_outb(hc, R_GPIO_SEL, 0x32);
- else
- HFC_outb(hc, R_GPIO_SEL, 0x30);
-
- HFC_outb(hc, R_GPIO_EN1, 0x0f);
- HFC_outb(hc, R_GPIO_OUT1, 0x00);
-
- HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3);
- break;
-
- case 2: /* HFC-4S OEM */
- case 3:
- HFC_outb(hc, R_GPIO_SEL, 0xf0);
- HFC_outb(hc, R_GPIO_EN1, 0xff);
- HFC_outb(hc, R_GPIO_OUT1, 0x00);
- break;
- }
-
- if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) {
- hc->hw.r_st_sync = 0x10; /* V_AUTO_SYNCI */
- HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync);
- }
-
- /* set master clock */
- if (hc->masterclk >= 0) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: setting ST master clock "
- "to port %d (0..%d)\n",
- __func__, hc->masterclk, hc->ports - 1);
- hc->hw.r_st_sync |= (hc->masterclk | V_AUTO_SYNC);
- HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync);
- }
-
-
-
- /* setting misc irq */
- HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc);
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "r_irqmsk_misc.2: 0x%x\n",
- hc->hw.r_irqmsk_misc);
-
- /* RAM access test */
- HFC_outb(hc, R_RAM_ADDR0, 0);
- HFC_outb(hc, R_RAM_ADDR1, 0);
- HFC_outb(hc, R_RAM_ADDR2, 0);
- for (i = 0; i < 256; i++) {
- HFC_outb_nodebug(hc, R_RAM_ADDR0, i);
- HFC_outb_nodebug(hc, R_RAM_DATA, ((i * 3) & 0xff));
- }
- for (i = 0; i < 256; i++) {
- HFC_outb_nodebug(hc, R_RAM_ADDR0, i);
- HFC_inb_nodebug(hc, R_RAM_DATA);
- rval = HFC_inb_nodebug(hc, R_INT_DATA);
- if (rval != ((i * 3) & 0xff)) {
- printk(KERN_DEBUG
- "addr:%x val:%x should:%x\n", i, rval,
- (i * 3) & 0xff);
- err++;
- }
- }
- if (err) {
- printk(KERN_DEBUG "aborting - %d RAM access errors\n", err);
- err = -EIO;
- goto out;
- }
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: done\n", __func__);
-out:
- spin_unlock_irqrestore(&hc->lock, flags);
- return err;
-}
-
-
-/*
- * control the watchdog
- */
-static void
-hfcmulti_watchdog(struct hfc_multi *hc)
-{
- hc->wdcount++;
-
- if (hc->wdcount > 10) {
- hc->wdcount = 0;
- hc->wdbyte = hc->wdbyte == V_GPIO_OUT2 ?
- V_GPIO_OUT3 : V_GPIO_OUT2;
-
- /* printk("Sending Watchdog Kill %x\n",hc->wdbyte); */
- HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3);
- HFC_outb(hc, R_GPIO_OUT0, hc->wdbyte);
- }
-}
-
-
-
-/*
- * output leds
- */
-static void
-hfcmulti_leds(struct hfc_multi *hc)
-{
- unsigned long lled;
- unsigned long leddw;
- int i, state, active, leds;
- struct dchannel *dch;
- int led[4];
-
- switch (hc->leds) {
- case 1: /* HFC-E1 OEM */
- /* 2 red steady: LOS
- * 1 red steady: L1 not active
- * 2 green steady: L1 active
- * 1st green flashing: activity on TX
- * 2nd green flashing: activity on RX
- */
- led[0] = 0;
- led[1] = 0;
- led[2] = 0;
- led[3] = 0;
- dch = hc->chan[hc->dnum[0]].dch;
- if (dch) {
- if (hc->chan[hc->dnum[0]].los)
- led[1] = 1;
- if (hc->e1_state != 1) {
- led[0] = 1;
- hc->flash[2] = 0;
- hc->flash[3] = 0;
- } else {
- led[2] = 1;
- led[3] = 1;
- if (!hc->flash[2] && hc->activity_tx)
- hc->flash[2] = poll;
- if (!hc->flash[3] && hc->activity_rx)
- hc->flash[3] = poll;
- if (hc->flash[2] && hc->flash[2] < 1024)
- led[2] = 0;
- if (hc->flash[3] && hc->flash[3] < 1024)
- led[3] = 0;
- if (hc->flash[2] >= 2048)
- hc->flash[2] = 0;
- if (hc->flash[3] >= 2048)
- hc->flash[3] = 0;
- if (hc->flash[2])
- hc->flash[2] += poll;
- if (hc->flash[3])
- hc->flash[3] += poll;
- }
- }
- leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF;
- /* leds are inverted */
- if (leds != (int)hc->ledstate) {
- HFC_outb_nodebug(hc, R_GPIO_OUT1, leds);
- hc->ledstate = leds;
- }
- break;
-
- case 2: /* HFC-4S OEM */
- /* red steady: PH_DEACTIVATE
- * green steady: PH_ACTIVATE
- * green flashing: activity on TX
- */
- for (i = 0; i < 4; i++) {
- state = 0;
- active = -1;
- dch = hc->chan[(i << 2) | 2].dch;
- if (dch) {
- state = dch->state;
- if (dch->dev.D.protocol == ISDN_P_NT_S0)
- active = 3;
- else
- active = 7;
- }
- if (state) {
- if (state == active) {
- led[i] = 1; /* led green */
- hc->activity_tx |= hc->activity_rx;
- if (!hc->flash[i] &&
- (hc->activity_tx & (1 << i)))
- hc->flash[i] = poll;
- if (hc->flash[i] && hc->flash[i] < 1024)
- led[i] = 0; /* led off */
- if (hc->flash[i] >= 2048)
- hc->flash[i] = 0;
- if (hc->flash[i])
- hc->flash[i] += poll;
- } else {
- led[i] = 2; /* led red */
- hc->flash[i] = 0;
- }
- } else
- led[i] = 0; /* led off */
- }
- if (test_bit(HFC_CHIP_B410P, &hc->chip)) {
- leds = 0;
- for (i = 0; i < 4; i++) {
- if (led[i] == 1) {
- /*green*/
- leds |= (0x2 << (i * 2));
- } else if (led[i] == 2) {
- /*red*/
- leds |= (0x1 << (i * 2));
- }
- }
- if (leds != (int)hc->ledstate) {
- vpm_out(hc, 0, 0x1a8 + 3, leds);
- hc->ledstate = leds;
- }
- } else {
- leds = ((led[3] > 0) << 0) | ((led[1] > 0) << 1) |
- ((led[0] > 0) << 2) | ((led[2] > 0) << 3) |
- ((led[3] & 1) << 4) | ((led[1] & 1) << 5) |
- ((led[0] & 1) << 6) | ((led[2] & 1) << 7);
- if (leds != (int)hc->ledstate) {
- HFC_outb_nodebug(hc, R_GPIO_EN1, leds & 0x0F);
- HFC_outb_nodebug(hc, R_GPIO_OUT1, leds >> 4);
- hc->ledstate = leds;
- }
- }
- break;
-
- case 3: /* HFC 1S/2S Beronet */
- /* red steady: PH_DEACTIVATE
- * green steady: PH_ACTIVATE
- * green flashing: activity on TX
- */
- for (i = 0; i < 2; i++) {
- state = 0;
- active = -1;
- dch = hc->chan[(i << 2) | 2].dch;
- if (dch) {
- state = dch->state;
- if (dch->dev.D.protocol == ISDN_P_NT_S0)
- active = 3;
- else
- active = 7;
- }
- if (state) {
- if (state == active) {
- led[i] = 1; /* led green */
- hc->activity_tx |= hc->activity_rx;
- if (!hc->flash[i] &&
- (hc->activity_tx & (1 << i)))
- hc->flash[i] = poll;
- if (hc->flash[i] < 1024)
- led[i] = 0; /* led off */
- if (hc->flash[i] >= 2048)
- hc->flash[i] = 0;
- if (hc->flash[i])
- hc->flash[i] += poll;
- } else {
- led[i] = 2; /* led red */
- hc->flash[i] = 0;
- }
- } else
- led[i] = 0; /* led off */
- }
- leds = (led[0] > 0) | ((led[1] > 0) << 1) | ((led[0]&1) << 2)
- | ((led[1]&1) << 3);
- if (leds != (int)hc->ledstate) {
- HFC_outb_nodebug(hc, R_GPIO_EN1,
- ((led[0] > 0) << 2) | ((led[1] > 0) << 3));
- HFC_outb_nodebug(hc, R_GPIO_OUT1,
- ((led[0] & 1) << 2) | ((led[1] & 1) << 3));
- hc->ledstate = leds;
- }
- break;
- case 8: /* HFC 8S+ Beronet */
- /* off: PH_DEACTIVATE
- * steady: PH_ACTIVATE
- * flashing: activity on TX
- */
- lled = 0xff; /* leds off */
- for (i = 0; i < 8; i++) {
- state = 0;
- active = -1;
- dch = hc->chan[(i << 2) | 2].dch;
- if (dch) {
- state = dch->state;
- if (dch->dev.D.protocol == ISDN_P_NT_S0)
- active = 3;
- else
- active = 7;
- }
- if (state) {
- if (state == active) {
- lled &= ~(1 << i); /* led on */
- hc->activity_tx |= hc->activity_rx;
- if (!hc->flash[i] &&
- (hc->activity_tx & (1 << i)))
- hc->flash[i] = poll;
- if (hc->flash[i] < 1024)
- lled |= 1 << i; /* led off */
- if (hc->flash[i] >= 2048)
- hc->flash[i] = 0;
- if (hc->flash[i])
- hc->flash[i] += poll;
- } else
- hc->flash[i] = 0;
- }
- }
- leddw = lled << 24 | lled << 16 | lled << 8 | lled;
- if (leddw != hc->ledstate) {
- /* HFC_outb(hc, R_BRG_PCM_CFG, 1);
- HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); */
- /* was _io before */
- HFC_outb_nodebug(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK);
- outw(0x4000, hc->pci_iobase + 4);
- outl(leddw, hc->pci_iobase);
- HFC_outb_nodebug(hc, R_BRG_PCM_CFG, V_PCM_CLK);
- hc->ledstate = leddw;
- }
- break;
- }
- hc->activity_tx = 0;
- hc->activity_rx = 0;
-}
-/*
- * read dtmf coefficients
- */
-
-static void
-hfcmulti_dtmf(struct hfc_multi *hc)
-{
- s32 *coeff;
- u_int mantissa;
- int co, ch;
- struct bchannel *bch = NULL;
- u8 exponent;
- int dtmf = 0;
- int addr;
- u16 w_float;
- struct sk_buff *skb;
- struct mISDNhead *hh;
-
- if (debug & DEBUG_HFCMULTI_DTMF)
- printk(KERN_DEBUG "%s: dtmf detection irq\n", __func__);
- for (ch = 0; ch <= 31; ch++) {
- /* only process enabled B-channels */
- bch = hc->chan[ch].bch;
- if (!bch)
- continue;
- if (!hc->created[hc->chan[ch].port])
- continue;
- if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
- continue;
- if (debug & DEBUG_HFCMULTI_DTMF)
- printk(KERN_DEBUG "%s: dtmf channel %d:",
- __func__, ch);
- coeff = &(hc->chan[ch].coeff[hc->chan[ch].coeff_count * 16]);
- dtmf = 1;
- for (co = 0; co < 8; co++) {
- /* read W(n-1) coefficient */
- addr = hc->DTMFbase + ((co << 7) | (ch << 2));
- HFC_outb_nodebug(hc, R_RAM_ADDR0, addr);
- HFC_outb_nodebug(hc, R_RAM_ADDR1, addr >> 8);
- HFC_outb_nodebug(hc, R_RAM_ADDR2, (addr >> 16)
- | V_ADDR_INC);
- w_float = HFC_inb_nodebug(hc, R_RAM_DATA);
- w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8);
- if (debug & DEBUG_HFCMULTI_DTMF)
- printk(" %04x", w_float);
-
- /* decode float (see chip doc) */
- mantissa = w_float & 0x0fff;
- if (w_float & 0x8000)
- mantissa |= 0xfffff000;
- exponent = (w_float >> 12) & 0x7;
- if (exponent) {
- mantissa ^= 0x1000;
- mantissa <<= (exponent - 1);
- }
-
- /* store coefficient */
- coeff[co << 1] = mantissa;
-
- /* read W(n) coefficient */
- w_float = HFC_inb_nodebug(hc, R_RAM_DATA);
- w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8);
- if (debug & DEBUG_HFCMULTI_DTMF)
- printk(" %04x", w_float);
-
- /* decode float (see chip doc) */
- mantissa = w_float & 0x0fff;
- if (w_float & 0x8000)
- mantissa |= 0xfffff000;
- exponent = (w_float >> 12) & 0x7;
- if (exponent) {
- mantissa ^= 0x1000;
- mantissa <<= (exponent - 1);
- }
-
- /* store coefficient */
- coeff[(co << 1) | 1] = mantissa;
- }
- if (debug & DEBUG_HFCMULTI_DTMF)
- printk(" DTMF ready %08x %08x %08x %08x "
- "%08x %08x %08x %08x\n",
- coeff[0], coeff[1], coeff[2], coeff[3],
- coeff[4], coeff[5], coeff[6], coeff[7]);
- hc->chan[ch].coeff_count++;
- if (hc->chan[ch].coeff_count == 8) {
- hc->chan[ch].coeff_count = 0;
- skb = mI_alloc_skb(512, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_DEBUG "%s: No memory for skb\n",
- __func__);
- continue;
- }
- hh = mISDN_HEAD_P(skb);
- hh->prim = PH_CONTROL_IND;
- hh->id = DTMF_HFC_COEF;
- skb_put_data(skb, hc->chan[ch].coeff, 512);
- recv_Bchannel_skb(bch, skb);
- }
- }
-
- /* restart DTMF processing */
- hc->dtmf = dtmf;
- if (dtmf)
- HFC_outb_nodebug(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF);
-}
-
-
-/*
- * fill fifo as much as possible
- */
-
-static void
-hfcmulti_tx(struct hfc_multi *hc, int ch)
-{
- int i, ii, temp, tmp_len, len = 0;
- int Zspace, z1, z2; /* must be int for calculation */
- int Fspace, f1, f2;
- u_char *d;
- int *txpending, slot_tx;
- struct bchannel *bch;
- struct dchannel *dch;
- struct sk_buff **sp = NULL;
- int *idxp;
-
- bch = hc->chan[ch].bch;
- dch = hc->chan[ch].dch;
- if ((!dch) && (!bch))
- return;
-
- txpending = &hc->chan[ch].txpending;
- slot_tx = hc->chan[ch].slot_tx;
- if (dch) {
- if (!test_bit(FLG_ACTIVE, &dch->Flags))
- return;
- sp = &dch->tx_skb;
- idxp = &dch->tx_idx;
- } else {
- if (!test_bit(FLG_ACTIVE, &bch->Flags))
- return;
- sp = &bch->tx_skb;
- idxp = &bch->tx_idx;
- }
- if (*sp)
- len = (*sp)->len;
-
- if ((!len) && *txpending != 1)
- return; /* no data */
-
- if (test_bit(HFC_CHIP_B410P, &hc->chip) &&
- (hc->chan[ch].protocol == ISDN_P_B_RAW) &&
- (hc->chan[ch].slot_rx < 0) &&
- (hc->chan[ch].slot_tx < 0))
- HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1));
- else
- HFC_outb_nodebug(hc, R_FIFO, ch << 1);
- HFC_wait_nodebug(hc);
-
- if (*txpending == 2) {
- /* reset fifo */
- HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F);
- HFC_wait_nodebug(hc);
- HFC_outb(hc, A_SUBCH_CFG, 0);
- *txpending = 1;
- }
-next_frame:
- if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
- f1 = HFC_inb_nodebug(hc, A_F1);
- f2 = HFC_inb_nodebug(hc, A_F2);
- while (f2 != (temp = HFC_inb_nodebug(hc, A_F2))) {
- if (debug & DEBUG_HFCMULTI_FIFO)
- printk(KERN_DEBUG
- "%s(card %d): reread f2 because %d!=%d\n",
- __func__, hc->id + 1, temp, f2);
- f2 = temp; /* repeat until F2 is equal */
- }
- Fspace = f2 - f1 - 1;
- if (Fspace < 0)
- Fspace += hc->Flen;
- /*
- * Old FIFO handling doesn't give us the current Z2 read
- * pointer, so we cannot send the next frame before the fifo
- * is empty. It makes no difference except for a slightly
- * lower performance.
- */
- if (test_bit(HFC_CHIP_REVISION0, &hc->chip)) {
- if (f1 != f2)
- Fspace = 0;
- else
- Fspace = 1;
- }
- /* one frame only for ST D-channels, to allow resending */
- if (hc->ctype != HFC_TYPE_E1 && dch) {
- if (f1 != f2)
- Fspace = 0;
- }
- /* F-counter full condition */
- if (Fspace == 0)
- return;
- }
- z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin;
- z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin;
- while (z2 != (temp = (HFC_inw_nodebug(hc, A_Z2) - hc->Zmin))) {
- if (debug & DEBUG_HFCMULTI_FIFO)
- printk(KERN_DEBUG "%s(card %d): reread z2 because "
- "%d!=%d\n", __func__, hc->id + 1, temp, z2);
- z2 = temp; /* repeat unti Z2 is equal */
- }
- hc->chan[ch].Zfill = z1 - z2;
- if (hc->chan[ch].Zfill < 0)
- hc->chan[ch].Zfill += hc->Zlen;
- Zspace = z2 - z1;
- if (Zspace <= 0)
- Zspace += hc->Zlen;
- Zspace -= 4; /* keep not too full, so pointers will not overrun */
- /* fill transparent data only to maximum transparent load (minus 4) */
- if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags))
- Zspace = Zspace - hc->Zlen + hc->max_trans;
- if (Zspace <= 0) /* no space of 4 bytes */
- return;
-
- /* if no data */
- if (!len) {
- if (z1 == z2) { /* empty */
- /* if done with FIFO audio data during PCM connection */
- if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) &&
- *txpending && slot_tx >= 0) {
- if (debug & DEBUG_HFCMULTI_MODE)
- printk(KERN_DEBUG
- "%s: reconnecting PCM due to no "
- "more FIFO data: channel %d "
- "slot_tx %d\n",
- __func__, ch, slot_tx);
- /* connect slot */
- if (hc->ctype == HFC_TYPE_XHFC)
- HFC_outb(hc, A_CON_HDLC, 0xc0
- | 0x07 << 2 | V_HDLC_TRP | V_IFF);
- /* Enable FIFO, no interrupt */
- else
- HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 |
- V_HDLC_TRP | V_IFF);
- HFC_outb_nodebug(hc, R_FIFO, ch << 1 | 1);
- HFC_wait_nodebug(hc);
- if (hc->ctype == HFC_TYPE_XHFC)
- HFC_outb(hc, A_CON_HDLC, 0xc0
- | 0x07 << 2 | V_HDLC_TRP | V_IFF);
- /* Enable FIFO, no interrupt */
- else
- HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 |
- V_HDLC_TRP | V_IFF);
- HFC_outb_nodebug(hc, R_FIFO, ch << 1);
- HFC_wait_nodebug(hc);
- }
- *txpending = 0;
- }
- return; /* no data */
- }
-
- /* "fill fifo if empty" feature */
- if (bch && test_bit(FLG_FILLEMPTY, &bch->Flags)
- && !test_bit(FLG_HDLC, &bch->Flags) && z2 == z1) {
- if (debug & DEBUG_HFCMULTI_FILL)
- printk(KERN_DEBUG "%s: buffer empty, so we have "
- "underrun\n", __func__);
- /* fill buffer, to prevent future underrun */
- hc->write_fifo(hc, hc->silence_data, poll >> 1);
- Zspace -= (poll >> 1);
- }
-
- /* if audio data and connected slot */
- if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending)
- && slot_tx >= 0) {
- if (debug & DEBUG_HFCMULTI_MODE)
- printk(KERN_DEBUG "%s: disconnecting PCM due to "
- "FIFO data: channel %d slot_tx %d\n",
- __func__, ch, slot_tx);
- /* disconnect slot */
- if (hc->ctype == HFC_TYPE_XHFC)
- HFC_outb(hc, A_CON_HDLC, 0x80
- | 0x07 << 2 | V_HDLC_TRP | V_IFF);
- /* Enable FIFO, no interrupt */
- else
- HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 |
- V_HDLC_TRP | V_IFF);
- HFC_outb_nodebug(hc, R_FIFO, ch << 1 | 1);
- HFC_wait_nodebug(hc);
- if (hc->ctype == HFC_TYPE_XHFC)
- HFC_outb(hc, A_CON_HDLC, 0x80
- | 0x07 << 2 | V_HDLC_TRP | V_IFF);
- /* Enable FIFO, no interrupt */
- else
- HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 |
- V_HDLC_TRP | V_IFF);
- HFC_outb_nodebug(hc, R_FIFO, ch << 1);
- HFC_wait_nodebug(hc);
- }
- *txpending = 1;
-
- /* show activity */
- if (dch)
- hc->activity_tx |= 1 << hc->chan[ch].port;
-
- /* fill fifo to what we have left */
- ii = len;
- if (dch || test_bit(FLG_HDLC, &bch->Flags))
- temp = 1;
- else
- temp = 0;
- i = *idxp;
- d = (*sp)->data + i;
- if (ii - i > Zspace)
- ii = Zspace + i;
- if (debug & DEBUG_HFCMULTI_FIFO)
- printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space "
- "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n",
- __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i,
- temp ? "HDLC" : "TRANS");
-
- /* Have to prep the audio data */
- hc->write_fifo(hc, d, ii - i);
- hc->chan[ch].Zfill += ii - i;
- *idxp = ii;
-
- /* if not all data has been written */
- if (ii != len) {
- /* NOTE: fifo is started by the calling function */
- return;
- }
-
- /* if all data has been written, terminate frame */
- if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
- /* increment f-counter */
- HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F);
- HFC_wait_nodebug(hc);
- }
-
- tmp_len = (*sp)->len;
- dev_kfree_skb(*sp);
- /* check for next frame */
- if (bch && get_next_bframe(bch)) {
- len = tmp_len;
- goto next_frame;
- }
- if (dch && get_next_dframe(dch)) {
- len = tmp_len;
- goto next_frame;
- }
-
- /*
- * now we have no more data, so in case of transparent,
- * we set the last byte in fifo to 'silence' in case we will get
- * no more data at all. this prevents sending an undefined value.
- */
- if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags))
- HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
-}
-
-
-/* NOTE: only called if E1 card is in active state */
-static void
-hfcmulti_rx(struct hfc_multi *hc, int ch)
-{
- int temp;
- int Zsize, z1, z2 = 0; /* = 0, to make GCC happy */
- int f1 = 0, f2 = 0; /* = 0, to make GCC happy */
- int again = 0;
- struct bchannel *bch;
- struct dchannel *dch = NULL;
- struct sk_buff *skb, **sp = NULL;
- int maxlen;
-
- bch = hc->chan[ch].bch;
- if (bch) {
- if (!test_bit(FLG_ACTIVE, &bch->Flags))
- return;
- } else if (hc->chan[ch].dch) {
- dch = hc->chan[ch].dch;
- if (!test_bit(FLG_ACTIVE, &dch->Flags))
- return;
- } else {
- return;
- }
-next_frame:
- /* on first AND before getting next valid frame, R_FIFO must be written
- to. */
- if (test_bit(HFC_CHIP_B410P, &hc->chip) &&
- (hc->chan[ch].protocol == ISDN_P_B_RAW) &&
- (hc->chan[ch].slot_rx < 0) &&
- (hc->chan[ch].slot_tx < 0))
- HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1) | 1);
- else
- HFC_outb_nodebug(hc, R_FIFO, (ch << 1) | 1);
- HFC_wait_nodebug(hc);
-
- /* ignore if rx is off BUT change fifo (above) to start pending TX */
- if (hc->chan[ch].rx_off) {
- if (bch)
- bch->dropcnt += poll; /* not exact but fair enough */
- return;
- }
-
- if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
- f1 = HFC_inb_nodebug(hc, A_F1);
- while (f1 != (temp = HFC_inb_nodebug(hc, A_F1))) {
- if (debug & DEBUG_HFCMULTI_FIFO)
- printk(KERN_DEBUG
- "%s(card %d): reread f1 because %d!=%d\n",
- __func__, hc->id + 1, temp, f1);
- f1 = temp; /* repeat until F1 is equal */
- }
- f2 = HFC_inb_nodebug(hc, A_F2);
- }
- z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin;
- while (z1 != (temp = (HFC_inw_nodebug(hc, A_Z1) - hc->Zmin))) {
- if (debug & DEBUG_HFCMULTI_FIFO)
- printk(KERN_DEBUG "%s(card %d): reread z2 because "
- "%d!=%d\n", __func__, hc->id + 1, temp, z2);
- z1 = temp; /* repeat until Z1 is equal */
- }
- z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin;
- Zsize = z1 - z2;
- if ((dch || test_bit(FLG_HDLC, &bch->Flags)) && f1 != f2)
- /* complete hdlc frame */
- Zsize++;
- if (Zsize < 0)
- Zsize += hc->Zlen;
- /* if buffer is empty */
- if (Zsize <= 0)
- return;
-
- if (bch) {
- maxlen = bchannel_get_rxbuf(bch, Zsize);
- if (maxlen < 0) {
- pr_warn("card%d.B%d: No bufferspace for %d bytes\n",
- hc->id + 1, bch->nr, Zsize);
- return;
- }
- sp = &bch->rx_skb;
- maxlen = bch->maxlen;
- } else { /* Dchannel */
- sp = &dch->rx_skb;
- maxlen = dch->maxlen + 3;
- if (*sp == NULL) {
- *sp = mI_alloc_skb(maxlen, GFP_ATOMIC);
- if (*sp == NULL) {
- pr_warn("card%d: No mem for dch rx_skb\n",
- hc->id + 1);
- return;
- }
- }
- }
- /* show activity */
- if (dch)
- hc->activity_rx |= 1 << hc->chan[ch].port;
-
- /* empty fifo with what we have */
- if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
- if (debug & DEBUG_HFCMULTI_FIFO)
- printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d "
- "bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) "
- "got=%d (again %d)\n", __func__, hc->id + 1, ch,
- Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE",
- f1, f2, Zsize + (*sp)->len, again);
- /* HDLC */
- if ((Zsize + (*sp)->len) > maxlen) {
- if (debug & DEBUG_HFCMULTI_FIFO)
- printk(KERN_DEBUG
- "%s(card %d): hdlc-frame too large.\n",
- __func__, hc->id + 1);
- skb_trim(*sp, 0);
- HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F);
- HFC_wait_nodebug(hc);
- return;
- }
-
- hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize);
-
- if (f1 != f2) {
- /* increment Z2,F2-counter */
- HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F);
- HFC_wait_nodebug(hc);
- /* check size */
- if ((*sp)->len < 4) {
- if (debug & DEBUG_HFCMULTI_FIFO)
- printk(KERN_DEBUG
- "%s(card %d): Frame below minimum "
- "size\n", __func__, hc->id + 1);
- skb_trim(*sp, 0);
- goto next_frame;
- }
- /* there is at least one complete frame, check crc */
- if ((*sp)->data[(*sp)->len - 1]) {
- if (debug & DEBUG_HFCMULTI_CRC)
- printk(KERN_DEBUG
- "%s: CRC-error\n", __func__);
- skb_trim(*sp, 0);
- goto next_frame;
- }
- skb_trim(*sp, (*sp)->len - 3);
- if ((*sp)->len < MISDN_COPY_SIZE) {
- skb = *sp;
- *sp = mI_alloc_skb(skb->len, GFP_ATOMIC);
- if (*sp) {
- skb_put_data(*sp, skb->data, skb->len);
- skb_trim(skb, 0);
- } else {
- printk(KERN_DEBUG "%s: No mem\n",
- __func__);
- *sp = skb;
- skb = NULL;
- }
- } else {
- skb = NULL;
- }
- if (debug & DEBUG_HFCMULTI_FIFO) {
- printk(KERN_DEBUG "%s(card %d):",
- __func__, hc->id + 1);
- temp = 0;
- while (temp < (*sp)->len)
- printk(" %02x", (*sp)->data[temp++]);
- printk("\n");
- }
- if (dch)
- recv_Dchannel(dch);
- else
- recv_Bchannel(bch, MISDN_ID_ANY, false);
- *sp = skb;
- again++;
- goto next_frame;
- }
- /* there is an incomplete frame */
- } else {
- /* transparent */
- hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize);
- if (debug & DEBUG_HFCMULTI_FIFO)
- printk(KERN_DEBUG
- "%s(card %d): fifo(%d) reading %d bytes "
- "(z1=%04x, z2=%04x) TRANS\n",
- __func__, hc->id + 1, ch, Zsize, z1, z2);
- /* only bch is transparent */
- recv_Bchannel(bch, hc->chan[ch].Zfill, false);
- }
-}
-
-
-/*
- * Interrupt handler
- */
-static void
-signal_state_up(struct dchannel *dch, int info, char *msg)
-{
- struct sk_buff *skb;
- int id, data = info;
-
- if (debug & DEBUG_HFCMULTI_STATE)
- printk(KERN_DEBUG "%s: %s\n", __func__, msg);
-
- id = TEI_SAPI | (GROUP_TEI << 8); /* manager address */
-
- skb = _alloc_mISDN_skb(MPH_INFORMATION_IND, id, sizeof(data), &data,
- GFP_ATOMIC);
- if (!skb)
- return;
- recv_Dchannel_skb(dch, skb);
-}
-
-static inline void
-handle_timer_irq(struct hfc_multi *hc)
-{
- int ch, temp;
- struct dchannel *dch;
- u_long flags;
-
- /* process queued resync jobs */
- if (hc->e1_resync) {
- /* lock, so e1_resync gets not changed */
- spin_lock_irqsave(&HFClock, flags);
- if (hc->e1_resync & 1) {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "Enable SYNC_I\n");
- HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC);
- /* disable JATT, if RX_SYNC is set */
- if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip))
- HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX);
- }
- if (hc->e1_resync & 2) {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "Enable jatt PLL\n");
- HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS);
- }
- if (hc->e1_resync & 4) {
- if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG
- "Enable QUARTZ for HFC-E1\n");
- /* set jatt to quartz */
- HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC
- | V_JATT_OFF);
- /* switch to JATT, in case it is not already */
- HFC_outb(hc, R_SYNC_OUT, 0);
- }
- hc->e1_resync = 0;
- spin_unlock_irqrestore(&HFClock, flags);
- }
-
- if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1)
- for (ch = 0; ch <= 31; ch++) {
- if (hc->created[hc->chan[ch].port]) {
- hfcmulti_tx(hc, ch);
- /* fifo is started when switching to rx-fifo */
- hfcmulti_rx(hc, ch);
- if (hc->chan[ch].dch &&
- hc->chan[ch].nt_timer > -1) {
- dch = hc->chan[ch].dch;
- if (!(--hc->chan[ch].nt_timer)) {
- schedule_event(dch,
- FLG_PHCHANGE);
- if (debug &
- DEBUG_HFCMULTI_STATE)
- printk(KERN_DEBUG
- "%s: nt_timer at "
- "state %x\n",
- __func__,
- dch->state);
- }
- }
- }
- }
- if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) {
- dch = hc->chan[hc->dnum[0]].dch;
- /* LOS */
- temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS;
- hc->chan[hc->dnum[0]].los = temp;
- if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) {
- if (!temp && hc->chan[hc->dnum[0]].los)
- signal_state_up(dch, L1_SIGNAL_LOS_ON,
- "LOS detected");
- if (temp && !hc->chan[hc->dnum[0]].los)
- signal_state_up(dch, L1_SIGNAL_LOS_OFF,
- "LOS gone");
- }
- if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dnum[0]].cfg)) {
- /* AIS */
- temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS;
- if (!temp && hc->chan[hc->dnum[0]].ais)
- signal_state_up(dch, L1_SIGNAL_AIS_ON,
- "AIS detected");
- if (temp && !hc->chan[hc->dnum[0]].ais)
- signal_state_up(dch, L1_SIGNAL_AIS_OFF,
- "AIS gone");
- hc->chan[hc->dnum[0]].ais = temp;
- }
- if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dnum[0]].cfg)) {
- /* SLIP */
- temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX;
- if (!temp && hc->chan[hc->dnum[0]].slip_rx)
- signal_state_up(dch, L1_SIGNAL_SLIP_RX,
- " bit SLIP detected RX");
- hc->chan[hc->dnum[0]].slip_rx = temp;
- temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX;
- if (!temp && hc->chan[hc->dnum[0]].slip_tx)
- signal_state_up(dch, L1_SIGNAL_SLIP_TX,
- " bit SLIP detected TX");
- hc->chan[hc->dnum[0]].slip_tx = temp;
- }
- if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dnum[0]].cfg)) {
- /* RDI */
- temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A;
- if (!temp && hc->chan[hc->dnum[0]].rdi)
- signal_state_up(dch, L1_SIGNAL_RDI_ON,
- "RDI detected");
- if (temp && !hc->chan[hc->dnum[0]].rdi)
- signal_state_up(dch, L1_SIGNAL_RDI_OFF,
- "RDI gone");
- hc->chan[hc->dnum[0]].rdi = temp;
- }
- temp = HFC_inb_nodebug(hc, R_JATT_DIR);
- switch (hc->chan[hc->dnum[0]].sync) {
- case 0:
- if ((temp & 0x60) == 0x60) {
- if (debug & DEBUG_HFCMULTI_SYNC)
- printk(KERN_DEBUG
- "%s: (id=%d) E1 now "
- "in clock sync\n",
- __func__, hc->id);
- HFC_outb(hc, R_RX_OFF,
- hc->chan[hc->dnum[0]].jitter | V_RX_INIT);
- HFC_outb(hc, R_TX_OFF,
- hc->chan[hc->dnum[0]].jitter | V_RX_INIT);
- hc->chan[hc->dnum[0]].sync = 1;
- goto check_framesync;
- }
- break;
- case 1:
- if ((temp & 0x60) != 0x60) {
- if (debug & DEBUG_HFCMULTI_SYNC)
- printk(KERN_DEBUG
- "%s: (id=%d) E1 "
- "lost clock sync\n",
- __func__, hc->id);
- hc->chan[hc->dnum[0]].sync = 0;
- break;
- }
- check_framesync:
- temp = HFC_inb_nodebug(hc, R_SYNC_STA);
- if (temp == 0x27) {
- if (debug & DEBUG_HFCMULTI_SYNC)
- printk(KERN_DEBUG
- "%s: (id=%d) E1 "
- "now in frame sync\n",
- __func__, hc->id);
- hc->chan[hc->dnum[0]].sync = 2;
- }
- break;
- case 2:
- if ((temp & 0x60) != 0x60) {
- if (debug & DEBUG_HFCMULTI_SYNC)
- printk(KERN_DEBUG
- "%s: (id=%d) E1 lost "
- "clock & frame sync\n",
- __func__, hc->id);
- hc->chan[hc->dnum[0]].sync = 0;
- break;
- }
- temp = HFC_inb_nodebug(hc, R_SYNC_STA);
- if (temp != 0x27) {
- if (debug & DEBUG_HFCMULTI_SYNC)
- printk(KERN_DEBUG
- "%s: (id=%d) E1 "
- "lost frame sync\n",
- __func__, hc->id);
- hc->chan[hc->dnum[0]].sync = 1;
- }
- break;
- }
- }
-
- if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip))
- hfcmulti_watchdog(hc);
-
- if (hc->leds)
- hfcmulti_leds(hc);
-}
-
-static void
-ph_state_irq(struct hfc_multi *hc, u_char r_irq_statech)
-{
- struct dchannel *dch;
- int ch;
- int active;
- u_char st_status, temp;
-
- /* state machine */
- for (ch = 0; ch <= 31; ch++) {
- if (hc->chan[ch].dch) {
- dch = hc->chan[ch].dch;
- if (r_irq_statech & 1) {
- HFC_outb_nodebug(hc, R_ST_SEL,
- hc->chan[ch].port);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- /* undocumented: status changes during read */
- st_status = HFC_inb_nodebug(hc, A_ST_RD_STATE);
- while (st_status != (temp =
- HFC_inb_nodebug(hc, A_ST_RD_STATE))) {
- if (debug & DEBUG_HFCMULTI_STATE)
- printk(KERN_DEBUG "%s: reread "
- "STATE because %d!=%d\n",
- __func__, temp,
- st_status);
- st_status = temp; /* repeat */
- }
-
- /* Speech Design TE-sync indication */
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip) &&
- dch->dev.D.protocol == ISDN_P_TE_S0) {
- if (st_status & V_FR_SYNC_ST)
- hc->syncronized |=
- (1 << hc->chan[ch].port);
- else
- hc->syncronized &=
- ~(1 << hc->chan[ch].port);
- }
- dch->state = st_status & 0x0f;
- if (dch->dev.D.protocol == ISDN_P_NT_S0)
- active = 3;
- else
- active = 7;
- if (dch->state == active) {
- HFC_outb_nodebug(hc, R_FIFO,
- (ch << 1) | 1);
- HFC_wait_nodebug(hc);
- HFC_outb_nodebug(hc,
- R_INC_RES_FIFO, V_RES_F);
- HFC_wait_nodebug(hc);
- dch->tx_idx = 0;
- }
- schedule_event(dch, FLG_PHCHANGE);
- if (debug & DEBUG_HFCMULTI_STATE)
- printk(KERN_DEBUG
- "%s: S/T newstate %x port %d\n",
- __func__, dch->state,
- hc->chan[ch].port);
- }
- r_irq_statech >>= 1;
- }
- }
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip))
- plxsd_checksync(hc, 0);
-}
-
-static void
-fifo_irq(struct hfc_multi *hc, int block)
-{
- int ch, j;
- struct dchannel *dch;
- struct bchannel *bch;
- u_char r_irq_fifo_bl;
-
- r_irq_fifo_bl = HFC_inb_nodebug(hc, R_IRQ_FIFO_BL0 + block);
- j = 0;
- while (j < 8) {
- ch = (block << 2) + (j >> 1);
- dch = hc->chan[ch].dch;
- bch = hc->chan[ch].bch;
- if (((!dch) && (!bch)) || (!hc->created[hc->chan[ch].port])) {
- j += 2;
- continue;
- }
- if (dch && (r_irq_fifo_bl & (1 << j)) &&
- test_bit(FLG_ACTIVE, &dch->Flags)) {
- hfcmulti_tx(hc, ch);
- /* start fifo */
- HFC_outb_nodebug(hc, R_FIFO, 0);
- HFC_wait_nodebug(hc);
- }
- if (bch && (r_irq_fifo_bl & (1 << j)) &&
- test_bit(FLG_ACTIVE, &bch->Flags)) {
- hfcmulti_tx(hc, ch);
- /* start fifo */
- HFC_outb_nodebug(hc, R_FIFO, 0);
- HFC_wait_nodebug(hc);
- }
- j++;
- if (dch && (r_irq_fifo_bl & (1 << j)) &&
- test_bit(FLG_ACTIVE, &dch->Flags)) {
- hfcmulti_rx(hc, ch);
- }
- if (bch && (r_irq_fifo_bl & (1 << j)) &&
- test_bit(FLG_ACTIVE, &bch->Flags)) {
- hfcmulti_rx(hc, ch);
- }
- j++;
- }
-}
-
-#ifdef IRQ_DEBUG
-int irqsem;
-#endif
-static irqreturn_t
-hfcmulti_interrupt(int intno, void *dev_id)
-{
-#ifdef IRQCOUNT_DEBUG
- static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0,
- iq5 = 0, iq6 = 0, iqcnt = 0;
-#endif
- struct hfc_multi *hc = dev_id;
- struct dchannel *dch;
- u_char r_irq_statech, status, r_irq_misc, r_irq_oview;
- int i;
- void __iomem *plx_acc;
- u_short wval;
- u_char e1_syncsta, temp, temp2;
- u_long flags;
-
- if (!hc) {
- printk(KERN_ERR "HFC-multi: Spurious interrupt!\n");
- return IRQ_NONE;
- }
-
- spin_lock(&hc->lock);
-
-#ifdef IRQ_DEBUG
- if (irqsem)
- printk(KERN_ERR "irq for card %d during irq from "
- "card %d, this is no bug.\n", hc->id + 1, irqsem);
- irqsem = hc->id + 1;
-#endif
-#ifdef CONFIG_MISDN_HFCMULTI_8xx
- if (hc->immap->im_cpm.cp_pbdat & hc->pb_irqmsk)
- goto irq_notforus;
-#endif
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- spin_lock_irqsave(&plx_lock, flags);
- plx_acc = hc->plx_membase + PLX_INTCSR;
- wval = readw(plx_acc);
- spin_unlock_irqrestore(&plx_lock, flags);
- if (!(wval & PLX_INTCSR_LINTI1_STATUS))
- goto irq_notforus;
- }
-
- status = HFC_inb_nodebug(hc, R_STATUS);
- r_irq_statech = HFC_inb_nodebug(hc, R_IRQ_STATECH);
-#ifdef IRQCOUNT_DEBUG
- if (r_irq_statech)
- iq1++;
- if (status & V_DTMF_STA)
- iq2++;
- if (status & V_LOST_STA)
- iq3++;
- if (status & V_EXT_IRQSTA)
- iq4++;
- if (status & V_MISC_IRQSTA)
- iq5++;
- if (status & V_FR_IRQSTA)
- iq6++;
- if (iqcnt++ > 5000) {
- printk(KERN_ERR "iq1:%x iq2:%x iq3:%x iq4:%x iq5:%x iq6:%x\n",
- iq1, iq2, iq3, iq4, iq5, iq6);
- iqcnt = 0;
- }
-#endif
-
- if (!r_irq_statech &&
- !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA |
- V_MISC_IRQSTA | V_FR_IRQSTA))) {
- /* irq is not for us */
- goto irq_notforus;
- }
- hc->irqcnt++;
- if (r_irq_statech) {
- if (hc->ctype != HFC_TYPE_E1)
- ph_state_irq(hc, r_irq_statech);
- }
- if (status & V_LOST_STA) {
- /* LOST IRQ */
- HFC_outb(hc, R_INC_RES_FIFO, V_RES_LOST); /* clear irq! */
- }
- if (status & V_MISC_IRQSTA) {
- /* misc IRQ */
- r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC);
- r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */
- if (r_irq_misc & V_STA_IRQ) {
- if (hc->ctype == HFC_TYPE_E1) {
- /* state machine */
- dch = hc->chan[hc->dnum[0]].dch;
- e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA);
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)
- && hc->e1_getclock) {
- if (e1_syncsta & V_FR_SYNC_E1)
- hc->syncronized = 1;
- else
- hc->syncronized = 0;
- }
- /* undocumented: status changes during read */
- temp = HFC_inb_nodebug(hc, R_E1_RD_STA);
- while (temp != (temp2 =
- HFC_inb_nodebug(hc, R_E1_RD_STA))) {
- if (debug & DEBUG_HFCMULTI_STATE)
- printk(KERN_DEBUG "%s: reread "
- "STATE because %d!=%d\n",
- __func__, temp, temp2);
- temp = temp2; /* repeat */
- }
- /* broadcast state change to all fragments */
- if (debug & DEBUG_HFCMULTI_STATE)
- printk(KERN_DEBUG
- "%s: E1 (id=%d) newstate %x\n",
- __func__, hc->id, temp & 0x7);
- for (i = 0; i < hc->ports; i++) {
- dch = hc->chan[hc->dnum[i]].dch;
- dch->state = temp & 0x7;
- schedule_event(dch, FLG_PHCHANGE);
- }
-
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip))
- plxsd_checksync(hc, 0);
- }
- }
- if (r_irq_misc & V_TI_IRQ) {
- if (hc->iclock_on)
- mISDN_clock_update(hc->iclock, poll, NULL);
- handle_timer_irq(hc);
- }
-
- if (r_irq_misc & V_DTMF_IRQ)
- hfcmulti_dtmf(hc);
-
- if (r_irq_misc & V_IRQ_PROC) {
- static int irq_proc_cnt;
- if (!irq_proc_cnt++)
- printk(KERN_DEBUG "%s: got V_IRQ_PROC -"
- " this should not happen\n", __func__);
- }
-
- }
- if (status & V_FR_IRQSTA) {
- /* FIFO IRQ */
- r_irq_oview = HFC_inb_nodebug(hc, R_IRQ_OVIEW);
- for (i = 0; i < 8; i++) {
- if (r_irq_oview & (1 << i))
- fifo_irq(hc, i);
- }
- }
-
-#ifdef IRQ_DEBUG
- irqsem = 0;
-#endif
- spin_unlock(&hc->lock);
- return IRQ_HANDLED;
-
-irq_notforus:
-#ifdef IRQ_DEBUG
- irqsem = 0;
-#endif
- spin_unlock(&hc->lock);
- return IRQ_NONE;
-}
-
-
-/*
- * timer callback for D-chan busy resolution. Currently no function
- */
-
-static void
-hfcmulti_dbusy_timer(struct timer_list *t)
-{
-}
-
-
-/*
- * activate/deactivate hardware for selected channels and mode
- *
- * configure B-channel with the given protocol
- * ch eqals to the HFC-channel (0-31)
- * ch is the number of channel (0-4,4-7,8-11,12-15,16-19,20-23,24-27,28-31
- * for S/T, 1-31 for E1)
- * the hdlc interrupts will be set/unset
- */
-static int
-mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
- int bank_tx, int slot_rx, int bank_rx)
-{
- int flow_tx = 0, flow_rx = 0, routing = 0;
- int oslot_tx, oslot_rx;
- int conf;
-
- if (ch < 0 || ch > 31)
- return -EINVAL;
- oslot_tx = hc->chan[ch].slot_tx;
- oslot_rx = hc->chan[ch].slot_rx;
- conf = hc->chan[ch].conf;
-
- if (debug & DEBUG_HFCMULTI_MODE)
- printk(KERN_DEBUG
- "%s: card %d channel %d protocol %x slot old=%d new=%d "
- "bank new=%d (TX) slot old=%d new=%d bank new=%d (RX)\n",
- __func__, hc->id, ch, protocol, oslot_tx, slot_tx,
- bank_tx, oslot_rx, slot_rx, bank_rx);
-
- if (oslot_tx >= 0 && slot_tx != oslot_tx) {
- /* remove from slot */
- if (debug & DEBUG_HFCMULTI_MODE)
- printk(KERN_DEBUG "%s: remove from slot %d (TX)\n",
- __func__, oslot_tx);
- if (hc->slot_owner[oslot_tx << 1] == ch) {
- HFC_outb(hc, R_SLOT, oslot_tx << 1);
- HFC_outb(hc, A_SL_CFG, 0);
- if (hc->ctype != HFC_TYPE_XHFC)
- HFC_outb(hc, A_CONF, 0);
- hc->slot_owner[oslot_tx << 1] = -1;
- } else {
- if (debug & DEBUG_HFCMULTI_MODE)
- printk(KERN_DEBUG
- "%s: we are not owner of this tx slot "
- "anymore, channel %d is.\n",
- __func__, hc->slot_owner[oslot_tx << 1]);
- }
- }
-
- if (oslot_rx >= 0 && slot_rx != oslot_rx) {
- /* remove from slot */
- if (debug & DEBUG_HFCMULTI_MODE)
- printk(KERN_DEBUG
- "%s: remove from slot %d (RX)\n",
- __func__, oslot_rx);
- if (hc->slot_owner[(oslot_rx << 1) | 1] == ch) {
- HFC_outb(hc, R_SLOT, (oslot_rx << 1) | V_SL_DIR);
- HFC_outb(hc, A_SL_CFG, 0);
- hc->slot_owner[(oslot_rx << 1) | 1] = -1;
- } else {
- if (debug & DEBUG_HFCMULTI_MODE)
- printk(KERN_DEBUG
- "%s: we are not owner of this rx slot "
- "anymore, channel %d is.\n",
- __func__,
- hc->slot_owner[(oslot_rx << 1) | 1]);
- }
- }
-
- if (slot_tx < 0) {
- flow_tx = 0x80; /* FIFO->ST */
- /* disable pcm slot */
- hc->chan[ch].slot_tx = -1;
- hc->chan[ch].bank_tx = 0;
- } else {
- /* set pcm slot */
- if (hc->chan[ch].txpending)
- flow_tx = 0x80; /* FIFO->ST */
- else
- flow_tx = 0xc0; /* PCM->ST */
- /* put on slot */
- routing = bank_tx ? 0xc0 : 0x80;
- if (conf >= 0 || bank_tx > 1)
- routing = 0x40; /* loop */
- if (debug & DEBUG_HFCMULTI_MODE)
- printk(KERN_DEBUG "%s: put channel %d to slot %d bank"
- " %d flow %02x routing %02x conf %d (TX)\n",
- __func__, ch, slot_tx, bank_tx,
- flow_tx, routing, conf);
- HFC_outb(hc, R_SLOT, slot_tx << 1);
- HFC_outb(hc, A_SL_CFG, (ch << 1) | routing);
- if (hc->ctype != HFC_TYPE_XHFC)
- HFC_outb(hc, A_CONF,
- (conf < 0) ? 0 : (conf | V_CONF_SL));
- hc->slot_owner[slot_tx << 1] = ch;
- hc->chan[ch].slot_tx = slot_tx;
- hc->chan[ch].bank_tx = bank_tx;
- }
- if (slot_rx < 0) {
- /* disable pcm slot */
- flow_rx = 0x80; /* ST->FIFO */
- hc->chan[ch].slot_rx = -1;
- hc->chan[ch].bank_rx = 0;
- } else {
- /* set pcm slot */
- if (hc->chan[ch].txpending)
- flow_rx = 0x80; /* ST->FIFO */
- else
- flow_rx = 0xc0; /* ST->(FIFO,PCM) */
- /* put on slot */
- routing = bank_rx ? 0x80 : 0xc0; /* reversed */
- if (conf >= 0 || bank_rx > 1)
- routing = 0x40; /* loop */
- if (debug & DEBUG_HFCMULTI_MODE)
- printk(KERN_DEBUG "%s: put channel %d to slot %d bank"
- " %d flow %02x routing %02x conf %d (RX)\n",
- __func__, ch, slot_rx, bank_rx,
- flow_rx, routing, conf);
- HFC_outb(hc, R_SLOT, (slot_rx << 1) | V_SL_DIR);
- HFC_outb(hc, A_SL_CFG, (ch << 1) | V_CH_DIR | routing);
- hc->slot_owner[(slot_rx << 1) | 1] = ch;
- hc->chan[ch].slot_rx = slot_rx;
- hc->chan[ch].bank_rx = bank_rx;
- }
-
- switch (protocol) {
- case (ISDN_P_NONE):
- /* disable TX fifo */
- HFC_outb(hc, R_FIFO, ch << 1);
- HFC_wait(hc);
- HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_IFF);
- HFC_outb(hc, A_SUBCH_CFG, 0);
- HFC_outb(hc, A_IRQ_MSK, 0);
- HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
- HFC_wait(hc);
- /* disable RX fifo */
- HFC_outb(hc, R_FIFO, (ch << 1) | 1);
- HFC_wait(hc);
- HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00);
- HFC_outb(hc, A_SUBCH_CFG, 0);
- HFC_outb(hc, A_IRQ_MSK, 0);
- HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
- HFC_wait(hc);
- if (hc->chan[ch].bch && hc->ctype != HFC_TYPE_E1) {
- hc->hw.a_st_ctrl0[hc->chan[ch].port] &=
- ((ch & 0x3) == 0) ? ~V_B1_EN : ~V_B2_EN;
- HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- HFC_outb(hc, A_ST_CTRL0,
- hc->hw.a_st_ctrl0[hc->chan[ch].port]);
- }
- if (hc->chan[ch].bch) {
- test_and_clear_bit(FLG_HDLC, &hc->chan[ch].bch->Flags);
- test_and_clear_bit(FLG_TRANSPARENT,
- &hc->chan[ch].bch->Flags);
- }
- break;
- case (ISDN_P_B_RAW): /* B-channel */
-
- if (test_bit(HFC_CHIP_B410P, &hc->chip) &&
- (hc->chan[ch].slot_rx < 0) &&
- (hc->chan[ch].slot_tx < 0)) {
-
- printk(KERN_DEBUG
- "Setting B-channel %d to echo cancelable "
- "state on PCM slot %d\n", ch,
- ((ch / 4) * 8) + ((ch % 4) * 4) + 1);
- printk(KERN_DEBUG
- "Enabling pass through for channel\n");
- vpm_out(hc, ch, ((ch / 4) * 8) +
- ((ch % 4) * 4) + 1, 0x01);
- /* rx path */
- /* S/T -> PCM */
- HFC_outb(hc, R_FIFO, (ch << 1));
- HFC_wait(hc);
- HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF);
- HFC_outb(hc, R_SLOT, (((ch / 4) * 8) +
- ((ch % 4) * 4) + 1) << 1);
- HFC_outb(hc, A_SL_CFG, 0x80 | (ch << 1));
-
- /* PCM -> FIFO */
- HFC_outb(hc, R_FIFO, 0x20 | (ch << 1) | 1);
- HFC_wait(hc);
- HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF);
- HFC_outb(hc, A_SUBCH_CFG, 0);
- HFC_outb(hc, A_IRQ_MSK, 0);
- if (hc->chan[ch].protocol != protocol) {
- HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
- HFC_wait(hc);
- }
- HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) +
- ((ch % 4) * 4) + 1) << 1) | 1);
- HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1);
-
- /* tx path */
- /* PCM -> S/T */
- HFC_outb(hc, R_FIFO, (ch << 1) | 1);
- HFC_wait(hc);
- HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF);
- HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) +
- ((ch % 4) * 4)) << 1) | 1);
- HFC_outb(hc, A_SL_CFG, 0x80 | 0x40 | (ch << 1) | 1);
-
- /* FIFO -> PCM */
- HFC_outb(hc, R_FIFO, 0x20 | (ch << 1));
- HFC_wait(hc);
- HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF);
- HFC_outb(hc, A_SUBCH_CFG, 0);
- HFC_outb(hc, A_IRQ_MSK, 0);
- if (hc->chan[ch].protocol != protocol) {
- HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
- HFC_wait(hc);
- }
- /* tx silence */
- HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
- HFC_outb(hc, R_SLOT, (((ch / 4) * 8) +
- ((ch % 4) * 4)) << 1);
- HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1));
- } else {
- /* enable TX fifo */
- HFC_outb(hc, R_FIFO, ch << 1);
- HFC_wait(hc);
- if (hc->ctype == HFC_TYPE_XHFC)
- HFC_outb(hc, A_CON_HDLC, flow_tx | 0x07 << 2 |
- V_HDLC_TRP | V_IFF);
- /* Enable FIFO, no interrupt */
- else
- HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 |
- V_HDLC_TRP | V_IFF);
- HFC_outb(hc, A_SUBCH_CFG, 0);
- HFC_outb(hc, A_IRQ_MSK, 0);
- if (hc->chan[ch].protocol != protocol) {
- HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
- HFC_wait(hc);
- }
- /* tx silence */
- HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
- /* enable RX fifo */
- HFC_outb(hc, R_FIFO, (ch << 1) | 1);
- HFC_wait(hc);
- if (hc->ctype == HFC_TYPE_XHFC)
- HFC_outb(hc, A_CON_HDLC, flow_rx | 0x07 << 2 |
- V_HDLC_TRP);
- /* Enable FIFO, no interrupt*/
- else
- HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 |
- V_HDLC_TRP);
- HFC_outb(hc, A_SUBCH_CFG, 0);
- HFC_outb(hc, A_IRQ_MSK, 0);
- if (hc->chan[ch].protocol != protocol) {
- HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
- HFC_wait(hc);
- }
- }
- if (hc->ctype != HFC_TYPE_E1) {
- hc->hw.a_st_ctrl0[hc->chan[ch].port] |=
- ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN;
- HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- HFC_outb(hc, A_ST_CTRL0,
- hc->hw.a_st_ctrl0[hc->chan[ch].port]);
- }
- if (hc->chan[ch].bch)
- test_and_set_bit(FLG_TRANSPARENT,
- &hc->chan[ch].bch->Flags);
- break;
- case (ISDN_P_B_HDLC): /* B-channel */
- case (ISDN_P_TE_S0): /* D-channel */
- case (ISDN_P_NT_S0):
- case (ISDN_P_TE_E1):
- case (ISDN_P_NT_E1):
- /* enable TX fifo */
- HFC_outb(hc, R_FIFO, ch << 1);
- HFC_wait(hc);
- if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) {
- /* E1 or B-channel */
- HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04);
- HFC_outb(hc, A_SUBCH_CFG, 0);
- } else {
- /* D-Channel without HDLC fill flags */
- HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04 | V_IFF);
- HFC_outb(hc, A_SUBCH_CFG, 2);
- }
- HFC_outb(hc, A_IRQ_MSK, V_IRQ);
- HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
- HFC_wait(hc);
- /* enable RX fifo */
- HFC_outb(hc, R_FIFO, (ch << 1) | 1);
- HFC_wait(hc);
- HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04);
- if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch)
- HFC_outb(hc, A_SUBCH_CFG, 0); /* full 8 bits */
- else
- HFC_outb(hc, A_SUBCH_CFG, 2); /* 2 bits dchannel */
- HFC_outb(hc, A_IRQ_MSK, V_IRQ);
- HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
- HFC_wait(hc);
- if (hc->chan[ch].bch) {
- test_and_set_bit(FLG_HDLC, &hc->chan[ch].bch->Flags);
- if (hc->ctype != HFC_TYPE_E1) {
- hc->hw.a_st_ctrl0[hc->chan[ch].port] |=
- ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN;
- HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- HFC_outb(hc, A_ST_CTRL0,
- hc->hw.a_st_ctrl0[hc->chan[ch].port]);
- }
- }
- break;
- default:
- printk(KERN_DEBUG "%s: protocol not known %x\n",
- __func__, protocol);
- hc->chan[ch].protocol = ISDN_P_NONE;
- return -ENOPROTOOPT;
- }
- hc->chan[ch].protocol = protocol;
- return 0;
-}
-
-
-/*
- * connect/disconnect PCM
- */
-
-static void
-hfcmulti_pcm(struct hfc_multi *hc, int ch, int slot_tx, int bank_tx,
- int slot_rx, int bank_rx)
-{
- if (slot_tx < 0 || slot_rx < 0 || bank_tx < 0 || bank_rx < 0) {
- /* disable PCM */
- mode_hfcmulti(hc, ch, hc->chan[ch].protocol, -1, 0, -1, 0);
- return;
- }
-
- /* enable pcm */
- mode_hfcmulti(hc, ch, hc->chan[ch].protocol, slot_tx, bank_tx,
- slot_rx, bank_rx);
-}
-
-/*
- * set/disable conference
- */
-
-static void
-hfcmulti_conf(struct hfc_multi *hc, int ch, int num)
-{
- if (num >= 0 && num <= 7)
- hc->chan[ch].conf = num;
- else
- hc->chan[ch].conf = -1;
- mode_hfcmulti(hc, ch, hc->chan[ch].protocol, hc->chan[ch].slot_tx,
- hc->chan[ch].bank_tx, hc->chan[ch].slot_rx,
- hc->chan[ch].bank_rx);
-}
-
-
-/*
- * set/disable sample loop
- */
-
-/* NOTE: this function is experimental and therefore disabled */
-
-/*
- * Layer 1 callback function
- */
-static int
-hfcm_l1callback(struct dchannel *dch, u_int cmd)
-{
- struct hfc_multi *hc = dch->hw;
- struct sk_buff_head free_queue;
- u_long flags;
-
- switch (cmd) {
- case INFO3_P8:
- case INFO3_P10:
- break;
- case HW_RESET_REQ:
- /* start activation */
- spin_lock_irqsave(&hc->lock, flags);
- if (hc->ctype == HFC_TYPE_E1) {
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG
- "%s: HW_RESET_REQ no BRI\n",
- __func__);
- } else {
- HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 3); /* F3 */
- udelay(6); /* wait at least 5,21us */
- HFC_outb(hc, A_ST_WR_STATE, 3);
- HFC_outb(hc, A_ST_WR_STATE, 3 | (V_ST_ACT * 3));
- /* activate */
- }
- spin_unlock_irqrestore(&hc->lock, flags);
- l1_event(dch->l1, HW_POWERUP_IND);
- break;
- case HW_DEACT_REQ:
- __skb_queue_head_init(&free_queue);
- /* start deactivation */
- spin_lock_irqsave(&hc->lock, flags);
- if (hc->ctype == HFC_TYPE_E1) {
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG
- "%s: HW_DEACT_REQ no BRI\n",
- __func__);
- } else {
- HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2);
- /* deactivate */
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- hc->syncronized &=
- ~(1 << hc->chan[dch->slot].port);
- plxsd_checksync(hc, 0);
- }
- }
- skb_queue_splice_init(&dch->squeue, &free_queue);
- if (dch->tx_skb) {
- __skb_queue_tail(&free_queue, dch->tx_skb);
- dch->tx_skb = NULL;
- }
- dch->tx_idx = 0;
- if (dch->rx_skb) {
- __skb_queue_tail(&free_queue, dch->rx_skb);
- dch->rx_skb = NULL;
- }
- test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
- if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
- timer_delete(&dch->timer);
- spin_unlock_irqrestore(&hc->lock, flags);
- __skb_queue_purge(&free_queue);
- break;
- case HW_POWERUP_REQ:
- spin_lock_irqsave(&hc->lock, flags);
- if (hc->ctype == HFC_TYPE_E1) {
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG
- "%s: HW_POWERUP_REQ no BRI\n",
- __func__);
- } else {
- HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- HFC_outb(hc, A_ST_WR_STATE, 3 | 0x10); /* activate */
- udelay(6); /* wait at least 5,21us */
- HFC_outb(hc, A_ST_WR_STATE, 3); /* activate */
- }
- spin_unlock_irqrestore(&hc->lock, flags);
- break;
- case PH_ACTIVATE_IND:
- test_and_set_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
- GFP_ATOMIC);
- break;
- case PH_DEACTIVATE_IND:
- test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
- GFP_ATOMIC);
- break;
- default:
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: unknown command %x\n",
- __func__, cmd);
- return -1;
- }
- return 0;
-}
-
-/*
- * Layer2 -> Layer 1 Transfer
- */
-
-static int
-handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct hfc_multi *hc = dch->hw;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- int ret = -EINVAL;
- unsigned int id;
- u_long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- if (skb->len < 1)
- break;
- spin_lock_irqsave(&hc->lock, flags);
- ret = dchannel_senddata(dch, skb);
- if (ret > 0) { /* direct TX */
- id = hh->id; /* skb can be freed */
- hfcmulti_tx(hc, dch->slot);
- ret = 0;
- /* start fifo */
- HFC_outb(hc, R_FIFO, 0);
- HFC_wait(hc);
- spin_unlock_irqrestore(&hc->lock, flags);
- queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
- } else
- spin_unlock_irqrestore(&hc->lock, flags);
- return ret;
- case PH_ACTIVATE_REQ:
- if (dch->dev.D.protocol != ISDN_P_TE_S0) {
- spin_lock_irqsave(&hc->lock, flags);
- ret = 0;
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG
- "%s: PH_ACTIVATE port %d (0..%d)\n",
- __func__, hc->chan[dch->slot].port,
- hc->ports - 1);
- /* start activation */
- if (hc->ctype == HFC_TYPE_E1) {
- ph_state_change(dch);
- if (debug & DEBUG_HFCMULTI_STATE)
- printk(KERN_DEBUG
- "%s: E1 report state %x \n",
- __func__, dch->state);
- } else {
- HFC_outb(hc, R_ST_SEL,
- hc->chan[dch->slot].port);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1);
- /* G1 */
- udelay(6); /* wait at least 5,21us */
- HFC_outb(hc, A_ST_WR_STATE, 1);
- HFC_outb(hc, A_ST_WR_STATE, 1 |
- (V_ST_ACT * 3)); /* activate */
- dch->state = 1;
- }
- spin_unlock_irqrestore(&hc->lock, flags);
- } else
- ret = l1_event(dch->l1, hh->prim);
- break;
- case PH_DEACTIVATE_REQ:
- test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
- if (dch->dev.D.protocol != ISDN_P_TE_S0) {
- struct sk_buff_head free_queue;
-
- __skb_queue_head_init(&free_queue);
- spin_lock_irqsave(&hc->lock, flags);
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG
- "%s: PH_DEACTIVATE port %d (0..%d)\n",
- __func__, hc->chan[dch->slot].port,
- hc->ports - 1);
- /* start deactivation */
- if (hc->ctype == HFC_TYPE_E1) {
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG
- "%s: PH_DEACTIVATE no BRI\n",
- __func__);
- } else {
- HFC_outb(hc, R_ST_SEL,
- hc->chan[dch->slot].port);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2);
- /* deactivate */
- dch->state = 1;
- }
- skb_queue_splice_init(&dch->squeue, &free_queue);
- if (dch->tx_skb) {
- __skb_queue_tail(&free_queue, dch->tx_skb);
- dch->tx_skb = NULL;
- }
- dch->tx_idx = 0;
- if (dch->rx_skb) {
- __skb_queue_tail(&free_queue, dch->rx_skb);
- dch->rx_skb = NULL;
- }
- test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
- if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
- timer_delete(&dch->timer);
-#ifdef FIXME
- if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
- dchannel_sched_event(&hc->dch, D_CLEARBUSY);
-#endif
- ret = 0;
- spin_unlock_irqrestore(&hc->lock, flags);
- __skb_queue_purge(&free_queue);
- } else
- ret = l1_event(dch->l1, hh->prim);
- break;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static void
-deactivate_bchannel(struct bchannel *bch)
-{
- struct hfc_multi *hc = bch->hw;
- u_long flags;
-
- spin_lock_irqsave(&hc->lock, flags);
- mISDN_clear_bchannel(bch);
- hc->chan[bch->slot].coeff_count = 0;
- hc->chan[bch->slot].rx_off = 0;
- hc->chan[bch->slot].conf = -1;
- mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0);
- spin_unlock_irqrestore(&hc->lock, flags);
-}
-
-static int
-handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct hfc_multi *hc = bch->hw;
- int ret = -EINVAL;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- unsigned long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- if (!skb->len)
- break;
- spin_lock_irqsave(&hc->lock, flags);
- ret = bchannel_senddata(bch, skb);
- if (ret > 0) { /* direct TX */
- hfcmulti_tx(hc, bch->slot);
- ret = 0;
- /* start fifo */
- HFC_outb_nodebug(hc, R_FIFO, 0);
- HFC_wait_nodebug(hc);
- }
- spin_unlock_irqrestore(&hc->lock, flags);
- return ret;
- case PH_ACTIVATE_REQ:
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n",
- __func__, bch->slot);
- spin_lock_irqsave(&hc->lock, flags);
- /* activate B-channel if not already activated */
- if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
- hc->chan[bch->slot].txpending = 0;
- ret = mode_hfcmulti(hc, bch->slot,
- ch->protocol,
- hc->chan[bch->slot].slot_tx,
- hc->chan[bch->slot].bank_tx,
- hc->chan[bch->slot].slot_rx,
- hc->chan[bch->slot].bank_rx);
- if (!ret) {
- if (ch->protocol == ISDN_P_B_RAW && !hc->dtmf
- && test_bit(HFC_CHIP_DTMF, &hc->chip)) {
- /* start decoder */
- hc->dtmf = 1;
- if (debug & DEBUG_HFCMULTI_DTMF)
- printk(KERN_DEBUG
- "%s: start dtmf decoder\n",
- __func__);
- HFC_outb(hc, R_DTMF, hc->hw.r_dtmf |
- V_RST_DTMF);
- }
- }
- } else
- ret = 0;
- spin_unlock_irqrestore(&hc->lock, flags);
- if (!ret)
- _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL,
- GFP_KERNEL);
- break;
- case PH_CONTROL_REQ:
- spin_lock_irqsave(&hc->lock, flags);
- switch (hh->id) {
- case HFC_SPL_LOOP_ON: /* set sample loop */
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG
- "%s: HFC_SPL_LOOP_ON (len = %d)\n",
- __func__, skb->len);
- ret = 0;
- break;
- case HFC_SPL_LOOP_OFF: /* set silence */
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG "%s: HFC_SPL_LOOP_OFF\n",
- __func__);
- ret = 0;
- break;
- default:
- printk(KERN_ERR
- "%s: unknown PH_CONTROL_REQ info %x\n",
- __func__, hh->id);
- ret = -EINVAL;
- }
- spin_unlock_irqrestore(&hc->lock, flags);
- break;
- case PH_DEACTIVATE_REQ:
- deactivate_bchannel(bch); /* locked there */
- _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL,
- GFP_KERNEL);
- ret = 0;
- break;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-/*
- * bchannel control function
- */
-static int
-channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
-{
- int ret = 0;
- struct dsp_features *features =
- (struct dsp_features *)(*((u_long *)&cq->p1));
- struct hfc_multi *hc = bch->hw;
- int slot_tx;
- int bank_tx;
- int slot_rx;
- int bank_rx;
- int num;
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- ret = mISDN_ctrl_bchannel(bch, cq);
- cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP;
- break;
- case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
- ret = mISDN_ctrl_bchannel(bch, cq);
- hc->chan[bch->slot].rx_off = !!cq->p1;
- if (!hc->chan[bch->slot].rx_off) {
- /* reset fifo on rx on */
- HFC_outb_nodebug(hc, R_FIFO, (bch->slot << 1) | 1);
- HFC_wait_nodebug(hc);
- HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F);
- HFC_wait_nodebug(hc);
- }
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n",
- __func__, bch->nr, hc->chan[bch->slot].rx_off);
- break;
- case MISDN_CTRL_FILL_EMPTY:
- ret = mISDN_ctrl_bchannel(bch, cq);
- hc->silence = bch->fill[0];
- memset(hc->silence_data, hc->silence, sizeof(hc->silence_data));
- break;
- case MISDN_CTRL_HW_FEATURES: /* fill features structure */
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG "%s: HW_FEATURE request\n",
- __func__);
- /* create confirm */
- features->hfc_id = hc->id;
- if (test_bit(HFC_CHIP_DTMF, &hc->chip))
- features->hfc_dtmf = 1;
- if (test_bit(HFC_CHIP_CONF, &hc->chip))
- features->hfc_conf = 1;
- features->hfc_loops = 0;
- if (test_bit(HFC_CHIP_B410P, &hc->chip)) {
- features->hfc_echocanhw = 1;
- } else {
- features->pcm_id = hc->pcm;
- features->pcm_slots = hc->slots;
- features->pcm_banks = 2;
- }
- break;
- case MISDN_CTRL_HFC_PCM_CONN: /* connect to pcm timeslot (0..N) */
- slot_tx = cq->p1 & 0xff;
- bank_tx = cq->p1 >> 8;
- slot_rx = cq->p2 & 0xff;
- bank_rx = cq->p2 >> 8;
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG
- "%s: HFC_PCM_CONN slot %d bank %d (TX) "
- "slot %d bank %d (RX)\n",
- __func__, slot_tx, bank_tx,
- slot_rx, bank_rx);
- if (slot_tx < hc->slots && bank_tx <= 2 &&
- slot_rx < hc->slots && bank_rx <= 2)
- hfcmulti_pcm(hc, bch->slot,
- slot_tx, bank_tx, slot_rx, bank_rx);
- else {
- printk(KERN_WARNING
- "%s: HFC_PCM_CONN slot %d bank %d (TX) "
- "slot %d bank %d (RX) out of range\n",
- __func__, slot_tx, bank_tx,
- slot_rx, bank_rx);
- ret = -EINVAL;
- }
- break;
- case MISDN_CTRL_HFC_PCM_DISC: /* release interface from pcm timeslot */
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG "%s: HFC_PCM_DISC\n",
- __func__);
- hfcmulti_pcm(hc, bch->slot, -1, 0, -1, 0);
- break;
- case MISDN_CTRL_HFC_CONF_JOIN: /* join conference (0..7) */
- num = cq->p1 & 0xff;
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG "%s: HFC_CONF_JOIN conf %d\n",
- __func__, num);
- if (num <= 7)
- hfcmulti_conf(hc, bch->slot, num);
- else {
- printk(KERN_WARNING
- "%s: HW_CONF_JOIN conf %d out of range\n",
- __func__, num);
- ret = -EINVAL;
- }
- break;
- case MISDN_CTRL_HFC_CONF_SPLIT: /* split conference */
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG "%s: HFC_CONF_SPLIT\n", __func__);
- hfcmulti_conf(hc, bch->slot, -1);
- break;
- case MISDN_CTRL_HFC_ECHOCAN_ON:
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG "%s: HFC_ECHOCAN_ON\n", __func__);
- if (test_bit(HFC_CHIP_B410P, &hc->chip))
- vpm_echocan_on(hc, bch->slot, cq->p1);
- else
- ret = -EINVAL;
- break;
-
- case MISDN_CTRL_HFC_ECHOCAN_OFF:
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG "%s: HFC_ECHOCAN_OFF\n",
- __func__);
- if (test_bit(HFC_CHIP_B410P, &hc->chip))
- vpm_echocan_off(hc, bch->slot);
- else
- ret = -EINVAL;
- break;
- default:
- ret = mISDN_ctrl_bchannel(bch, cq);
- break;
- }
- return ret;
-}
-
-static int
-hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct hfc_multi *hc = bch->hw;
- int err = -EINVAL;
- u_long flags;
-
- if (bch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: cmd:%x %p\n",
- __func__, cmd, arg);
- switch (cmd) {
- case CLOSE_CHANNEL:
- test_and_clear_bit(FLG_OPEN, &bch->Flags);
- deactivate_bchannel(bch); /* locked there */
- ch->protocol = ISDN_P_NONE;
- ch->peer = NULL;
- module_put(THIS_MODULE);
- err = 0;
- break;
- case CONTROL_CHANNEL:
- spin_lock_irqsave(&hc->lock, flags);
- err = channel_bctrl(bch, arg);
- spin_unlock_irqrestore(&hc->lock, flags);
- break;
- default:
- printk(KERN_WARNING "%s: unknown prim(%x)\n",
- __func__, cmd);
- }
- return err;
-}
-
-/*
- * handle D-channel events
- *
- * handle state change event
- */
-static void
-ph_state_change(struct dchannel *dch)
-{
- struct hfc_multi *hc;
- int ch, i;
-
- if (!dch) {
- printk(KERN_WARNING "%s: ERROR given dch is NULL\n", __func__);
- return;
- }
- hc = dch->hw;
- ch = dch->slot;
-
- if (hc->ctype == HFC_TYPE_E1) {
- if (dch->dev.D.protocol == ISDN_P_TE_E1) {
- if (debug & DEBUG_HFCMULTI_STATE)
- printk(KERN_DEBUG
- "%s: E1 TE (id=%d) newstate %x\n",
- __func__, hc->id, dch->state);
- } else {
- if (debug & DEBUG_HFCMULTI_STATE)
- printk(KERN_DEBUG
- "%s: E1 NT (id=%d) newstate %x\n",
- __func__, hc->id, dch->state);
- }
- switch (dch->state) {
- case (1):
- if (hc->e1_state != 1) {
- for (i = 1; i <= 31; i++) {
- /* reset fifos on e1 activation */
- HFC_outb_nodebug(hc, R_FIFO,
- (i << 1) | 1);
- HFC_wait_nodebug(hc);
- HFC_outb_nodebug(hc, R_INC_RES_FIFO,
- V_RES_F);
- HFC_wait_nodebug(hc);
- }
- }
- test_and_set_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, PH_ACTIVATE_IND,
- MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
- break;
-
- default:
- if (hc->e1_state != 1)
- return;
- test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, PH_DEACTIVATE_IND,
- MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
- }
- hc->e1_state = dch->state;
- } else {
- if (dch->dev.D.protocol == ISDN_P_TE_S0) {
- if (debug & DEBUG_HFCMULTI_STATE)
- printk(KERN_DEBUG
- "%s: S/T TE newstate %x\n",
- __func__, dch->state);
- switch (dch->state) {
- case (0):
- l1_event(dch->l1, HW_RESET_IND);
- break;
- case (3):
- l1_event(dch->l1, HW_DEACT_IND);
- break;
- case (5):
- case (8):
- l1_event(dch->l1, ANYSIGNAL);
- break;
- case (6):
- l1_event(dch->l1, INFO2);
- break;
- case (7):
- l1_event(dch->l1, INFO4_P8);
- break;
- }
- } else {
- if (debug & DEBUG_HFCMULTI_STATE)
- printk(KERN_DEBUG "%s: S/T NT newstate %x\n",
- __func__, dch->state);
- switch (dch->state) {
- case (2):
- if (hc->chan[ch].nt_timer == 0) {
- hc->chan[ch].nt_timer = -1;
- HFC_outb(hc, R_ST_SEL,
- hc->chan[ch].port);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- HFC_outb(hc, A_ST_WR_STATE, 4 |
- V_ST_LD_STA); /* G4 */
- udelay(6); /* wait at least 5,21us */
- HFC_outb(hc, A_ST_WR_STATE, 4);
- dch->state = 4;
- } else {
- /* one extra count for the next event */
- hc->chan[ch].nt_timer =
- nt_t1_count[poll_timer] + 1;
- HFC_outb(hc, R_ST_SEL,
- hc->chan[ch].port);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- /* allow G2 -> G3 transition */
- HFC_outb(hc, A_ST_WR_STATE, 2 |
- V_SET_G2_G3);
- }
- break;
- case (1):
- hc->chan[ch].nt_timer = -1;
- test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, PH_DEACTIVATE_IND,
- MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
- break;
- case (4):
- hc->chan[ch].nt_timer = -1;
- break;
- case (3):
- hc->chan[ch].nt_timer = -1;
- test_and_set_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, PH_ACTIVATE_IND,
- MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
- break;
- }
- }
- }
-}
-
-/*
- * called for card mode init message
- */
-
-static void
-hfcmulti_initmode(struct dchannel *dch)
-{
- struct hfc_multi *hc = dch->hw;
- u_char a_st_wr_state, r_e1_wr_sta;
- int i, pt;
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: entered\n", __func__);
-
- i = dch->slot;
- pt = hc->chan[i].port;
- if (hc->ctype == HFC_TYPE_E1) {
- /* E1 */
- hc->chan[hc->dnum[pt]].slot_tx = -1;
- hc->chan[hc->dnum[pt]].slot_rx = -1;
- hc->chan[hc->dnum[pt]].conf = -1;
- if (hc->dnum[pt]) {
- mode_hfcmulti(hc, dch->slot, dch->dev.D.protocol,
- -1, 0, -1, 0);
- timer_setup(&dch->timer, hfcmulti_dbusy_timer, 0);
- }
- for (i = 1; i <= 31; i++) {
- if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */
- continue;
- hc->chan[i].slot_tx = -1;
- hc->chan[i].slot_rx = -1;
- hc->chan[i].conf = -1;
- mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0);
- }
- }
- if (hc->ctype == HFC_TYPE_E1 && pt == 0) {
- /* E1, port 0 */
- dch = hc->chan[hc->dnum[0]].dch;
- if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) {
- HFC_outb(hc, R_LOS0, 255); /* 2 ms */
- HFC_outb(hc, R_LOS1, 255); /* 512 ms */
- }
- if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dnum[0]].cfg)) {
- HFC_outb(hc, R_RX0, 0);
- hc->hw.r_tx0 = 0 | V_OUT_EN;
- } else {
- HFC_outb(hc, R_RX0, 1);
- hc->hw.r_tx0 = 1 | V_OUT_EN;
- }
- hc->hw.r_tx1 = V_ATX | V_NTRI;
- HFC_outb(hc, R_TX0, hc->hw.r_tx0);
- HFC_outb(hc, R_TX1, hc->hw.r_tx1);
- HFC_outb(hc, R_TX_FR0, 0x00);
- HFC_outb(hc, R_TX_FR1, 0xf8);
-
- if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg))
- HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E);
-
- HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0);
-
- if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg))
- HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC);
-
- if (dch->dev.D.protocol == ISDN_P_NT_E1) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: E1 port is NT-mode\n",
- __func__);
- r_e1_wr_sta = 0; /* G0 */
- hc->e1_getclock = 0;
- } else {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: E1 port is TE-mode\n",
- __func__);
- r_e1_wr_sta = 0; /* F0 */
- hc->e1_getclock = 1;
- }
- if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip))
- HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX);
- else
- HFC_outb(hc, R_SYNC_OUT, 0);
- if (test_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip))
- hc->e1_getclock = 1;
- if (test_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip))
- hc->e1_getclock = 0;
- if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
- /* SLAVE (clock master) */
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: E1 port is clock master "
- "(clock from PCM)\n", __func__);
- HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC);
- } else {
- if (hc->e1_getclock) {
- /* MASTER (clock slave) */
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: E1 port is clock slave "
- "(clock to PCM)\n", __func__);
- HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS);
- } else {
- /* MASTER (clock master) */
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: E1 port is "
- "clock master "
- "(clock from QUARTZ)\n",
- __func__);
- HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC |
- V_PCM_SYNC | V_JATT_OFF);
- HFC_outb(hc, R_SYNC_OUT, 0);
- }
- }
- HFC_outb(hc, R_JATT_ATT, 0x9c); /* undoc register */
- HFC_outb(hc, R_PWM_MD, V_PWM0_MD);
- HFC_outb(hc, R_PWM0, 0x50);
- HFC_outb(hc, R_PWM1, 0xff);
- /* state machine setup */
- HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA);
- udelay(6); /* wait at least 5,21us */
- HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta);
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- hc->syncronized = 0;
- plxsd_checksync(hc, 0);
- }
- }
- if (hc->ctype != HFC_TYPE_E1) {
- /* ST */
- hc->chan[i].slot_tx = -1;
- hc->chan[i].slot_rx = -1;
- hc->chan[i].conf = -1;
- mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0);
- timer_setup(&dch->timer, hfcmulti_dbusy_timer, 0);
- hc->chan[i - 2].slot_tx = -1;
- hc->chan[i - 2].slot_rx = -1;
- hc->chan[i - 2].conf = -1;
- mode_hfcmulti(hc, i - 2, ISDN_P_NONE, -1, 0, -1, 0);
- hc->chan[i - 1].slot_tx = -1;
- hc->chan[i - 1].slot_rx = -1;
- hc->chan[i - 1].conf = -1;
- mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0);
- /* select interface */
- HFC_outb(hc, R_ST_SEL, pt);
- /* undocumented: delay after R_ST_SEL */
- udelay(1);
- if (dch->dev.D.protocol == ISDN_P_NT_S0) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: ST port %d is NT-mode\n",
- __func__, pt);
- /* clock delay */
- HFC_outb(hc, A_ST_CLK_DLY, clockdelay_nt);
- a_st_wr_state = 1; /* G1 */
- hc->hw.a_st_ctrl0[pt] = V_ST_MD;
- } else {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: ST port %d is TE-mode\n",
- __func__, pt);
- /* clock delay */
- HFC_outb(hc, A_ST_CLK_DLY, clockdelay_te);
- a_st_wr_state = 2; /* F2 */
- hc->hw.a_st_ctrl0[pt] = 0;
- }
- if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg))
- hc->hw.a_st_ctrl0[pt] |= V_TX_LI;
- if (hc->ctype == HFC_TYPE_XHFC) {
- hc->hw.a_st_ctrl0[pt] |= 0x40 /* V_ST_PU_CTRL */;
- HFC_outb(hc, 0x35 /* A_ST_CTRL3 */,
- 0x7c << 1 /* V_ST_PULSE */);
- }
- /* line setup */
- HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[pt]);
- /* disable E-channel */
- if ((dch->dev.D.protocol == ISDN_P_NT_S0) ||
- test_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i].cfg))
- HFC_outb(hc, A_ST_CTRL1, V_E_IGNO);
- else
- HFC_outb(hc, A_ST_CTRL1, 0);
- /* enable B-channel receive */
- HFC_outb(hc, A_ST_CTRL2, V_B1_RX_EN | V_B2_RX_EN);
- /* state machine setup */
- HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state | V_ST_LD_STA);
- udelay(6); /* wait at least 5,21us */
- HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state);
- hc->hw.r_sci_msk |= 1 << pt;
- /* state machine interrupts */
- HFC_outb(hc, R_SCI_MSK, hc->hw.r_sci_msk);
- /* unset sync on port */
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- hc->syncronized &=
- ~(1 << hc->chan[dch->slot].port);
- plxsd_checksync(hc, 0);
- }
- }
- if (debug & DEBUG_HFCMULTI_INIT)
- printk("%s: done\n", __func__);
-}
-
-
-static int
-open_dchannel(struct hfc_multi *hc, struct dchannel *dch,
- struct channel_req *rq)
-{
- int err = 0;
- u_long flags;
-
- if (debug & DEBUG_HW_OPEN)
- printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__,
- dch->dev.id, __builtin_return_address(0));
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
- if ((dch->dev.D.protocol != ISDN_P_NONE) &&
- (dch->dev.D.protocol != rq->protocol)) {
- if (debug & DEBUG_HFCMULTI_MODE)
- printk(KERN_DEBUG "%s: change protocol %x to %x\n",
- __func__, dch->dev.D.protocol, rq->protocol);
- }
- if ((dch->dev.D.protocol == ISDN_P_TE_S0) &&
- (rq->protocol != ISDN_P_TE_S0))
- l1_event(dch->l1, CLOSE_CHANNEL);
- if (dch->dev.D.protocol != rq->protocol) {
- if (rq->protocol == ISDN_P_TE_S0) {
- err = create_l1(dch, hfcm_l1callback);
- if (err)
- return err;
- }
- dch->dev.D.protocol = rq->protocol;
- spin_lock_irqsave(&hc->lock, flags);
- hfcmulti_initmode(dch);
- spin_unlock_irqrestore(&hc->lock, flags);
- }
- if (test_bit(FLG_ACTIVE, &dch->Flags))
- _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY,
- 0, NULL, GFP_KERNEL);
- rq->ch = &dch->dev.D;
- if (!try_module_get(THIS_MODULE))
- printk(KERN_WARNING "%s:cannot get module\n", __func__);
- return 0;
-}
-
-static int
-open_bchannel(struct hfc_multi *hc, struct dchannel *dch,
- struct channel_req *rq)
-{
- struct bchannel *bch;
- int ch;
-
- if (!test_channelmap(rq->adr.channel, dch->dev.channelmap))
- return -EINVAL;
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
- if (hc->ctype == HFC_TYPE_E1)
- ch = rq->adr.channel;
- else
- ch = (rq->adr.channel - 1) + (dch->slot - 2);
- bch = hc->chan[ch].bch;
- if (!bch) {
- printk(KERN_ERR "%s:internal error ch %d has no bch\n",
- __func__, ch);
- return -EINVAL;
- }
- if (test_and_set_bit(FLG_OPEN, &bch->Flags))
- return -EBUSY; /* b-channel can be only open once */
- bch->ch.protocol = rq->protocol;
- hc->chan[ch].rx_off = 0;
- rq->ch = &bch->ch;
- if (!try_module_get(THIS_MODULE))
- printk(KERN_WARNING "%s:cannot get module\n", __func__);
- return 0;
-}
-
-/*
- * device control function
- */
-static int
-channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
-{
- struct hfc_multi *hc = dch->hw;
- int ret = 0;
- int wd_mode, wd_cnt;
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_L1_TIMER3;
- break;
- case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */
- wd_cnt = cq->p1 & 0xf;
- wd_mode = !!(cq->p1 >> 4);
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_INIT mode %s"
- ", counter 0x%x\n", __func__,
- wd_mode ? "AUTO" : "MANUAL", wd_cnt);
- /* set the watchdog timer */
- HFC_outb(hc, R_TI_WD, poll_timer | (wd_cnt << 4));
- hc->hw.r_bert_wd_md = (wd_mode ? V_AUTO_WD_RES : 0);
- if (hc->ctype == HFC_TYPE_XHFC)
- hc->hw.r_bert_wd_md |= 0x40 /* V_WD_EN */;
- /* init the watchdog register and reset the counter */
- HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES);
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- /* enable the watchdog output for Speech-Design */
- HFC_outb(hc, R_GPIO_SEL, V_GPIO_SEL7);
- HFC_outb(hc, R_GPIO_EN1, V_GPIO_EN15);
- HFC_outb(hc, R_GPIO_OUT1, 0);
- HFC_outb(hc, R_GPIO_OUT1, V_GPIO_OUT15);
- }
- break;
- case MISDN_CTRL_HFC_WD_RESET: /* reset the watchdog counter */
- if (debug & DEBUG_HFCMULTI_MSG)
- printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_RESET\n",
- __func__);
- HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES);
- break;
- case MISDN_CTRL_L1_TIMER3:
- ret = l1_event(dch->l1, HW_TIMER3_VALUE | (cq->p1 & 0xff));
- break;
- default:
- printk(KERN_WARNING "%s: unknown Op %x\n",
- __func__, cq->op);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int
-hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct hfc_multi *hc = dch->hw;
- struct channel_req *rq;
- int err = 0;
- u_long flags;
-
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: cmd:%x %p\n",
- __func__, cmd, arg);
- switch (cmd) {
- case OPEN_CHANNEL:
- rq = arg;
- switch (rq->protocol) {
- case ISDN_P_TE_S0:
- case ISDN_P_NT_S0:
- if (hc->ctype == HFC_TYPE_E1) {
- err = -EINVAL;
- break;
- }
- err = open_dchannel(hc, dch, rq); /* locked there */
- break;
- case ISDN_P_TE_E1:
- case ISDN_P_NT_E1:
- if (hc->ctype != HFC_TYPE_E1) {
- err = -EINVAL;
- break;
- }
- err = open_dchannel(hc, dch, rq); /* locked there */
- break;
- default:
- spin_lock_irqsave(&hc->lock, flags);
- err = open_bchannel(hc, dch, rq);
- spin_unlock_irqrestore(&hc->lock, flags);
- }
- break;
- case CLOSE_CHANNEL:
- if (debug & DEBUG_HW_OPEN)
- printk(KERN_DEBUG "%s: dev(%d) close from %p\n",
- __func__, dch->dev.id,
- __builtin_return_address(0));
- module_put(THIS_MODULE);
- break;
- case CONTROL_CHANNEL:
- spin_lock_irqsave(&hc->lock, flags);
- err = channel_dctrl(dch, arg);
- spin_unlock_irqrestore(&hc->lock, flags);
- break;
- default:
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: unknown command %x\n",
- __func__, cmd);
- err = -EINVAL;
- }
- return err;
-}
-
-static int
-clockctl(void *priv, int enable)
-{
- struct hfc_multi *hc = priv;
-
- hc->iclock_on = enable;
- return 0;
-}
-
-/*
- * initialize the card
- */
-
-/*
- * start timer irq, wait some time and check if we have interrupts.
- * if not, reset chip and try again.
- */
-static int
-init_card(struct hfc_multi *hc)
-{
- int err = -EIO;
- u_long flags;
- void __iomem *plx_acc;
- u_long plx_flags;
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: entered\n", __func__);
-
- spin_lock_irqsave(&hc->lock, flags);
- /* set interrupts but leave global interrupt disabled */
- hc->hw.r_irq_ctrl = V_FIFO_IRQ;
- disable_hwirq(hc);
- spin_unlock_irqrestore(&hc->lock, flags);
-
- if (request_irq(hc->irq, hfcmulti_interrupt, IRQF_SHARED,
- "HFC-multi", hc)) {
- printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n",
- hc->irq);
- hc->irq = 0;
- return -EIO;
- }
-
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- spin_lock_irqsave(&plx_lock, plx_flags);
- plx_acc = hc->plx_membase + PLX_INTCSR;
- writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE),
- plx_acc); /* enable PCI & LINT1 irq */
- spin_unlock_irqrestore(&plx_lock, plx_flags);
- }
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: IRQ %d count %d\n",
- __func__, hc->irq, hc->irqcnt);
- err = init_chip(hc);
- if (err)
- goto error;
- /*
- * Finally enable IRQ output
- * this is only allowed, if an IRQ routine is already
- * established for this HFC, so don't do that earlier
- */
- spin_lock_irqsave(&hc->lock, flags);
- enable_hwirq(hc);
- spin_unlock_irqrestore(&hc->lock, flags);
- /* printk(KERN_DEBUG "no master irq set!!!\n"); */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((100 * HZ) / 1000); /* Timeout 100ms */
- /* turn IRQ off until chip is completely initialized */
- spin_lock_irqsave(&hc->lock, flags);
- disable_hwirq(hc);
- spin_unlock_irqrestore(&hc->lock, flags);
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: IRQ %d count %d\n",
- __func__, hc->irq, hc->irqcnt);
- if (hc->irqcnt) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: done\n", __func__);
-
- return 0;
- }
- if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
- printk(KERN_INFO "ignoring missing interrupts\n");
- return 0;
- }
-
- printk(KERN_ERR "HFC PCI: IRQ(%d) getting no interrupts during init.\n",
- hc->irq);
-
- err = -EIO;
-
-error:
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- spin_lock_irqsave(&plx_lock, plx_flags);
- plx_acc = hc->plx_membase + PLX_INTCSR;
- writew(0x00, plx_acc); /*disable IRQs*/
- spin_unlock_irqrestore(&plx_lock, plx_flags);
- }
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: free irq %d\n", __func__, hc->irq);
- if (hc->irq) {
- free_irq(hc->irq, hc);
- hc->irq = 0;
- }
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: done (err=%d)\n", __func__, err);
- return err;
-}
-
-/*
- * find pci device and set it up
- */
-
-static int
-setup_pci(struct hfc_multi *hc, struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct hm_map *m = (struct hm_map *)ent->driver_data;
-
- printk(KERN_INFO
- "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n",
- m->vendor_name, m->card_name, m->clock2 ? "double" : "normal");
-
- hc->pci_dev = pdev;
- if (m->clock2)
- test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip);
-
- if (ent->vendor == PCI_VENDOR_ID_DIGIUM &&
- ent->device == PCI_DEVICE_ID_DIGIUM_HFC4S) {
- test_and_set_bit(HFC_CHIP_B410P, &hc->chip);
- test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip);
- test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip);
- hc->slots = 32;
- }
-
- if (hc->pci_dev->irq <= 0) {
- printk(KERN_WARNING "HFC-multi: No IRQ for PCI card found.\n");
- return -EIO;
- }
- if (pci_enable_device(hc->pci_dev)) {
- printk(KERN_WARNING "HFC-multi: Error enabling PCI card.\n");
- return -EIO;
- }
- hc->leds = m->leds;
- hc->ledstate = 0xAFFEAFFE;
- hc->opticalsupport = m->opticalsupport;
-
- hc->pci_iobase = 0;
- hc->pci_membase = NULL;
- hc->plx_membase = NULL;
-
- /* set memory access methods */
- if (m->io_mode) /* use mode from card config */
- hc->io_mode = m->io_mode;
- switch (hc->io_mode) {
- case HFC_IO_MODE_PLXSD:
- test_and_set_bit(HFC_CHIP_PLXSD, &hc->chip);
- hc->slots = 128; /* required */
- hc->HFC_outb = HFC_outb_pcimem;
- hc->HFC_inb = HFC_inb_pcimem;
- hc->HFC_inw = HFC_inw_pcimem;
- hc->HFC_wait = HFC_wait_pcimem;
- hc->read_fifo = read_fifo_pcimem;
- hc->write_fifo = write_fifo_pcimem;
- hc->plx_origmembase = hc->pci_dev->resource[0].start;
- /* MEMBASE 1 is PLX PCI Bridge */
-
- if (!hc->plx_origmembase) {
- printk(KERN_WARNING
- "HFC-multi: No IO-Memory for PCI PLX bridge found\n");
- pci_disable_device(hc->pci_dev);
- return -EIO;
- }
-
- hc->plx_membase = ioremap(hc->plx_origmembase, 0x80);
- if (!hc->plx_membase) {
- printk(KERN_WARNING
- "HFC-multi: failed to remap plx address space. "
- "(internal error)\n");
- pci_disable_device(hc->pci_dev);
- return -EIO;
- }
- printk(KERN_INFO
- "HFC-multi: plx_membase:%#lx plx_origmembase:%#lx\n",
- (u_long)hc->plx_membase, hc->plx_origmembase);
-
- hc->pci_origmembase = hc->pci_dev->resource[2].start;
- /* MEMBASE 1 is PLX PCI Bridge */
- if (!hc->pci_origmembase) {
- printk(KERN_WARNING
- "HFC-multi: No IO-Memory for PCI card found\n");
- pci_disable_device(hc->pci_dev);
- return -EIO;
- }
-
- hc->pci_membase = ioremap(hc->pci_origmembase, 0x400);
- if (!hc->pci_membase) {
- printk(KERN_WARNING "HFC-multi: failed to remap io "
- "address space. (internal error)\n");
- pci_disable_device(hc->pci_dev);
- return -EIO;
- }
-
- printk(KERN_INFO
- "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d HZ %d "
- "leds-type %d\n",
- hc->id, (u_long)hc->pci_membase, hc->pci_origmembase,
- hc->pci_dev->irq, HZ, hc->leds);
- pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO);
- break;
- case HFC_IO_MODE_PCIMEM:
- hc->HFC_outb = HFC_outb_pcimem;
- hc->HFC_inb = HFC_inb_pcimem;
- hc->HFC_inw = HFC_inw_pcimem;
- hc->HFC_wait = HFC_wait_pcimem;
- hc->read_fifo = read_fifo_pcimem;
- hc->write_fifo = write_fifo_pcimem;
- hc->pci_origmembase = hc->pci_dev->resource[1].start;
- if (!hc->pci_origmembase) {
- printk(KERN_WARNING
- "HFC-multi: No IO-Memory for PCI card found\n");
- pci_disable_device(hc->pci_dev);
- return -EIO;
- }
-
- hc->pci_membase = ioremap(hc->pci_origmembase, 256);
- if (!hc->pci_membase) {
- printk(KERN_WARNING
- "HFC-multi: failed to remap io address space. "
- "(internal error)\n");
- pci_disable_device(hc->pci_dev);
- return -EIO;
- }
- printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ "
- "%d HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase,
- hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds);
- pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO);
- break;
- case HFC_IO_MODE_REGIO:
- hc->HFC_outb = HFC_outb_regio;
- hc->HFC_inb = HFC_inb_regio;
- hc->HFC_inw = HFC_inw_regio;
- hc->HFC_wait = HFC_wait_regio;
- hc->read_fifo = read_fifo_regio;
- hc->write_fifo = write_fifo_regio;
- hc->pci_iobase = (u_int) hc->pci_dev->resource[0].start;
- if (!hc->pci_iobase) {
- printk(KERN_WARNING
- "HFC-multi: No IO for PCI card found\n");
- pci_disable_device(hc->pci_dev);
- return -EIO;
- }
-
- if (!request_region(hc->pci_iobase, 8, "hfcmulti")) {
- printk(KERN_WARNING "HFC-multi: failed to request "
- "address space at 0x%08lx (internal error)\n",
- hc->pci_iobase);
- pci_disable_device(hc->pci_dev);
- return -EIO;
- }
-
- printk(KERN_INFO
- "%s %s: defined at IOBASE %#x IRQ %d HZ %d leds-type %d\n",
- m->vendor_name, m->card_name, (u_int) hc->pci_iobase,
- hc->pci_dev->irq, HZ, hc->leds);
- pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_REGIO);
- break;
- default:
- printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n");
- pci_disable_device(hc->pci_dev);
- return -EIO;
- }
-
- pci_set_drvdata(hc->pci_dev, hc);
-
- /* At this point the needed PCI config is done */
- /* fifos are still not enabled */
- return 0;
-}
-
-
-/*
- * remove port
- */
-
-static void
-release_port(struct hfc_multi *hc, struct dchannel *dch)
-{
- int pt, ci, i = 0;
- u_long flags;
- struct bchannel *pb;
-
- ci = dch->slot;
- pt = hc->chan[ci].port;
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: entered for port %d\n",
- __func__, pt + 1);
-
- if (pt >= hc->ports) {
- printk(KERN_WARNING "%s: ERROR port out of range (%d).\n",
- __func__, pt + 1);
- return;
- }
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: releasing port=%d\n",
- __func__, pt + 1);
-
- if (dch->dev.D.protocol == ISDN_P_TE_S0)
- l1_event(dch->l1, CLOSE_CHANNEL);
-
- hc->chan[ci].dch = NULL;
-
- if (hc->created[pt]) {
- hc->created[pt] = 0;
- mISDN_unregister_device(&dch->dev);
- }
-
- spin_lock_irqsave(&hc->lock, flags);
-
- if (dch->timer.function) {
- timer_delete(&dch->timer);
- dch->timer.function = NULL;
- }
-
- if (hc->ctype == HFC_TYPE_E1) { /* E1 */
- /* remove sync */
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- hc->syncronized = 0;
- plxsd_checksync(hc, 1);
- }
- /* free channels */
- for (i = 0; i <= 31; i++) {
- if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */
- continue;
- if (hc->chan[i].bch) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: free port %d channel %d\n",
- __func__, hc->chan[i].port + 1, i);
- pb = hc->chan[i].bch;
- hc->chan[i].bch = NULL;
- spin_unlock_irqrestore(&hc->lock, flags);
- mISDN_freebchannel(pb);
- kfree(pb);
- kfree(hc->chan[i].coeff);
- spin_lock_irqsave(&hc->lock, flags);
- }
- }
- } else {
- /* remove sync */
- if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
- hc->syncronized &=
- ~(1 << hc->chan[ci].port);
- plxsd_checksync(hc, 1);
- }
- /* free channels */
- if (hc->chan[ci - 2].bch) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: free port %d channel %d\n",
- __func__, hc->chan[ci - 2].port + 1,
- ci - 2);
- pb = hc->chan[ci - 2].bch;
- hc->chan[ci - 2].bch = NULL;
- spin_unlock_irqrestore(&hc->lock, flags);
- mISDN_freebchannel(pb);
- kfree(pb);
- kfree(hc->chan[ci - 2].coeff);
- spin_lock_irqsave(&hc->lock, flags);
- }
- if (hc->chan[ci - 1].bch) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: free port %d channel %d\n",
- __func__, hc->chan[ci - 1].port + 1,
- ci - 1);
- pb = hc->chan[ci - 1].bch;
- hc->chan[ci - 1].bch = NULL;
- spin_unlock_irqrestore(&hc->lock, flags);
- mISDN_freebchannel(pb);
- kfree(pb);
- kfree(hc->chan[ci - 1].coeff);
- spin_lock_irqsave(&hc->lock, flags);
- }
- }
-
- spin_unlock_irqrestore(&hc->lock, flags);
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: free port %d channel D(%d)\n", __func__,
- pt+1, ci);
- mISDN_freedchannel(dch);
- kfree(dch);
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: done!\n", __func__);
-}
-
-static void
-release_card(struct hfc_multi *hc)
-{
- u_long flags;
- int ch;
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: release card (%d) entered\n",
- __func__, hc->id);
-
- /* unregister clock source */
- if (hc->iclock)
- mISDN_unregister_clock(hc->iclock);
-
- /* disable and free irq */
- spin_lock_irqsave(&hc->lock, flags);
- disable_hwirq(hc);
- spin_unlock_irqrestore(&hc->lock, flags);
- udelay(1000);
- if (hc->irq) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: free irq %d (hc=%p)\n",
- __func__, hc->irq, hc);
- free_irq(hc->irq, hc);
- hc->irq = 0;
-
- }
-
- /* disable D-channels & B-channels */
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: disable all channels (d and b)\n",
- __func__);
- for (ch = 0; ch <= 31; ch++) {
- if (hc->chan[ch].dch)
- release_port(hc, hc->chan[ch].dch);
- }
-
- /* dimm leds */
- if (hc->leds)
- hfcmulti_leds(hc);
-
- /* release hardware */
- release_io_hfcmulti(hc);
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: remove instance from list\n",
- __func__);
- list_del(&hc->list);
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: delete instance\n", __func__);
- if (hc == syncmaster)
- syncmaster = NULL;
- kfree(hc);
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: card successfully removed\n",
- __func__);
-}
-
-static void
-init_e1_port_hw(struct hfc_multi *hc, struct hm_map *m)
-{
- /* set optical line type */
- if (port[Port_cnt] & 0x001) {
- if (!m->opticalsupport) {
- printk(KERN_INFO
- "This board has no optical "
- "support\n");
- } else {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: PORT set optical "
- "interface: card(%d) "
- "port(%d)\n",
- __func__,
- HFC_cnt + 1, 1);
- test_and_set_bit(HFC_CFG_OPTICAL,
- &hc->chan[hc->dnum[0]].cfg);
- }
- }
- /* set LOS report */
- if (port[Port_cnt] & 0x004) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: PORT set "
- "LOS report: card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, 1);
- test_and_set_bit(HFC_CFG_REPORT_LOS,
- &hc->chan[hc->dnum[0]].cfg);
- }
- /* set AIS report */
- if (port[Port_cnt] & 0x008) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: PORT set "
- "AIS report: card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, 1);
- test_and_set_bit(HFC_CFG_REPORT_AIS,
- &hc->chan[hc->dnum[0]].cfg);
- }
- /* set SLIP report */
- if (port[Port_cnt] & 0x010) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: PORT set SLIP report: "
- "card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, 1);
- test_and_set_bit(HFC_CFG_REPORT_SLIP,
- &hc->chan[hc->dnum[0]].cfg);
- }
- /* set RDI report */
- if (port[Port_cnt] & 0x020) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: PORT set RDI report: "
- "card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, 1);
- test_and_set_bit(HFC_CFG_REPORT_RDI,
- &hc->chan[hc->dnum[0]].cfg);
- }
- /* set CRC-4 Mode */
- if (!(port[Port_cnt] & 0x100)) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: PORT turn on CRC4 report:"
- " card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, 1);
- test_and_set_bit(HFC_CFG_CRC4,
- &hc->chan[hc->dnum[0]].cfg);
- } else {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: PORT turn off CRC4"
- " report: card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, 1);
- }
- /* set forced clock */
- if (port[Port_cnt] & 0x0200) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: PORT force getting clock from "
- "E1: card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, 1);
- test_and_set_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip);
- } else
- if (port[Port_cnt] & 0x0400) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: PORT force putting clock to "
- "E1: card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, 1);
- test_and_set_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip);
- }
- /* set JATT PLL */
- if (port[Port_cnt] & 0x0800) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: PORT disable JATT PLL on "
- "E1: card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, 1);
- test_and_set_bit(HFC_CHIP_RX_SYNC, &hc->chip);
- }
- /* set elastic jitter buffer */
- if (port[Port_cnt] & 0x3000) {
- hc->chan[hc->dnum[0]].jitter = (port[Port_cnt]>>12) & 0x3;
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: PORT set elastic "
- "buffer to %d: card(%d) port(%d)\n",
- __func__, hc->chan[hc->dnum[0]].jitter,
- HFC_cnt + 1, 1);
- } else
- hc->chan[hc->dnum[0]].jitter = 2; /* default */
-}
-
-static int
-init_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt)
-{
- struct dchannel *dch;
- struct bchannel *bch;
- int ch, ret = 0;
- char name[MISDN_MAX_IDLEN];
- int bcount = 0;
-
- dch = kzalloc_obj(struct dchannel);
- if (!dch)
- return -ENOMEM;
- dch->debug = debug;
- mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change);
- dch->hw = hc;
- dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1);
- dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
- dch->dev.D.send = handle_dmsg;
- dch->dev.D.ctrl = hfcm_dctrl;
- dch->slot = hc->dnum[pt];
- hc->chan[hc->dnum[pt]].dch = dch;
- hc->chan[hc->dnum[pt]].port = pt;
- hc->chan[hc->dnum[pt]].nt_timer = -1;
- for (ch = 1; ch <= 31; ch++) {
- if (!((1 << ch) & hc->bmask[pt])) /* skip unused channel */
- continue;
- bch = kzalloc_obj(struct bchannel);
- if (!bch) {
- printk(KERN_ERR "%s: no memory for bchannel\n",
- __func__);
- ret = -ENOMEM;
- goto free_chan;
- }
- hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL);
- if (!hc->chan[ch].coeff) {
- printk(KERN_ERR "%s: no memory for coeffs\n",
- __func__);
- ret = -ENOMEM;
- kfree(bch);
- goto free_chan;
- }
- bch->nr = ch;
- bch->slot = ch;
- bch->debug = debug;
- mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1);
- bch->hw = hc;
- bch->ch.send = handle_bmsg;
- bch->ch.ctrl = hfcm_bctrl;
- bch->ch.nr = ch;
- list_add(&bch->ch.list, &dch->dev.bchannels);
- hc->chan[ch].bch = bch;
- hc->chan[ch].port = pt;
- set_channelmap(bch->nr, dch->dev.channelmap);
- bcount++;
- }
- dch->dev.nrbchan = bcount;
- if (pt == 0)
- init_e1_port_hw(hc, m);
- if (hc->ports > 1)
- snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d-%d",
- HFC_cnt + 1, pt+1);
- else
- snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1);
- ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name);
- if (ret)
- goto free_chan;
- hc->created[pt] = 1;
- return ret;
-free_chan:
- release_port(hc, dch);
- return ret;
-}
-
-static int
-init_multi_port(struct hfc_multi *hc, int pt)
-{
- struct dchannel *dch;
- struct bchannel *bch;
- int ch, i, ret = 0;
- char name[MISDN_MAX_IDLEN];
-
- dch = kzalloc_obj(struct dchannel);
- if (!dch)
- return -ENOMEM;
- dch->debug = debug;
- mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change);
- dch->hw = hc;
- dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0);
- dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
- dch->dev.D.send = handle_dmsg;
- dch->dev.D.ctrl = hfcm_dctrl;
- dch->dev.nrbchan = 2;
- i = pt << 2;
- dch->slot = i + 2;
- hc->chan[i + 2].dch = dch;
- hc->chan[i + 2].port = pt;
- hc->chan[i + 2].nt_timer = -1;
- for (ch = 0; ch < dch->dev.nrbchan; ch++) {
- bch = kzalloc_obj(struct bchannel);
- if (!bch) {
- printk(KERN_ERR "%s: no memory for bchannel\n",
- __func__);
- ret = -ENOMEM;
- goto free_chan;
- }
- hc->chan[i + ch].coeff = kzalloc(512, GFP_KERNEL);
- if (!hc->chan[i + ch].coeff) {
- printk(KERN_ERR "%s: no memory for coeffs\n",
- __func__);
- ret = -ENOMEM;
- kfree(bch);
- goto free_chan;
- }
- bch->nr = ch + 1;
- bch->slot = i + ch;
- bch->debug = debug;
- mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1);
- bch->hw = hc;
- bch->ch.send = handle_bmsg;
- bch->ch.ctrl = hfcm_bctrl;
- bch->ch.nr = ch + 1;
- list_add(&bch->ch.list, &dch->dev.bchannels);
- hc->chan[i + ch].bch = bch;
- hc->chan[i + ch].port = pt;
- set_channelmap(bch->nr, dch->dev.channelmap);
- }
- /* set master clock */
- if (port[Port_cnt] & 0x001) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: PROTOCOL set master clock: "
- "card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, pt + 1);
- if (dch->dev.D.protocol != ISDN_P_TE_S0) {
- printk(KERN_ERR "Error: Master clock "
- "for port(%d) of card(%d) is only"
- " possible with TE-mode\n",
- pt + 1, HFC_cnt + 1);
- ret = -EINVAL;
- goto free_chan;
- }
- if (hc->masterclk >= 0) {
- printk(KERN_ERR "Error: Master clock "
- "for port(%d) of card(%d) already "
- "defined for port(%d)\n",
- pt + 1, HFC_cnt + 1, hc->masterclk + 1);
- ret = -EINVAL;
- goto free_chan;
- }
- hc->masterclk = pt;
- }
- /* set transmitter line to non capacitive */
- if (port[Port_cnt] & 0x002) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: PROTOCOL set non capacitive "
- "transmitter: card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, pt + 1);
- test_and_set_bit(HFC_CFG_NONCAP_TX,
- &hc->chan[i + 2].cfg);
- }
- /* disable E-channel */
- if (port[Port_cnt] & 0x004) {
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: PROTOCOL disable E-channel: "
- "card(%d) port(%d)\n",
- __func__, HFC_cnt + 1, pt + 1);
- test_and_set_bit(HFC_CFG_DIS_ECHANNEL,
- &hc->chan[i + 2].cfg);
- }
- if (hc->ctype == HFC_TYPE_XHFC) {
- snprintf(name, MISDN_MAX_IDLEN - 1, "xhfc.%d-%d",
- HFC_cnt + 1, pt + 1);
- ret = mISDN_register_device(&dch->dev, NULL, name);
- } else {
- snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d",
- hc->ctype, HFC_cnt + 1, pt + 1);
- ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name);
- }
- if (ret)
- goto free_chan;
- hc->created[pt] = 1;
- return ret;
-free_chan:
- release_port(hc, dch);
- return ret;
-}
-
-static int
-hfcmulti_init(struct hm_map *m, struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int ret_err = 0;
- int pt;
- struct hfc_multi *hc;
- u_long flags;
- u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */
- int i, ch;
- u_int maskcheck;
-
- if (HFC_cnt >= MAX_CARDS) {
- printk(KERN_ERR "too many cards (max=%d).\n",
- MAX_CARDS);
- return -EINVAL;
- }
- if ((type[HFC_cnt] & 0xff) && (type[HFC_cnt] & 0xff) != m->type) {
- printk(KERN_WARNING "HFC-MULTI: Card '%s:%s' type %d found but "
- "type[%d] %d was supplied as module parameter\n",
- m->vendor_name, m->card_name, m->type, HFC_cnt,
- type[HFC_cnt] & 0xff);
- printk(KERN_WARNING "HFC-MULTI: Load module without parameters "
- "first, to see cards and their types.");
- return -EINVAL;
- }
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: Registering %s:%s chip type %d (0x%x)\n",
- __func__, m->vendor_name, m->card_name, m->type,
- type[HFC_cnt]);
-
- /* allocate card+fifo structure */
- hc = kzalloc_obj(struct hfc_multi);
- if (!hc) {
- printk(KERN_ERR "No kmem for HFC-Multi card\n");
- return -ENOMEM;
- }
- spin_lock_init(&hc->lock);
- hc->mtyp = m;
- hc->ctype = m->type;
- hc->ports = m->ports;
- hc->id = HFC_cnt;
- hc->pcm = pcm[HFC_cnt];
- hc->io_mode = iomode[HFC_cnt];
- if (hc->ctype == HFC_TYPE_E1 && dmask[E1_cnt]) {
- /* fragment card */
- pt = 0;
- maskcheck = 0;
- for (ch = 0; ch <= 31; ch++) {
- if (!((1 << ch) & dmask[E1_cnt]))
- continue;
- hc->dnum[pt] = ch;
- hc->bmask[pt] = bmask[bmask_cnt++];
- if ((maskcheck & hc->bmask[pt])
- || (dmask[E1_cnt] & hc->bmask[pt])) {
- printk(KERN_INFO
- "HFC-E1 #%d has overlapping B-channels on fragment #%d\n",
- E1_cnt + 1, pt);
- kfree(hc);
- return -EINVAL;
- }
- maskcheck |= hc->bmask[pt];
- printk(KERN_INFO
- "HFC-E1 #%d uses D-channel on slot %d and a B-channel map of 0x%08x\n",
- E1_cnt + 1, ch, hc->bmask[pt]);
- pt++;
- }
- hc->ports = pt;
- }
- if (hc->ctype == HFC_TYPE_E1 && !dmask[E1_cnt]) {
- /* default card layout */
- hc->dnum[0] = 16;
- hc->bmask[0] = 0xfffefffe;
- hc->ports = 1;
- }
-
- /* set chip specific features */
- hc->masterclk = -1;
- if (type[HFC_cnt] & 0x100) {
- test_and_set_bit(HFC_CHIP_ULAW, &hc->chip);
- hc->silence = 0xff; /* ulaw silence */
- } else
- hc->silence = 0x2a; /* alaw silence */
- if ((poll >> 1) > sizeof(hc->silence_data)) {
- printk(KERN_ERR "HFCMULTI error: silence_data too small, "
- "please fix\n");
- kfree(hc);
- return -EINVAL;
- }
- for (i = 0; i < (poll >> 1); i++)
- hc->silence_data[i] = hc->silence;
-
- if (hc->ctype != HFC_TYPE_XHFC) {
- if (!(type[HFC_cnt] & 0x200))
- test_and_set_bit(HFC_CHIP_DTMF, &hc->chip);
- test_and_set_bit(HFC_CHIP_CONF, &hc->chip);
- }
-
- if (type[HFC_cnt] & 0x800)
- test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip);
- if (type[HFC_cnt] & 0x1000) {
- test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip);
- test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip);
- }
- if (type[HFC_cnt] & 0x4000)
- test_and_set_bit(HFC_CHIP_EXRAM_128, &hc->chip);
- if (type[HFC_cnt] & 0x8000)
- test_and_set_bit(HFC_CHIP_EXRAM_512, &hc->chip);
- hc->slots = 32;
- if (type[HFC_cnt] & 0x10000)
- hc->slots = 64;
- if (type[HFC_cnt] & 0x20000)
- hc->slots = 128;
- if (type[HFC_cnt] & 0x80000) {
- test_and_set_bit(HFC_CHIP_WATCHDOG, &hc->chip);
- hc->wdcount = 0;
- hc->wdbyte = V_GPIO_OUT2;
- printk(KERN_NOTICE "Watchdog enabled\n");
- }
-
- if (pdev && ent)
- /* setup pci, hc->slots may change due to PLXSD */
- ret_err = setup_pci(hc, pdev, ent);
- else
-#ifdef CONFIG_MISDN_HFCMULTI_8xx
- ret_err = setup_embedded(hc, m);
-#else
- {
- printk(KERN_WARNING "Embedded IO Mode not selected\n");
- ret_err = -EIO;
- }
-#endif
- if (ret_err) {
- if (hc == syncmaster)
- syncmaster = NULL;
- kfree(hc);
- return ret_err;
- }
-
- hc->HFC_outb_nodebug = hc->HFC_outb;
- hc->HFC_inb_nodebug = hc->HFC_inb;
- hc->HFC_inw_nodebug = hc->HFC_inw;
- hc->HFC_wait_nodebug = hc->HFC_wait;
-#ifdef HFC_REGISTER_DEBUG
- hc->HFC_outb = HFC_outb_debug;
- hc->HFC_inb = HFC_inb_debug;
- hc->HFC_inw = HFC_inw_debug;
- hc->HFC_wait = HFC_wait_debug;
-#endif
- /* create channels */
- for (pt = 0; pt < hc->ports; pt++) {
- if (Port_cnt >= MAX_PORTS) {
- printk(KERN_ERR "too many ports (max=%d).\n",
- MAX_PORTS);
- ret_err = -EINVAL;
- goto free_card;
- }
- if (hc->ctype == HFC_TYPE_E1)
- ret_err = init_e1_port(hc, m, pt);
- else
- ret_err = init_multi_port(hc, pt);
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG
- "%s: Registering D-channel, card(%d) port(%d) "
- "result %d\n",
- __func__, HFC_cnt + 1, pt + 1, ret_err);
-
- if (ret_err) {
- while (pt) { /* release already registered ports */
- pt--;
- if (hc->ctype == HFC_TYPE_E1)
- release_port(hc,
- hc->chan[hc->dnum[pt]].dch);
- else
- release_port(hc,
- hc->chan[(pt << 2) + 2].dch);
- }
- goto free_card;
- }
- if (hc->ctype != HFC_TYPE_E1)
- Port_cnt++; /* for each S0 port */
- }
- if (hc->ctype == HFC_TYPE_E1) {
- Port_cnt++; /* for each E1 port */
- E1_cnt++;
- }
-
- /* disp switches */
- switch (m->dip_type) {
- case DIP_4S:
- /*
- * Get DIP setting for beroNet 1S/2S/4S cards
- * DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) +
- * GPI 19/23 (R_GPI_IN2))
- */
- dips = ((~HFC_inb(hc, R_GPIO_IN1) & 0xE0) >> 5) |
- ((~HFC_inb(hc, R_GPI_IN2) & 0x80) >> 3) |
- (~HFC_inb(hc, R_GPI_IN2) & 0x08);
-
- /* Port mode (TE/NT) jumpers */
- pmj = ((HFC_inb(hc, R_GPI_IN3) >> 4) & 0xf);
-
- if (test_bit(HFC_CHIP_B410P, &hc->chip))
- pmj = ~pmj & 0xf;
-
- printk(KERN_INFO "%s: %s DIPs(0x%x) jumpers(0x%x)\n",
- m->vendor_name, m->card_name, dips, pmj);
- break;
- case DIP_8S:
- /*
- * Get DIP Setting for beroNet 8S0+ cards
- * Enable PCI auxbridge function
- */
- HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK);
- /* prepare access to auxport */
- outw(0x4000, hc->pci_iobase + 4);
- /*
- * some dummy reads are required to
- * read valid DIP switch data
- */
- dips = inb(hc->pci_iobase);
- dips = inb(hc->pci_iobase);
- dips = inb(hc->pci_iobase);
- dips = ~inb(hc->pci_iobase) & 0x3F;
- outw(0x0, hc->pci_iobase + 4);
- /* disable PCI auxbridge function */
- HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK);
- printk(KERN_INFO "%s: %s DIPs(0x%x)\n",
- m->vendor_name, m->card_name, dips);
- break;
- case DIP_E1:
- /*
- * get DIP Setting for beroNet E1 cards
- * DIP Setting: collect GPI 4/5/6/7 (R_GPI_IN0)
- */
- dips = (~HFC_inb(hc, R_GPI_IN0) & 0xF0) >> 4;
- printk(KERN_INFO "%s: %s DIPs(0x%x)\n",
- m->vendor_name, m->card_name, dips);
- break;
- }
-
- /* add to list */
- spin_lock_irqsave(&HFClock, flags);
- list_add_tail(&hc->list, &HFClist);
- spin_unlock_irqrestore(&HFClock, flags);
-
- /* use as clock source */
- if (clock == HFC_cnt + 1)
- hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc);
-
- /* initialize hardware */
- hc->irq = (m->irq) ? : hc->pci_dev->irq;
- ret_err = init_card(hc);
- if (ret_err) {
- printk(KERN_ERR "init card returns %d\n", ret_err);
- release_card(hc);
- return ret_err;
- }
-
- /* start IRQ and return */
- spin_lock_irqsave(&hc->lock, flags);
- enable_hwirq(hc);
- spin_unlock_irqrestore(&hc->lock, flags);
- return 0;
-
-free_card:
- release_io_hfcmulti(hc);
- if (hc == syncmaster)
- syncmaster = NULL;
- kfree(hc);
- return ret_err;
-}
-
-static void hfc_remove_pci(struct pci_dev *pdev)
-{
- struct hfc_multi *card = pci_get_drvdata(pdev);
- u_long flags;
-
- if (debug)
- printk(KERN_INFO "removing hfc_multi card vendor:%x "
- "device:%x subvendor:%x subdevice:%x\n",
- pdev->vendor, pdev->device,
- pdev->subsystem_vendor, pdev->subsystem_device);
-
- if (card) {
- spin_lock_irqsave(&HFClock, flags);
- release_card(card);
- spin_unlock_irqrestore(&HFClock, flags);
- } else {
- if (debug)
- printk(KERN_DEBUG "%s: drvdata already removed\n",
- __func__);
- }
-}
-
-#define VENDOR_CCD "Cologne Chip AG"
-#define VENDOR_BN "beroNet GmbH"
-#define VENDOR_DIG "Digium Inc."
-#define VENDOR_JH "Junghanns.NET GmbH"
-#define VENDOR_PRIM "PrimuX"
-
-static const struct hm_map hfcm_map[] = {
- /*0*/ {VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0, 0},
- /*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0, 0},
- /*2*/ {VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0, 0},
- /*3*/ {VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0, 0},
- /*4*/ {VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0, 0},
- /*5*/ {VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0, 0},
- /*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0, 0},
- /*7*/ {VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0, 0},
- /*8*/ {VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO, 0},
- /*9*/ {VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0, 0},
- /*10*/ {VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0, 0},
- /*11*/ {VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0, 0},
-
- /*12*/ {VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0, 0},
- /*13*/ {VENDOR_BN, "HFC-8S Card (+)", 8, 8, 1, 8, 0, DIP_8S,
- HFC_IO_MODE_REGIO, 0},
- /*14*/ {VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0, 0},
- /*15*/ {VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0, 0},
-
- /*16*/ {VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0, 0},
- /*17*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0},
- /*18*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0},
-
- /*19*/ {VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0, 0},
- /*20*/ {VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0, 0},
- /*21*/ {VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0},
- /*22*/ {VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0},
-
- /*23*/ {VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0, 0},
- /*24*/ {VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0, 0},
- /*25*/ {VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0, 0},
-
- /*26*/ {VENDOR_CCD, "HFC-4S Speech Design", 4, 4, 0, 0, 0, 0,
- HFC_IO_MODE_PLXSD, 0},
- /*27*/ {VENDOR_CCD, "HFC-E1 Speech Design", 1, 1, 0, 0, 0, 0,
- HFC_IO_MODE_PLXSD, 0},
- /*28*/ {VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0, 0},
- /*29*/ {VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0, 0},
- /*30*/ {VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0, 0},
- /*31*/ {VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0,
- HFC_IO_MODE_EMBSD, XHFC_IRQ},
- /*32*/ {VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0},
- /*33*/ {VENDOR_BN, "HFC-2S Beronet Card PCIe", 4, 2, 1, 3, 0, DIP_4S, 0, 0},
- /*34*/ {VENDOR_BN, "HFC-4S Beronet Card PCIe", 4, 4, 1, 2, 0, DIP_4S, 0, 0},
-};
-
-#undef H
-#define H(x) ((unsigned long)&hfcm_map[x])
-static const struct pci_device_id hfmultipci_ids[] = {
-
- /* Cards with HFC-4S Chip */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_BN1SM, 0, 0, H(0)}, /* BN1S mini PCI */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_BN2S, 0, 0, H(1)}, /* BN2S */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_BN2SM, 0, 0, H(2)}, /* BN2S mini PCI */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_BN4S, 0, 0, H(3)}, /* BN4S */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_BN4SM, 0, 0, H(4)}, /* BN4S mini PCI */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_DEVICE_ID_CCD_HFC4S, 0, 0, H(5)}, /* Old Eval */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_IOB4ST, 0, 0, H(6)}, /* IOB4ST */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_HFC4S, 0, 0, H(7)}, /* 4S */
- { PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S,
- PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, 0, 0, H(8)},
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_SWYX4S, 0, 0, H(9)}, /* 4S Swyx */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_JH4S20, 0, 0, H(10)},
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_PMX2S, 0, 0, H(11)}, /* Primux */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_OV4S, 0, 0, H(28)}, /* OpenVox 4 */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_OV2S, 0, 0, H(29)}, /* OpenVox 2 */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- 0xb761, 0, 0, H(33)}, /* BN2S PCIe */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
- 0xb762, 0, 0, H(34)}, /* BN4S PCIe */
-
- /* Cards with HFC-8S Chip */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_BN8S, 0, 0, H(12)}, /* BN8S */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_BN8SP, 0, 0, H(13)}, /* BN8S+ */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
- PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, /* IOB8ST Recording */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_IOB8ST_1, 0, 0, H(17)}, /* IOB8ST */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_HFC8S, 0, 0, H(18)}, /* 8S */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_OV8S, 0, 0, H(30)}, /* OpenVox 8 */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_JH8S, 0, 0, H(32)}, /* Junganns 8S */
-
-
- /* Cards with HFC-E1 Chip */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_BNE1, 0, 0, H(19)}, /* BNE1 */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_BNE1M, 0, 0, H(20)}, /* BNE1 mini PCI */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_BNE1DP, 0, 0, H(21)}, /* BNE1 + (Dual) */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_BNE1D, 0, 0, H(22)}, /* BNE1 (Dual) */
-
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
- PCI_DEVICE_ID_CCD_HFCE1, 0, 0, H(23)}, /* Old Eval */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_IOB1E1, 0, 0, H(24)}, /* IOB1E1 */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_HFCE1, 0, 0, H(25)}, /* E1 */
-
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_SPD4S, 0, 0, H(26)}, /* PLX PCI Bridge */
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_SPDE1, 0, 0, H(27)}, /* PLX PCI Bridge */
-
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_JHSE1, 0, 0, H(25)}, /* Junghanns E1 */
-
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC4S), 0 },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC8S), 0 },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFCE1), 0 },
- {0, }
-};
-#undef H
-
-MODULE_DEVICE_TABLE(pci, hfmultipci_ids);
-
-static int
-hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- struct hm_map *m = (struct hm_map *)ent->driver_data;
- int ret;
-
- if (m == NULL && ent->vendor == PCI_VENDOR_ID_CCD && (
- ent->device == PCI_DEVICE_ID_CCD_HFC4S ||
- ent->device == PCI_DEVICE_ID_CCD_HFC8S ||
- ent->device == PCI_DEVICE_ID_CCD_HFCE1)) {
- printk(KERN_ERR
- "Unknown HFC multiport controller (vendor:%04x device:%04x "
- "subvendor:%04x subdevice:%04x)\n", pdev->vendor,
- pdev->device, pdev->subsystem_vendor,
- pdev->subsystem_device);
- printk(KERN_ERR
- "Please contact the driver maintainer for support.\n");
- return -ENODEV;
- }
- ret = hfcmulti_init(m, pdev, ent);
- if (ret)
- return ret;
- HFC_cnt++;
- printk(KERN_INFO "%d devices registered\n", HFC_cnt);
- return 0;
-}
-
-static struct pci_driver hfcmultipci_driver = {
- .name = "hfc_multi",
- .probe = hfcmulti_probe,
- .remove = hfc_remove_pci,
- .id_table = hfmultipci_ids,
-};
-
-static void __exit
-HFCmulti_cleanup(void)
-{
- struct hfc_multi *card, *next;
-
- /* get rid of all devices of this driver */
- list_for_each_entry_safe(card, next, &HFClist, list)
- release_card(card);
- pci_unregister_driver(&hfcmultipci_driver);
-}
-
-static int __init
-HFCmulti_init(void)
-{
- int err;
- int i, xhfc = 0;
- struct hm_map m;
-
- printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION);
-
-#ifdef IRQ_DEBUG
- printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__);
-#endif
-
- if (debug & DEBUG_HFCMULTI_INIT)
- printk(KERN_DEBUG "%s: init entered\n", __func__);
-
- switch (poll) {
- case 0:
- poll_timer = 6;
- poll = 128;
- break;
- case 8:
- poll_timer = 2;
- break;
- case 16:
- poll_timer = 3;
- break;
- case 32:
- poll_timer = 4;
- break;
- case 64:
- poll_timer = 5;
- break;
- case 128:
- poll_timer = 6;
- break;
- case 256:
- poll_timer = 7;
- break;
- default:
- printk(KERN_ERR
- "%s: Wrong poll value (%d).\n", __func__, poll);
- err = -EINVAL;
- return err;
-
- }
-
- if (!clock)
- clock = 1;
-
- /* Register the embedded devices.
- * This should be done before the PCI cards registration */
- switch (hwid) {
- case HWID_MINIP4:
- xhfc = 1;
- m = hfcm_map[31];
- break;
- case HWID_MINIP8:
- xhfc = 2;
- m = hfcm_map[31];
- break;
- case HWID_MINIP16:
- xhfc = 4;
- m = hfcm_map[31];
- break;
- default:
- xhfc = 0;
- }
-
- for (i = 0; i < xhfc; ++i) {
- err = hfcmulti_init(&m, NULL, NULL);
- if (err) {
- printk(KERN_ERR "error registering embedded driver: "
- "%x\n", err);
- return err;
- }
- HFC_cnt++;
- printk(KERN_INFO "%d devices registered\n", HFC_cnt);
- }
-
- /* Register the PCI cards */
- err = pci_register_driver(&hfcmultipci_driver);
- if (err < 0) {
- printk(KERN_ERR "error registering pci driver: %x\n", err);
- return err;
- }
-
- return 0;
-}
-
-
-module_init(HFCmulti_init);
-module_exit(HFCmulti_cleanup);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * hfcpci.c low level driver for CCD's hfc-pci based cards
- *
- * Author Werner Cornelius (werner@isdn4linux.de)
- * based on existing driver for CCD hfc ISA cards
- * type approval valid for HFC-S PCI A based card
- *
- * Copyright 1999 by Werner Cornelius (werner@isdn-development.de)
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- *
- * Module options:
- *
- * debug:
- * NOTE: only one poll value must be given for all cards
- * See hfc_pci.h for debug flags.
- *
- * poll:
- * NOTE: only one poll value must be given for all cards
- * Give the number of samples for each fifo process.
- * By default 128 is used. Decrease to reduce delay, increase to
- * reduce cpu load. If unsure, don't mess with it!
- * A value of 128 will use controller's interrupt. Other values will
- * use kernel timer, because the controller will not allow lower values
- * than 128.
- * Also note that the value depends on the kernel timer frequency.
- * If kernel uses a frequency of 1000 Hz, steps of 8 samples are possible.
- * If the kernel uses 100 Hz, steps of 80 samples are possible.
- * If the kernel uses 300 Hz, steps of about 26 samples are possible.
- */
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/mISDNhw.h>
-#include <linux/slab.h>
-
-#include "hfc_pci.h"
-
-static void hfcpci_softirq(struct timer_list *unused);
-static const char *hfcpci_revision = "2.0";
-
-static int HFC_cnt;
-static uint debug;
-static uint poll, tics;
-static DEFINE_TIMER(hfc_tl, hfcpci_softirq);
-static unsigned long hfc_jiffies;
-
-MODULE_AUTHOR("Karsten Keil");
-MODULE_DESCRIPTION("mISDN driver for CCD's hfc-pci based cards");
-MODULE_LICENSE("GPL");
-module_param(debug, uint, S_IRUGO | S_IWUSR);
-module_param(poll, uint, S_IRUGO | S_IWUSR);
-
-enum {
- HFC_CCD_2BD0,
- HFC_CCD_B000,
- HFC_CCD_B006,
- HFC_CCD_B007,
- HFC_CCD_B008,
- HFC_CCD_B009,
- HFC_CCD_B00A,
- HFC_CCD_B00B,
- HFC_CCD_B00C,
- HFC_CCD_B100,
- HFC_CCD_B700,
- HFC_CCD_B701,
- HFC_ASUS_0675,
- HFC_BERKOM_A1T,
- HFC_BERKOM_TCONCEPT,
- HFC_ANIGMA_MC145575,
- HFC_ZOLTRIX_2BD0,
- HFC_DIGI_DF_M_IOM2_E,
- HFC_DIGI_DF_M_E,
- HFC_DIGI_DF_M_IOM2_A,
- HFC_DIGI_DF_M_A,
- HFC_ABOCOM_2BD1,
- HFC_SITECOM_DC105V2,
-};
-
-struct hfcPCI_hw {
- unsigned char cirm;
- unsigned char ctmt;
- unsigned char clkdel;
- unsigned char states;
- unsigned char conn;
- unsigned char mst_m;
- unsigned char int_m1;
- unsigned char int_m2;
- unsigned char sctrl;
- unsigned char sctrl_r;
- unsigned char sctrl_e;
- unsigned char trm;
- unsigned char fifo_en;
- unsigned char bswapped;
- unsigned char protocol;
- int nt_timer;
- unsigned char __iomem *pci_io; /* start of PCI IO memory */
- dma_addr_t dmahandle;
- void *fifos; /* FIFO memory */
- int last_bfifo_cnt[2];
- /* marker saving last b-fifo frame count */
- struct timer_list timer;
-};
-
-#define HFC_CFG_MASTER 1
-#define HFC_CFG_SLAVE 2
-#define HFC_CFG_PCM 3
-#define HFC_CFG_2HFC 4
-#define HFC_CFG_SLAVEHFC 5
-#define HFC_CFG_NEG_F0 6
-#define HFC_CFG_SW_DD_DU 7
-
-#define FLG_HFC_TIMER_T1 16
-#define FLG_HFC_TIMER_T3 17
-
-#define NT_T1_COUNT 1120 /* number of 3.125ms interrupts (3.5s) */
-#define NT_T3_COUNT 31 /* number of 3.125ms interrupts (97 ms) */
-#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */
-#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */
-
-
-struct hfc_pci {
- u_char subtype;
- u_char chanlimit;
- u_char initdone;
- u_long cfg;
- u_int irq;
- u_int irqcnt;
- struct pci_dev *pdev;
- struct hfcPCI_hw hw;
- spinlock_t lock; /* card lock */
- struct dchannel dch;
- struct bchannel bch[2];
-};
-
-/* Interface functions */
-static void
-enable_hwirq(struct hfc_pci *hc)
-{
- hc->hw.int_m2 |= HFCPCI_IRQ_ENABLE;
- Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
-}
-
-static void
-disable_hwirq(struct hfc_pci *hc)
-{
- hc->hw.int_m2 &= ~((u_char)HFCPCI_IRQ_ENABLE);
- Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
-}
-
-/*
- * free hardware resources used by driver
- */
-static void
-release_io_hfcpci(struct hfc_pci *hc)
-{
- /* disable memory mapped ports + busmaster */
- pci_write_config_word(hc->pdev, PCI_COMMAND, 0);
- timer_delete(&hc->hw.timer);
- dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos,
- hc->hw.dmahandle);
- iounmap(hc->hw.pci_io);
-}
-
-/*
- * set mode (NT or TE)
- */
-static void
-hfcpci_setmode(struct hfc_pci *hc)
-{
- if (hc->hw.protocol == ISDN_P_NT_S0) {
- hc->hw.clkdel = CLKDEL_NT; /* ST-Bit delay for NT-Mode */
- hc->hw.sctrl |= SCTRL_MODE_NT; /* NT-MODE */
- hc->hw.states = 1; /* G1 */
- } else {
- hc->hw.clkdel = CLKDEL_TE; /* ST-Bit delay for TE-Mode */
- hc->hw.sctrl &= ~SCTRL_MODE_NT; /* TE-MODE */
- hc->hw.states = 2; /* F2 */
- }
- Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel);
- Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | hc->hw.states);
- udelay(10);
- Write_hfc(hc, HFCPCI_STATES, hc->hw.states | 0x40); /* Deactivate */
- Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl);
-}
-
-/*
- * function called to reset the HFC PCI chip. A complete software reset of chip
- * and fifos is done.
- */
-static void
-reset_hfcpci(struct hfc_pci *hc)
-{
- u_char val;
- int cnt = 0;
-
- printk(KERN_DEBUG "reset_hfcpci: entered\n");
- val = Read_hfc(hc, HFCPCI_CHIP_ID);
- printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val);
- /* enable memory mapped ports, disable busmaster */
- pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO);
- disable_hwirq(hc);
- /* enable memory ports + busmaster */
- pci_write_config_word(hc->pdev, PCI_COMMAND,
- PCI_ENA_MEMIO + PCI_ENA_MASTER);
- val = Read_hfc(hc, HFCPCI_STATUS);
- printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val);
- hc->hw.cirm = HFCPCI_RESET; /* Reset On */
- Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
- set_current_state(TASK_UNINTERRUPTIBLE);
- mdelay(10); /* Timeout 10ms */
- hc->hw.cirm = 0; /* Reset Off */
- Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
- val = Read_hfc(hc, HFCPCI_STATUS);
- printk(KERN_DEBUG "HFC-PCI status(%x) after reset\n", val);
- while (cnt < 50000) { /* max 50000 us */
- udelay(5);
- cnt += 5;
- val = Read_hfc(hc, HFCPCI_STATUS);
- if (!(val & 2))
- break;
- }
- printk(KERN_DEBUG "HFC-PCI status(%x) after %dus\n", val, cnt);
-
- hc->hw.fifo_en = 0x30; /* only D fifos enabled */
-
- hc->hw.bswapped = 0; /* no exchange */
- hc->hw.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
- hc->hw.trm = HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */
- hc->hw.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
- hc->hw.sctrl_r = 0;
- hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE; /* S/T Auto awake */
- hc->hw.mst_m = 0;
- if (test_bit(HFC_CFG_MASTER, &hc->cfg))
- hc->hw.mst_m |= HFCPCI_MASTER; /* HFC Master Mode */
- if (test_bit(HFC_CFG_NEG_F0, &hc->cfg))
- hc->hw.mst_m |= HFCPCI_F0_NEGATIV;
- Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
- Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
- Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e);
- Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
-
- hc->hw.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
- HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER;
- Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
-
- /* Clear already pending ints */
- val = Read_hfc(hc, HFCPCI_INT_S1);
-
- /* set NT/TE mode */
- hfcpci_setmode(hc);
-
- Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
- Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
-
- /*
- * Init GCI/IOM2 in master mode
- * Slots 0 and 1 are set for B-chan 1 and 2
- * D- and monitor/CI channel are not enabled
- * STIO1 is used as output for data, B1+B2 from ST->IOM+HFC
- * STIO2 is used as data input, B1+B2 from IOM->ST
- * ST B-channel send disabled -> continuous 1s
- * The IOM slots are always enabled
- */
- if (test_bit(HFC_CFG_PCM, &hc->cfg)) {
- /* set data flow directions: connect B1,B2: HFC to/from PCM */
- hc->hw.conn = 0x09;
- } else {
- hc->hw.conn = 0x36; /* set data flow directions */
- if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) {
- Write_hfc(hc, HFCPCI_B1_SSL, 0xC0);
- Write_hfc(hc, HFCPCI_B2_SSL, 0xC1);
- Write_hfc(hc, HFCPCI_B1_RSL, 0xC0);
- Write_hfc(hc, HFCPCI_B2_RSL, 0xC1);
- } else {
- Write_hfc(hc, HFCPCI_B1_SSL, 0x80);
- Write_hfc(hc, HFCPCI_B2_SSL, 0x81);
- Write_hfc(hc, HFCPCI_B1_RSL, 0x80);
- Write_hfc(hc, HFCPCI_B2_RSL, 0x81);
- }
- }
- Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
- val = Read_hfc(hc, HFCPCI_INT_S2);
-}
-
-/*
- * Timer function called when kernel timer expires
- */
-static void
-hfcpci_Timer(struct timer_list *t)
-{
- struct hfc_pci *hc = timer_container_of(hc, t, hw.timer);
- hc->hw.timer.expires = jiffies + 75;
- /* WD RESET */
-/*
- * WriteReg(hc, HFCD_DATA, HFCD_CTMT, hc->hw.ctmt | 0x80);
- * add_timer(&hc->hw.timer);
- */
-}
-
-
-/*
- * select a b-channel entry matching and active
- */
-static struct bchannel *
-Sel_BCS(struct hfc_pci *hc, int channel)
-{
- if (test_bit(FLG_ACTIVE, &hc->bch[0].Flags) &&
- (hc->bch[0].nr & channel))
- return &hc->bch[0];
- else if (test_bit(FLG_ACTIVE, &hc->bch[1].Flags) &&
- (hc->bch[1].nr & channel))
- return &hc->bch[1];
- else
- return NULL;
-}
-
-/*
- * clear the desired B-channel rx fifo
- */
-static void
-hfcpci_clear_fifo_rx(struct hfc_pci *hc, int fifo)
-{
- u_char fifo_state;
- struct bzfifo *bzr;
-
- if (fifo) {
- bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
- fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2RX;
- } else {
- bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
- fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1RX;
- }
- if (fifo_state)
- hc->hw.fifo_en ^= fifo_state;
- Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
- hc->hw.last_bfifo_cnt[fifo] = 0;
- bzr->f1 = MAX_B_FRAMES;
- bzr->f2 = bzr->f1; /* init F pointers to remain constant */
- bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
- bzr->za[MAX_B_FRAMES].z2 = cpu_to_le16(
- le16_to_cpu(bzr->za[MAX_B_FRAMES].z1));
- if (fifo_state)
- hc->hw.fifo_en |= fifo_state;
- Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
-}
-
-/*
- * clear the desired B-channel tx fifo
- */
-static void hfcpci_clear_fifo_tx(struct hfc_pci *hc, int fifo)
-{
- u_char fifo_state;
- struct bzfifo *bzt;
-
- if (fifo) {
- bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
- fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2TX;
- } else {
- bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
- fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1TX;
- }
- if (fifo_state)
- hc->hw.fifo_en ^= fifo_state;
- Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
- if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL)
- printk(KERN_DEBUG "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) "
- "z1(%x) z2(%x) state(%x)\n",
- fifo, bzt->f1, bzt->f2,
- le16_to_cpu(bzt->za[MAX_B_FRAMES].z1),
- le16_to_cpu(bzt->za[MAX_B_FRAMES].z2),
- fifo_state);
- bzt->f2 = MAX_B_FRAMES;
- bzt->f1 = bzt->f2; /* init F pointers to remain constant */
- bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
- bzt->za[MAX_B_FRAMES].z2 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 2);
- if (fifo_state)
- hc->hw.fifo_en |= fifo_state;
- Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
- if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL)
- printk(KERN_DEBUG
- "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x)\n",
- fifo, bzt->f1, bzt->f2,
- le16_to_cpu(bzt->za[MAX_B_FRAMES].z1),
- le16_to_cpu(bzt->za[MAX_B_FRAMES].z2));
-}
-
-/*
- * read a complete B-frame out of the buffer
- */
-static void
-hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz,
- u_char *bdata, int count)
-{
- u_char *ptr, *ptr1, new_f2;
- int maxlen, new_z2;
- struct zt *zp;
-
- if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO))
- printk(KERN_DEBUG "hfcpci_empty_fifo\n");
- zp = &bz->za[bz->f2]; /* point to Z-Regs */
- new_z2 = le16_to_cpu(zp->z2) + count; /* new position in fifo */
- if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
- new_z2 -= B_FIFO_SIZE; /* buffer wrap */
- new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
- if ((count > MAX_DATA_SIZE + 3) || (count < 4) ||
- (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) {
- if (bch->debug & DEBUG_HW)
- printk(KERN_DEBUG "hfcpci_empty_fifo: incoming packet "
- "invalid length %d or crc\n", count);
-#ifdef ERROR_STATISTIC
- bch->err_inv++;
-#endif
- bz->za[new_f2].z2 = cpu_to_le16(new_z2);
- bz->f2 = new_f2; /* next buffer */
- } else {
- bch->rx_skb = mI_alloc_skb(count - 3, GFP_ATOMIC);
- if (!bch->rx_skb) {
- printk(KERN_WARNING "HFCPCI: receive out of memory\n");
- return;
- }
- count -= 3;
- ptr = skb_put(bch->rx_skb, count);
-
- if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL)
- maxlen = count; /* complete transfer */
- else
- maxlen = B_FIFO_SIZE + B_SUB_VAL -
- le16_to_cpu(zp->z2); /* maximum */
-
- ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL);
- /* start of data */
- memcpy(ptr, ptr1, maxlen); /* copy data */
- count -= maxlen;
-
- if (count) { /* rest remaining */
- ptr += maxlen;
- ptr1 = bdata; /* start of buffer */
- memcpy(ptr, ptr1, count); /* rest */
- }
- bz->za[new_f2].z2 = cpu_to_le16(new_z2);
- bz->f2 = new_f2; /* next buffer */
- recv_Bchannel(bch, MISDN_ID_ANY, false);
- }
-}
-
-/*
- * D-channel receive procedure
- */
-static int
-receive_dmsg(struct hfc_pci *hc)
-{
- struct dchannel *dch = &hc->dch;
- int maxlen;
- int rcnt, total;
- int count = 5;
- u_char *ptr, *ptr1;
- struct dfifo *df;
- struct zt *zp;
-
- df = &((union fifo_area *)(hc->hw.fifos))->d_chan.d_rx;
- while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) {
- zp = &df->za[df->f2 & D_FREG_MASK];
- rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
- if (rcnt < 0)
- rcnt += D_FIFO_SIZE;
- rcnt++;
- if (dch->debug & DEBUG_HW_DCHANNEL)
- printk(KERN_DEBUG
- "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)\n",
- df->f1, df->f2,
- le16_to_cpu(zp->z1),
- le16_to_cpu(zp->z2),
- rcnt);
-
- if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) ||
- (df->data[le16_to_cpu(zp->z1)])) {
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG
- "empty_fifo hfcpci packet inv. len "
- "%d or crc %d\n",
- rcnt,
- df->data[le16_to_cpu(zp->z1)]);
-#ifdef ERROR_STATISTIC
- cs->err_rx++;
-#endif
- df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) |
- (MAX_D_FRAMES + 1); /* next buffer */
- df->za[df->f2 & D_FREG_MASK].z2 =
- cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) &
- (D_FIFO_SIZE - 1));
- } else {
- dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC);
- if (!dch->rx_skb) {
- printk(KERN_WARNING
- "HFC-PCI: D receive out of memory\n");
- break;
- }
- total = rcnt;
- rcnt -= 3;
- ptr = skb_put(dch->rx_skb, rcnt);
-
- if (le16_to_cpu(zp->z2) + rcnt <= D_FIFO_SIZE)
- maxlen = rcnt; /* complete transfer */
- else
- maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2);
- /* maximum */
-
- ptr1 = df->data + le16_to_cpu(zp->z2);
- /* start of data */
- memcpy(ptr, ptr1, maxlen); /* copy data */
- rcnt -= maxlen;
-
- if (rcnt) { /* rest remaining */
- ptr += maxlen;
- ptr1 = df->data; /* start of buffer */
- memcpy(ptr, ptr1, rcnt); /* rest */
- }
- df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) |
- (MAX_D_FRAMES + 1); /* next buffer */
- df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((
- le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1));
- recv_Dchannel(dch);
- }
- }
- return 1;
-}
-
-/*
- * check for transparent receive data and read max one 'poll' size if avail
- */
-static void
-hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
- struct bzfifo *txbz, u_char *bdata)
-{
- __le16 *z1r, *z2r, *z1t, *z2t;
- int new_z2, fcnt_rx, fcnt_tx, maxlen;
- u_char *ptr, *ptr1;
-
- z1r = &rxbz->za[MAX_B_FRAMES].z1; /* pointer to z reg */
- z2r = z1r + 1;
- z1t = &txbz->za[MAX_B_FRAMES].z1;
- z2t = z1t + 1;
-
- fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r);
- if (!fcnt_rx)
- return; /* no data avail */
-
- if (fcnt_rx <= 0)
- fcnt_rx += B_FIFO_SIZE; /* bytes actually buffered */
- new_z2 = le16_to_cpu(*z2r) + fcnt_rx; /* new position in fifo */
- if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
- new_z2 -= B_FIFO_SIZE; /* buffer wrap */
-
- fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
- if (fcnt_tx <= 0)
- fcnt_tx += B_FIFO_SIZE;
- /* fcnt_tx contains available bytes in tx-fifo */
- fcnt_tx = B_FIFO_SIZE - fcnt_tx;
- /* remaining bytes to send (bytes in tx-fifo) */
-
- if (test_bit(FLG_RX_OFF, &bch->Flags)) {
- bch->dropcnt += fcnt_rx;
- *z2r = cpu_to_le16(new_z2);
- return;
- }
- maxlen = bchannel_get_rxbuf(bch, fcnt_rx);
- if (maxlen < 0) {
- pr_warn("B%d: No bufferspace for %d bytes\n", bch->nr, fcnt_rx);
- } else {
- ptr = skb_put(bch->rx_skb, fcnt_rx);
- if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL)
- maxlen = fcnt_rx; /* complete transfer */
- else
- maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r);
- /* maximum */
-
- ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL);
- /* start of data */
- memcpy(ptr, ptr1, maxlen); /* copy data */
- fcnt_rx -= maxlen;
-
- if (fcnt_rx) { /* rest remaining */
- ptr += maxlen;
- ptr1 = bdata; /* start of buffer */
- memcpy(ptr, ptr1, fcnt_rx); /* rest */
- }
- recv_Bchannel(bch, fcnt_tx, false); /* bch, id, !force */
- }
- *z2r = cpu_to_le16(new_z2); /* new position */
-}
-
-/*
- * B-channel main receive routine
- */
-static void
-main_rec_hfcpci(struct bchannel *bch)
-{
- struct hfc_pci *hc = bch->hw;
- int rcnt, real_fifo;
- int receive = 0, count = 5;
- struct bzfifo *txbz, *rxbz;
- u_char *bdata;
- struct zt *zp;
-
- if ((bch->nr & 2) && (!hc->hw.bswapped)) {
- rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
- txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
- bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2;
- real_fifo = 1;
- } else {
- rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
- txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
- bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1;
- real_fifo = 0;
- }
-Begin:
- count--;
- if (rxbz->f1 != rxbz->f2) {
- if (bch->debug & DEBUG_HW_BCHANNEL)
- printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n",
- bch->nr, rxbz->f1, rxbz->f2);
- zp = &rxbz->za[rxbz->f2];
-
- rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
- if (rcnt < 0)
- rcnt += B_FIFO_SIZE;
- rcnt++;
- if (bch->debug & DEBUG_HW_BCHANNEL)
- printk(KERN_DEBUG
- "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n",
- bch->nr, le16_to_cpu(zp->z1),
- le16_to_cpu(zp->z2), rcnt);
- hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt);
- rcnt = rxbz->f1 - rxbz->f2;
- if (rcnt < 0)
- rcnt += MAX_B_FRAMES + 1;
- if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) {
- rcnt = 0;
- hfcpci_clear_fifo_rx(hc, real_fifo);
- }
- hc->hw.last_bfifo_cnt[real_fifo] = rcnt;
- if (rcnt > 1)
- receive = 1;
- else
- receive = 0;
- } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
- hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata);
- return;
- } else
- receive = 0;
- if (count && receive)
- goto Begin;
-
-}
-
-/*
- * D-channel send routine
- */
-static void
-hfcpci_fill_dfifo(struct hfc_pci *hc)
-{
- struct dchannel *dch = &hc->dch;
- int fcnt;
- int count, new_z1, maxlen;
- struct dfifo *df;
- u_char *src, *dst, new_f1;
-
- if ((dch->debug & DEBUG_HW_DCHANNEL) && !(dch->debug & DEBUG_HW_DFIFO))
- printk(KERN_DEBUG "%s\n", __func__);
-
- if (!dch->tx_skb)
- return;
- count = dch->tx_skb->len - dch->tx_idx;
- if (count <= 0)
- return;
- df = &((union fifo_area *) (hc->hw.fifos))->d_chan.d_tx;
-
- if (dch->debug & DEBUG_HW_DFIFO)
- printk(KERN_DEBUG "%s:f1(%d) f2(%d) z1(f1)(%x)\n", __func__,
- df->f1, df->f2,
- le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1));
- fcnt = df->f1 - df->f2; /* frame count actually buffered */
- if (fcnt < 0)
- fcnt += (MAX_D_FRAMES + 1); /* if wrap around */
- if (fcnt > (MAX_D_FRAMES - 1)) {
- if (dch->debug & DEBUG_HW_DCHANNEL)
- printk(KERN_DEBUG
- "hfcpci_fill_Dfifo more as 14 frames\n");
-#ifdef ERROR_STATISTIC
- cs->err_tx++;
-#endif
- return;
- }
- /* now determine free bytes in FIFO buffer */
- maxlen = le16_to_cpu(df->za[df->f2 & D_FREG_MASK].z2) -
- le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) - 1;
- if (maxlen <= 0)
- maxlen += D_FIFO_SIZE; /* count now contains available bytes */
-
- if (dch->debug & DEBUG_HW_DCHANNEL)
- printk(KERN_DEBUG "hfcpci_fill_Dfifo count(%d/%d)\n",
- count, maxlen);
- if (count > maxlen) {
- if (dch->debug & DEBUG_HW_DCHANNEL)
- printk(KERN_DEBUG "hfcpci_fill_Dfifo no fifo mem\n");
- return;
- }
- new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) &
- (D_FIFO_SIZE - 1);
- new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1);
- src = dch->tx_skb->data + dch->tx_idx; /* source pointer */
- dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);
- maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);
- /* end fifo */
- if (maxlen > count)
- maxlen = count; /* limit size */
- memcpy(dst, src, maxlen); /* first copy */
-
- count -= maxlen; /* remaining bytes */
- if (count) {
- dst = df->data; /* start of buffer */
- src += maxlen; /* new position */
- memcpy(dst, src, count);
- }
- df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);
- /* for next buffer */
- df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);
- /* new pos actual buffer */
- df->f1 = new_f1; /* next frame */
- dch->tx_idx = dch->tx_skb->len;
-}
-
-/*
- * B-channel send routine
- */
-static void
-hfcpci_fill_fifo(struct bchannel *bch)
-{
- struct hfc_pci *hc = bch->hw;
- int maxlen, fcnt;
- int count, new_z1;
- struct bzfifo *bz;
- u_char *bdata;
- u_char new_f1, *src, *dst;
- __le16 *z1t, *z2t;
-
- if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO))
- printk(KERN_DEBUG "%s\n", __func__);
- if ((!bch->tx_skb) || bch->tx_skb->len == 0) {
- if (!test_bit(FLG_FILLEMPTY, &bch->Flags) &&
- !test_bit(FLG_TRANSPARENT, &bch->Flags))
- return;
- count = HFCPCI_FILLEMPTY;
- } else {
- count = bch->tx_skb->len - bch->tx_idx;
- }
- if ((bch->nr & 2) && (!hc->hw.bswapped)) {
- bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
- bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b2;
- } else {
- bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
- bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b1;
- }
-
- if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
- z1t = &bz->za[MAX_B_FRAMES].z1;
- z2t = z1t + 1;
- if (bch->debug & DEBUG_HW_BCHANNEL)
- printk(KERN_DEBUG "hfcpci_fill_fifo_trans ch(%x) "
- "cnt(%d) z1(%x) z2(%x)\n", bch->nr, count,
- le16_to_cpu(*z1t), le16_to_cpu(*z2t));
- fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
- if (fcnt <= 0)
- fcnt += B_FIFO_SIZE;
- if (test_bit(FLG_FILLEMPTY, &bch->Flags)) {
- /* fcnt contains available bytes in fifo */
- if (count > fcnt)
- count = fcnt;
- new_z1 = le16_to_cpu(*z1t) + count;
- /* new buffer Position */
- if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
- new_z1 -= B_FIFO_SIZE; /* buffer wrap */
- dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL);
- maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t);
- /* end of fifo */
- if (bch->debug & DEBUG_HW_BFIFO)
- printk(KERN_DEBUG "hfcpci_FFt fillempty "
- "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n",
- fcnt, maxlen, new_z1, dst);
- if (maxlen > count)
- maxlen = count; /* limit size */
- memset(dst, bch->fill[0], maxlen); /* first copy */
- count -= maxlen; /* remaining bytes */
- if (count) {
- dst = bdata; /* start of buffer */
- memset(dst, bch->fill[0], count);
- }
- *z1t = cpu_to_le16(new_z1); /* now send data */
- return;
- }
- /* fcnt contains available bytes in fifo */
- fcnt = B_FIFO_SIZE - fcnt;
- /* remaining bytes to send (bytes in fifo) */
-
- next_t_frame:
- count = bch->tx_skb->len - bch->tx_idx;
- /* maximum fill shall be poll*2 */
- if (count > (poll << 1) - fcnt)
- count = (poll << 1) - fcnt;
- if (count <= 0)
- return;
- /* data is suitable for fifo */
- new_z1 = le16_to_cpu(*z1t) + count;
- /* new buffer Position */
- if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
- new_z1 -= B_FIFO_SIZE; /* buffer wrap */
- src = bch->tx_skb->data + bch->tx_idx;
- /* source pointer */
- dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL);
- maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t);
- /* end of fifo */
- if (bch->debug & DEBUG_HW_BFIFO)
- printk(KERN_DEBUG "hfcpci_FFt fcnt(%d) "
- "maxl(%d) nz1(%x) dst(%p)\n",
- fcnt, maxlen, new_z1, dst);
- fcnt += count;
- bch->tx_idx += count;
- if (maxlen > count)
- maxlen = count; /* limit size */
- memcpy(dst, src, maxlen); /* first copy */
- count -= maxlen; /* remaining bytes */
- if (count) {
- dst = bdata; /* start of buffer */
- src += maxlen; /* new position */
- memcpy(dst, src, count);
- }
- *z1t = cpu_to_le16(new_z1); /* now send data */
- if (bch->tx_idx < bch->tx_skb->len)
- return;
- dev_kfree_skb_any(bch->tx_skb);
- if (get_next_bframe(bch))
- goto next_t_frame;
- return;
- }
- if (bch->debug & DEBUG_HW_BCHANNEL)
- printk(KERN_DEBUG
- "%s: ch(%x) f1(%d) f2(%d) z1(f1)(%x)\n",
- __func__, bch->nr, bz->f1, bz->f2,
- bz->za[bz->f1].z1);
- fcnt = bz->f1 - bz->f2; /* frame count actually buffered */
- if (fcnt < 0)
- fcnt += (MAX_B_FRAMES + 1); /* if wrap around */
- if (fcnt > (MAX_B_FRAMES - 1)) {
- if (bch->debug & DEBUG_HW_BCHANNEL)
- printk(KERN_DEBUG
- "hfcpci_fill_Bfifo more as 14 frames\n");
- return;
- }
- /* now determine free bytes in FIFO buffer */
- maxlen = le16_to_cpu(bz->za[bz->f2].z2) -
- le16_to_cpu(bz->za[bz->f1].z1) - 1;
- if (maxlen <= 0)
- maxlen += B_FIFO_SIZE; /* count now contains available bytes */
-
- if (bch->debug & DEBUG_HW_BCHANNEL)
- printk(KERN_DEBUG "hfcpci_fill_fifo ch(%x) count(%d/%d)\n",
- bch->nr, count, maxlen);
-
- if (maxlen < count) {
- if (bch->debug & DEBUG_HW_BCHANNEL)
- printk(KERN_DEBUG "hfcpci_fill_fifo no fifo mem\n");
- return;
- }
- new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count;
- /* new buffer Position */
- if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
- new_z1 -= B_FIFO_SIZE; /* buffer wrap */
-
- new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES);
- src = bch->tx_skb->data + bch->tx_idx; /* source pointer */
- dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL);
- maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1);
- /* end fifo */
- if (maxlen > count)
- maxlen = count; /* limit size */
- memcpy(dst, src, maxlen); /* first copy */
-
- count -= maxlen; /* remaining bytes */
- if (count) {
- dst = bdata; /* start of buffer */
- src += maxlen; /* new position */
- memcpy(dst, src, count);
- }
- bz->za[new_f1].z1 = cpu_to_le16(new_z1); /* for next buffer */
- bz->f1 = new_f1; /* next frame */
- dev_kfree_skb_any(bch->tx_skb);
- get_next_bframe(bch);
-}
-
-
-
-/*
- * handle L1 state changes TE
- */
-
-static void
-ph_state_te(struct dchannel *dch)
-{
- if (dch->debug)
- printk(KERN_DEBUG "%s: TE newstate %x\n",
- __func__, dch->state);
- switch (dch->state) {
- case 0:
- l1_event(dch->l1, HW_RESET_IND);
- break;
- case 3:
- l1_event(dch->l1, HW_DEACT_IND);
- break;
- case 5:
- case 8:
- l1_event(dch->l1, ANYSIGNAL);
- break;
- case 6:
- l1_event(dch->l1, INFO2);
- break;
- case 7:
- l1_event(dch->l1, INFO4_P8);
- break;
- }
-}
-
-/*
- * handle L1 state changes NT
- */
-
-static void
-handle_nt_timer3(struct dchannel *dch) {
- struct hfc_pci *hc = dch->hw;
-
- test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
- hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
- Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
- hc->hw.nt_timer = 0;
- test_and_set_bit(FLG_ACTIVE, &dch->Flags);
- if (test_bit(HFC_CFG_MASTER, &hc->cfg))
- hc->hw.mst_m |= HFCPCI_MASTER;
- Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
- _queue_data(&dch->dev.D, PH_ACTIVATE_IND,
- MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
-}
-
-static void
-ph_state_nt(struct dchannel *dch)
-{
- struct hfc_pci *hc = dch->hw;
-
- if (dch->debug)
- printk(KERN_DEBUG "%s: NT newstate %x\n",
- __func__, dch->state);
- switch (dch->state) {
- case 2:
- if (hc->hw.nt_timer < 0) {
- hc->hw.nt_timer = 0;
- test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
- test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
- hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
- Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
- /* Clear already pending ints */
- (void) Read_hfc(hc, HFCPCI_INT_S1);
- Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
- udelay(10);
- Write_hfc(hc, HFCPCI_STATES, 4);
- dch->state = 4;
- } else if (hc->hw.nt_timer == 0) {
- hc->hw.int_m1 |= HFCPCI_INTS_TIMER;
- Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
- hc->hw.nt_timer = NT_T1_COUNT;
- hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER;
- hc->hw.ctmt |= HFCPCI_TIM3_125;
- Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt |
- HFCPCI_CLTIMER);
- test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
- test_and_set_bit(FLG_HFC_TIMER_T1, &dch->Flags);
- /* allow G2 -> G3 transition */
- Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3);
- } else {
- Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3);
- }
- break;
- case 1:
- hc->hw.nt_timer = 0;
- test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
- test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
- hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
- Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
- test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
- hc->hw.mst_m &= ~HFCPCI_MASTER;
- Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
- test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
- _queue_data(&dch->dev.D, PH_DEACTIVATE_IND,
- MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
- break;
- case 4:
- hc->hw.nt_timer = 0;
- test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
- test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
- hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
- Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
- break;
- case 3:
- if (!test_and_set_bit(FLG_HFC_TIMER_T3, &dch->Flags)) {
- if (!test_and_clear_bit(FLG_L2_ACTIVATED,
- &dch->Flags)) {
- handle_nt_timer3(dch);
- break;
- }
- test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
- hc->hw.int_m1 |= HFCPCI_INTS_TIMER;
- Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
- hc->hw.nt_timer = NT_T3_COUNT;
- hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER;
- hc->hw.ctmt |= HFCPCI_TIM3_125;
- Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt |
- HFCPCI_CLTIMER);
- }
- break;
- }
-}
-
-static void
-ph_state(struct dchannel *dch)
-{
- struct hfc_pci *hc = dch->hw;
-
- if (hc->hw.protocol == ISDN_P_NT_S0) {
- if (test_bit(FLG_HFC_TIMER_T3, &dch->Flags) &&
- hc->hw.nt_timer < 0)
- handle_nt_timer3(dch);
- else
- ph_state_nt(dch);
- } else
- ph_state_te(dch);
-}
-
-/*
- * Layer 1 callback function
- */
-static int
-hfc_l1callback(struct dchannel *dch, u_int cmd)
-{
- struct hfc_pci *hc = dch->hw;
-
- switch (cmd) {
- case INFO3_P8:
- case INFO3_P10:
- if (test_bit(HFC_CFG_MASTER, &hc->cfg))
- hc->hw.mst_m |= HFCPCI_MASTER;
- Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
- break;
- case HW_RESET_REQ:
- Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3);
- /* HFC ST 3 */
- udelay(6);
- Write_hfc(hc, HFCPCI_STATES, 3); /* HFC ST 2 */
- if (test_bit(HFC_CFG_MASTER, &hc->cfg))
- hc->hw.mst_m |= HFCPCI_MASTER;
- Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
- Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE |
- HFCPCI_DO_ACTION);
- l1_event(dch->l1, HW_POWERUP_IND);
- break;
- case HW_DEACT_REQ:
- hc->hw.mst_m &= ~HFCPCI_MASTER;
- Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
- skb_queue_purge(&dch->squeue);
- if (dch->tx_skb) {
- dev_kfree_skb(dch->tx_skb);
- dch->tx_skb = NULL;
- }
- dch->tx_idx = 0;
- if (dch->rx_skb) {
- dev_kfree_skb(dch->rx_skb);
- dch->rx_skb = NULL;
- }
- test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
- if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
- timer_delete(&dch->timer);
- break;
- case HW_POWERUP_REQ:
- Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION);
- break;
- case PH_ACTIVATE_IND:
- test_and_set_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
- GFP_ATOMIC);
- break;
- case PH_DEACTIVATE_IND:
- test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
- GFP_ATOMIC);
- break;
- default:
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: unknown command %x\n",
- __func__, cmd);
- return -1;
- }
- return 0;
-}
-
-/*
- * Interrupt handler
- */
-static inline void
-tx_birq(struct bchannel *bch)
-{
- if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
- hfcpci_fill_fifo(bch);
- else {
- dev_kfree_skb_any(bch->tx_skb);
- if (get_next_bframe(bch))
- hfcpci_fill_fifo(bch);
- }
-}
-
-static inline void
-tx_dirq(struct dchannel *dch)
-{
- if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len)
- hfcpci_fill_dfifo(dch->hw);
- else {
- dev_kfree_skb(dch->tx_skb);
- if (get_next_dframe(dch))
- hfcpci_fill_dfifo(dch->hw);
- }
-}
-
-static irqreturn_t
-hfcpci_int(int intno, void *dev_id)
-{
- struct hfc_pci *hc = dev_id;
- u_char exval;
- struct bchannel *bch;
- u_char val, stat;
-
- spin_lock(&hc->lock);
- if (!(hc->hw.int_m2 & 0x08)) {
- spin_unlock(&hc->lock);
- return IRQ_NONE; /* not initialised */
- }
- stat = Read_hfc(hc, HFCPCI_STATUS);
- if (HFCPCI_ANYINT & stat) {
- val = Read_hfc(hc, HFCPCI_INT_S1);
- if (hc->dch.debug & DEBUG_HW_DCHANNEL)
- printk(KERN_DEBUG
- "HFC-PCI: stat(%02x) s1(%02x)\n", stat, val);
- } else {
- /* shared */
- spin_unlock(&hc->lock);
- return IRQ_NONE;
- }
- hc->irqcnt++;
-
- if (hc->dch.debug & DEBUG_HW_DCHANNEL)
- printk(KERN_DEBUG "HFC-PCI irq %x\n", val);
- val &= hc->hw.int_m1;
- if (val & 0x40) { /* state machine irq */
- exval = Read_hfc(hc, HFCPCI_STATES) & 0xf;
- if (hc->dch.debug & DEBUG_HW_DCHANNEL)
- printk(KERN_DEBUG "ph_state chg %d->%d\n",
- hc->dch.state, exval);
- hc->dch.state = exval;
- schedule_event(&hc->dch, FLG_PHCHANGE);
- val &= ~0x40;
- }
- if (val & 0x80) { /* timer irq */
- if (hc->hw.protocol == ISDN_P_NT_S0) {
- if ((--hc->hw.nt_timer) < 0)
- schedule_event(&hc->dch, FLG_PHCHANGE);
- }
- val &= ~0x80;
- Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
- }
- if (val & 0x08) { /* B1 rx */
- bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
- if (bch)
- main_rec_hfcpci(bch);
- else if (hc->dch.debug)
- printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n");
- }
- if (val & 0x10) { /* B2 rx */
- bch = Sel_BCS(hc, 2);
- if (bch)
- main_rec_hfcpci(bch);
- else if (hc->dch.debug)
- printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n");
- }
- if (val & 0x01) { /* B1 tx */
- bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
- if (bch)
- tx_birq(bch);
- else if (hc->dch.debug)
- printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n");
- }
- if (val & 0x02) { /* B2 tx */
- bch = Sel_BCS(hc, 2);
- if (bch)
- tx_birq(bch);
- else if (hc->dch.debug)
- printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n");
- }
- if (val & 0x20) /* D rx */
- receive_dmsg(hc);
- if (val & 0x04) { /* D tx */
- if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags))
- timer_delete(&hc->dch.timer);
- tx_dirq(&hc->dch);
- }
- spin_unlock(&hc->lock);
- return IRQ_HANDLED;
-}
-
-/*
- * timer callback for D-chan busy resolution. Currently no function
- */
-static void
-hfcpci_dbusy_timer(struct timer_list *t)
-{
-}
-
-/*
- * activate/deactivate hardware for selected channels and mode
- */
-static int
-mode_hfcpci(struct bchannel *bch, int bc, int protocol)
-{
- struct hfc_pci *hc = bch->hw;
- int fifo2;
- u_char rx_slot = 0, tx_slot = 0, pcm_mode;
-
- if (bch->debug & DEBUG_HW_BCHANNEL)
- printk(KERN_DEBUG
- "HFCPCI bchannel protocol %x-->%x ch %x-->%x\n",
- bch->state, protocol, bch->nr, bc);
-
- fifo2 = bc;
- pcm_mode = (bc >> 24) & 0xff;
- if (pcm_mode) { /* PCM SLOT USE */
- if (!test_bit(HFC_CFG_PCM, &hc->cfg))
- printk(KERN_WARNING
- "%s: pcm channel id without HFC_CFG_PCM\n",
- __func__);
- rx_slot = (bc >> 8) & 0xff;
- tx_slot = (bc >> 16) & 0xff;
- bc = bc & 0xff;
- } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_P_NONE))
- printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n",
- __func__);
- if (hc->chanlimit > 1) {
- hc->hw.bswapped = 0; /* B1 and B2 normal mode */
- hc->hw.sctrl_e &= ~0x80;
- } else {
- if (bc & 2) {
- if (protocol != ISDN_P_NONE) {
- hc->hw.bswapped = 1; /* B1 and B2 exchanged */
- hc->hw.sctrl_e |= 0x80;
- } else {
- hc->hw.bswapped = 0; /* B1 and B2 normal mode */
- hc->hw.sctrl_e &= ~0x80;
- }
- fifo2 = 1;
- } else {
- hc->hw.bswapped = 0; /* B1 and B2 normal mode */
- hc->hw.sctrl_e &= ~0x80;
- }
- }
- switch (protocol) {
- case (-1): /* used for init */
- bch->state = -1;
- bch->nr = bc;
- fallthrough;
- case (ISDN_P_NONE):
- if (bch->state == ISDN_P_NONE)
- return 0;
- if (bc & 2) {
- hc->hw.sctrl &= ~SCTRL_B2_ENA;
- hc->hw.sctrl_r &= ~SCTRL_B2_ENA;
- } else {
- hc->hw.sctrl &= ~SCTRL_B1_ENA;
- hc->hw.sctrl_r &= ~SCTRL_B1_ENA;
- }
- if (fifo2 & 2) {
- hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2;
- hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS |
- HFCPCI_INTS_B2REC);
- } else {
- hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1;
- hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS |
- HFCPCI_INTS_B1REC);
- }
-#ifdef REVERSE_BITORDER
- if (bch->nr & 2)
- hc->hw.cirm &= 0x7f;
- else
- hc->hw.cirm &= 0xbf;
-#endif
- bch->state = ISDN_P_NONE;
- bch->nr = bc;
- test_and_clear_bit(FLG_HDLC, &bch->Flags);
- test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
- break;
- case (ISDN_P_B_RAW):
- bch->state = protocol;
- bch->nr = bc;
- hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0);
- hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0);
- if (bc & 2) {
- hc->hw.sctrl |= SCTRL_B2_ENA;
- hc->hw.sctrl_r |= SCTRL_B2_ENA;
-#ifdef REVERSE_BITORDER
- hc->hw.cirm |= 0x80;
-#endif
- } else {
- hc->hw.sctrl |= SCTRL_B1_ENA;
- hc->hw.sctrl_r |= SCTRL_B1_ENA;
-#ifdef REVERSE_BITORDER
- hc->hw.cirm |= 0x40;
-#endif
- }
- if (fifo2 & 2) {
- hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
- if (!tics)
- hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS |
- HFCPCI_INTS_B2REC);
- hc->hw.ctmt |= 2;
- hc->hw.conn &= ~0x18;
- } else {
- hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
- if (!tics)
- hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS |
- HFCPCI_INTS_B1REC);
- hc->hw.ctmt |= 1;
- hc->hw.conn &= ~0x03;
- }
- test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
- break;
- case (ISDN_P_B_HDLC):
- bch->state = protocol;
- bch->nr = bc;
- hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0);
- hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0);
- if (bc & 2) {
- hc->hw.sctrl |= SCTRL_B2_ENA;
- hc->hw.sctrl_r |= SCTRL_B2_ENA;
- } else {
- hc->hw.sctrl |= SCTRL_B1_ENA;
- hc->hw.sctrl_r |= SCTRL_B1_ENA;
- }
- if (fifo2 & 2) {
- hc->hw.last_bfifo_cnt[1] = 0;
- hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
- hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS |
- HFCPCI_INTS_B2REC);
- hc->hw.ctmt &= ~2;
- hc->hw.conn &= ~0x18;
- } else {
- hc->hw.last_bfifo_cnt[0] = 0;
- hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
- hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS |
- HFCPCI_INTS_B1REC);
- hc->hw.ctmt &= ~1;
- hc->hw.conn &= ~0x03;
- }
- test_and_set_bit(FLG_HDLC, &bch->Flags);
- break;
- default:
- printk(KERN_DEBUG "prot not known %x\n", protocol);
- return -ENOPROTOOPT;
- }
- if (test_bit(HFC_CFG_PCM, &hc->cfg)) {
- if ((protocol == ISDN_P_NONE) ||
- (protocol == -1)) { /* init case */
- rx_slot = 0;
- tx_slot = 0;
- } else {
- if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) {
- rx_slot |= 0xC0;
- tx_slot |= 0xC0;
- } else {
- rx_slot |= 0x80;
- tx_slot |= 0x80;
- }
- }
- if (bc & 2) {
- hc->hw.conn &= 0xc7;
- hc->hw.conn |= 0x08;
- printk(KERN_DEBUG "%s: Write_hfc: B2_SSL 0x%x\n",
- __func__, tx_slot);
- printk(KERN_DEBUG "%s: Write_hfc: B2_RSL 0x%x\n",
- __func__, rx_slot);
- Write_hfc(hc, HFCPCI_B2_SSL, tx_slot);
- Write_hfc(hc, HFCPCI_B2_RSL, rx_slot);
- } else {
- hc->hw.conn &= 0xf8;
- hc->hw.conn |= 0x01;
- printk(KERN_DEBUG "%s: Write_hfc: B1_SSL 0x%x\n",
- __func__, tx_slot);
- printk(KERN_DEBUG "%s: Write_hfc: B1_RSL 0x%x\n",
- __func__, rx_slot);
- Write_hfc(hc, HFCPCI_B1_SSL, tx_slot);
- Write_hfc(hc, HFCPCI_B1_RSL, rx_slot);
- }
- }
- Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e);
- Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
- Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
- Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl);
- Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
- Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
- Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
-#ifdef REVERSE_BITORDER
- Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
-#endif
- return 0;
-}
-
-static int
-set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan)
-{
- struct hfc_pci *hc = bch->hw;
-
- if (bch->debug & DEBUG_HW_BCHANNEL)
- printk(KERN_DEBUG
- "HFCPCI bchannel test rx protocol %x-->%x ch %x-->%x\n",
- bch->state, protocol, bch->nr, chan);
- if (bch->nr != chan) {
- printk(KERN_DEBUG
- "HFCPCI rxtest wrong channel parameter %x/%x\n",
- bch->nr, chan);
- return -EINVAL;
- }
- switch (protocol) {
- case (ISDN_P_B_RAW):
- bch->state = protocol;
- hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0);
- if (chan & 2) {
- hc->hw.sctrl_r |= SCTRL_B2_ENA;
- hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
- if (!tics)
- hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
- hc->hw.ctmt |= 2;
- hc->hw.conn &= ~0x18;
-#ifdef REVERSE_BITORDER
- hc->hw.cirm |= 0x80;
-#endif
- } else {
- hc->hw.sctrl_r |= SCTRL_B1_ENA;
- hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX;
- if (!tics)
- hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
- hc->hw.ctmt |= 1;
- hc->hw.conn &= ~0x03;
-#ifdef REVERSE_BITORDER
- hc->hw.cirm |= 0x40;
-#endif
- }
- break;
- case (ISDN_P_B_HDLC):
- bch->state = protocol;
- hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0);
- if (chan & 2) {
- hc->hw.sctrl_r |= SCTRL_B2_ENA;
- hc->hw.last_bfifo_cnt[1] = 0;
- hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
- hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
- hc->hw.ctmt &= ~2;
- hc->hw.conn &= ~0x18;
- } else {
- hc->hw.sctrl_r |= SCTRL_B1_ENA;
- hc->hw.last_bfifo_cnt[0] = 0;
- hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX;
- hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
- hc->hw.ctmt &= ~1;
- hc->hw.conn &= ~0x03;
- }
- break;
- default:
- printk(KERN_DEBUG "prot not known %x\n", protocol);
- return -ENOPROTOOPT;
- }
- Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
- Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
- Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
- Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
- Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
-#ifdef REVERSE_BITORDER
- Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
-#endif
- return 0;
-}
-
-static void
-deactivate_bchannel(struct bchannel *bch)
-{
- struct hfc_pci *hc = bch->hw;
- u_long flags;
-
- spin_lock_irqsave(&hc->lock, flags);
- mISDN_clear_bchannel(bch);
- mode_hfcpci(bch, bch->nr, ISDN_P_NONE);
- spin_unlock_irqrestore(&hc->lock, flags);
-}
-
-/*
- * Layer 1 B-channel hardware access
- */
-static int
-channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
-{
- return mISDN_ctrl_bchannel(bch, cq);
-}
-static int
-hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct hfc_pci *hc = bch->hw;
- int ret = -EINVAL;
- u_long flags;
-
- if (bch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg);
- switch (cmd) {
- case HW_TESTRX_RAW:
- spin_lock_irqsave(&hc->lock, flags);
- ret = set_hfcpci_rxtest(bch, ISDN_P_B_RAW, (int)(long)arg);
- spin_unlock_irqrestore(&hc->lock, flags);
- break;
- case HW_TESTRX_HDLC:
- spin_lock_irqsave(&hc->lock, flags);
- ret = set_hfcpci_rxtest(bch, ISDN_P_B_HDLC, (int)(long)arg);
- spin_unlock_irqrestore(&hc->lock, flags);
- break;
- case HW_TESTRX_OFF:
- spin_lock_irqsave(&hc->lock, flags);
- mode_hfcpci(bch, bch->nr, ISDN_P_NONE);
- spin_unlock_irqrestore(&hc->lock, flags);
- ret = 0;
- break;
- case CLOSE_CHANNEL:
- test_and_clear_bit(FLG_OPEN, &bch->Flags);
- deactivate_bchannel(bch);
- ch->protocol = ISDN_P_NONE;
- ch->peer = NULL;
- module_put(THIS_MODULE);
- ret = 0;
- break;
- case CONTROL_CHANNEL:
- ret = channel_bctrl(bch, arg);
- break;
- default:
- printk(KERN_WARNING "%s: unknown prim(%x)\n",
- __func__, cmd);
- }
- return ret;
-}
-
-/*
- * Layer2 -> Layer 1 Dchannel data
- */
-static int
-hfcpci_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct hfc_pci *hc = dch->hw;
- int ret = -EINVAL;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- unsigned int id;
- u_long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- spin_lock_irqsave(&hc->lock, flags);
- ret = dchannel_senddata(dch, skb);
- if (ret > 0) { /* direct TX */
- id = hh->id; /* skb can be freed */
- hfcpci_fill_dfifo(dch->hw);
- ret = 0;
- spin_unlock_irqrestore(&hc->lock, flags);
- queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
- } else
- spin_unlock_irqrestore(&hc->lock, flags);
- return ret;
- case PH_ACTIVATE_REQ:
- spin_lock_irqsave(&hc->lock, flags);
- if (hc->hw.protocol == ISDN_P_NT_S0) {
- ret = 0;
- if (test_bit(HFC_CFG_MASTER, &hc->cfg))
- hc->hw.mst_m |= HFCPCI_MASTER;
- Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
- if (test_bit(FLG_ACTIVE, &dch->Flags)) {
- spin_unlock_irqrestore(&hc->lock, flags);
- _queue_data(&dch->dev.D, PH_ACTIVATE_IND,
- MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
- break;
- }
- test_and_set_bit(FLG_L2_ACTIVATED, &dch->Flags);
- Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE |
- HFCPCI_DO_ACTION | 1);
- } else
- ret = l1_event(dch->l1, hh->prim);
- spin_unlock_irqrestore(&hc->lock, flags);
- break;
- case PH_DEACTIVATE_REQ:
- test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
- spin_lock_irqsave(&hc->lock, flags);
- if (hc->hw.protocol == ISDN_P_NT_S0) {
- struct sk_buff_head free_queue;
-
- __skb_queue_head_init(&free_queue);
- /* prepare deactivation */
- Write_hfc(hc, HFCPCI_STATES, 0x40);
- skb_queue_splice_init(&dch->squeue, &free_queue);
- if (dch->tx_skb) {
- __skb_queue_tail(&free_queue, dch->tx_skb);
- dch->tx_skb = NULL;
- }
- dch->tx_idx = 0;
- if (dch->rx_skb) {
- __skb_queue_tail(&free_queue, dch->rx_skb);
- dch->rx_skb = NULL;
- }
- test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
- if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
- timer_delete(&dch->timer);
-#ifdef FIXME
- if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
- dchannel_sched_event(&hc->dch, D_CLEARBUSY);
-#endif
- hc->hw.mst_m &= ~HFCPCI_MASTER;
- Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
- ret = 0;
- spin_unlock_irqrestore(&hc->lock, flags);
- __skb_queue_purge(&free_queue);
- } else {
- ret = l1_event(dch->l1, hh->prim);
- spin_unlock_irqrestore(&hc->lock, flags);
- }
- break;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-/*
- * Layer2 -> Layer 1 Bchannel data
- */
-static int
-hfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct hfc_pci *hc = bch->hw;
- int ret = -EINVAL;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- unsigned long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- spin_lock_irqsave(&hc->lock, flags);
- ret = bchannel_senddata(bch, skb);
- if (ret > 0) { /* direct TX */
- hfcpci_fill_fifo(bch);
- ret = 0;
- }
- spin_unlock_irqrestore(&hc->lock, flags);
- return ret;
- case PH_ACTIVATE_REQ:
- spin_lock_irqsave(&hc->lock, flags);
- if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
- ret = mode_hfcpci(bch, bch->nr, ch->protocol);
- else
- ret = 0;
- spin_unlock_irqrestore(&hc->lock, flags);
- if (!ret)
- _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- break;
- case PH_DEACTIVATE_REQ:
- deactivate_bchannel(bch);
- _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- ret = 0;
- break;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-/*
- * called for card init message
- */
-
-static void
-inithfcpci(struct hfc_pci *hc)
-{
- printk(KERN_DEBUG "inithfcpci: entered\n");
- timer_setup(&hc->dch.timer, hfcpci_dbusy_timer, 0);
- hc->chanlimit = 2;
- mode_hfcpci(&hc->bch[0], 1, -1);
- mode_hfcpci(&hc->bch[1], 2, -1);
-}
-
-
-static int
-init_card(struct hfc_pci *hc)
-{
- int cnt = 3;
- u_long flags;
-
- printk(KERN_DEBUG "init_card: entered\n");
-
-
- spin_lock_irqsave(&hc->lock, flags);
- disable_hwirq(hc);
- spin_unlock_irqrestore(&hc->lock, flags);
- if (request_irq(hc->irq, hfcpci_int, IRQF_SHARED, "HFC PCI", hc)) {
- printk(KERN_WARNING
- "mISDN: couldn't get interrupt %d\n", hc->irq);
- return -EIO;
- }
- spin_lock_irqsave(&hc->lock, flags);
- reset_hfcpci(hc);
- while (cnt) {
- inithfcpci(hc);
- /*
- * Finally enable IRQ output
- * this is only allowed, if an IRQ routine is already
- * established for this HFC, so don't do that earlier
- */
- enable_hwirq(hc);
- spin_unlock_irqrestore(&hc->lock, flags);
- /* Timeout 80ms */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((80 * HZ) / 1000);
- printk(KERN_INFO "HFC PCI: IRQ %d count %d\n",
- hc->irq, hc->irqcnt);
- /* now switch timer interrupt off */
- spin_lock_irqsave(&hc->lock, flags);
- hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
- Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
- /* reinit mode reg */
- Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
- if (!hc->irqcnt) {
- printk(KERN_WARNING
- "HFC PCI: IRQ(%d) getting no interrupts "
- "during init %d\n", hc->irq, 4 - cnt);
- if (cnt == 1)
- break;
- else {
- reset_hfcpci(hc);
- cnt--;
- }
- } else {
- spin_unlock_irqrestore(&hc->lock, flags);
- hc->initdone = 1;
- return 0;
- }
- }
- disable_hwirq(hc);
- spin_unlock_irqrestore(&hc->lock, flags);
- free_irq(hc->irq, hc);
- return -EIO;
-}
-
-static int
-channel_ctrl(struct hfc_pci *hc, struct mISDN_ctrl_req *cq)
-{
- int ret = 0;
- u_char slot;
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT |
- MISDN_CTRL_DISCONNECT | MISDN_CTRL_L1_TIMER3;
- break;
- case MISDN_CTRL_LOOP:
- /* channel 0 disabled loop */
- if (cq->channel < 0 || cq->channel > 2) {
- ret = -EINVAL;
- break;
- }
- if (cq->channel & 1) {
- if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
- slot = 0xC0;
- else
- slot = 0x80;
- printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n",
- __func__, slot);
- Write_hfc(hc, HFCPCI_B1_SSL, slot);
- Write_hfc(hc, HFCPCI_B1_RSL, slot);
- hc->hw.conn = (hc->hw.conn & ~7) | 6;
- Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
- }
- if (cq->channel & 2) {
- if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
- slot = 0xC1;
- else
- slot = 0x81;
- printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n",
- __func__, slot);
- Write_hfc(hc, HFCPCI_B2_SSL, slot);
- Write_hfc(hc, HFCPCI_B2_RSL, slot);
- hc->hw.conn = (hc->hw.conn & ~0x38) | 0x30;
- Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
- }
- if (cq->channel & 3)
- hc->hw.trm |= 0x80; /* enable IOM-loop */
- else {
- hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09;
- Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
- hc->hw.trm &= 0x7f; /* disable IOM-loop */
- }
- Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
- break;
- case MISDN_CTRL_CONNECT:
- if (cq->channel == cq->p1) {
- ret = -EINVAL;
- break;
- }
- if (cq->channel < 1 || cq->channel > 2 ||
- cq->p1 < 1 || cq->p1 > 2) {
- ret = -EINVAL;
- break;
- }
- if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
- slot = 0xC0;
- else
- slot = 0x80;
- printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n",
- __func__, slot);
- Write_hfc(hc, HFCPCI_B1_SSL, slot);
- Write_hfc(hc, HFCPCI_B2_RSL, slot);
- if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
- slot = 0xC1;
- else
- slot = 0x81;
- printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n",
- __func__, slot);
- Write_hfc(hc, HFCPCI_B2_SSL, slot);
- Write_hfc(hc, HFCPCI_B1_RSL, slot);
- hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x36;
- Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
- hc->hw.trm |= 0x80;
- Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
- break;
- case MISDN_CTRL_DISCONNECT:
- hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09;
- Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
- hc->hw.trm &= 0x7f; /* disable IOM-loop */
- break;
- case MISDN_CTRL_L1_TIMER3:
- ret = l1_event(hc->dch.l1, HW_TIMER3_VALUE | (cq->p1 & 0xff));
- break;
- default:
- printk(KERN_WARNING "%s: unknown Op %x\n",
- __func__, cq->op);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int
-open_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch,
- struct channel_req *rq)
-{
- int err = 0;
-
- if (debug & DEBUG_HW_OPEN)
- printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__,
- hc->dch.dev.id, __builtin_return_address(0));
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
- if (rq->adr.channel == 1) {
- /* TODO: E-Channel */
- return -EINVAL;
- }
- if (!hc->initdone) {
- if (rq->protocol == ISDN_P_TE_S0) {
- err = create_l1(&hc->dch, hfc_l1callback);
- if (err)
- return err;
- }
- hc->hw.protocol = rq->protocol;
- ch->protocol = rq->protocol;
- err = init_card(hc);
- if (err)
- return err;
- } else {
- if (rq->protocol != ch->protocol) {
- if (hc->hw.protocol == ISDN_P_TE_S0)
- l1_event(hc->dch.l1, CLOSE_CHANNEL);
- if (rq->protocol == ISDN_P_TE_S0) {
- err = create_l1(&hc->dch, hfc_l1callback);
- if (err)
- return err;
- }
- hc->hw.protocol = rq->protocol;
- ch->protocol = rq->protocol;
- hfcpci_setmode(hc);
- }
- }
-
- if (((ch->protocol == ISDN_P_NT_S0) && (hc->dch.state == 3)) ||
- ((ch->protocol == ISDN_P_TE_S0) && (hc->dch.state == 7))) {
- _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
- 0, NULL, GFP_KERNEL);
- }
- rq->ch = ch;
- if (!try_module_get(THIS_MODULE))
- printk(KERN_WARNING "%s:cannot get module\n", __func__);
- return 0;
-}
-
-static int
-open_bchannel(struct hfc_pci *hc, struct channel_req *rq)
-{
- struct bchannel *bch;
-
- if (rq->adr.channel == 0 || rq->adr.channel > 2)
- return -EINVAL;
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
- bch = &hc->bch[rq->adr.channel - 1];
- if (test_and_set_bit(FLG_OPEN, &bch->Flags))
- return -EBUSY; /* b-channel can be only open once */
- bch->ch.protocol = rq->protocol;
- rq->ch = &bch->ch; /* TODO: E-channel */
- if (!try_module_get(THIS_MODULE))
- printk(KERN_WARNING "%s:cannot get module\n", __func__);
- return 0;
-}
-
-/*
- * device control function
- */
-static int
-hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct hfc_pci *hc = dch->hw;
- struct channel_req *rq;
- int err = 0;
-
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: cmd:%x %p\n",
- __func__, cmd, arg);
- switch (cmd) {
- case OPEN_CHANNEL:
- rq = arg;
- if ((rq->protocol == ISDN_P_TE_S0) ||
- (rq->protocol == ISDN_P_NT_S0))
- err = open_dchannel(hc, ch, rq);
- else
- err = open_bchannel(hc, rq);
- break;
- case CLOSE_CHANNEL:
- if (debug & DEBUG_HW_OPEN)
- printk(KERN_DEBUG "%s: dev(%d) close from %p\n",
- __func__, hc->dch.dev.id,
- __builtin_return_address(0));
- module_put(THIS_MODULE);
- break;
- case CONTROL_CHANNEL:
- err = channel_ctrl(hc, arg);
- break;
- default:
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: unknown command %x\n",
- __func__, cmd);
- return -EINVAL;
- }
- return err;
-}
-
-static int
-setup_hw(struct hfc_pci *hc)
-{
- void *buffer;
-
- printk(KERN_INFO "mISDN: HFC-PCI driver %s\n", hfcpci_revision);
- hc->hw.cirm = 0;
- hc->dch.state = 0;
- pci_set_master(hc->pdev);
- if (!hc->irq) {
- printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
- return -EINVAL;
- }
- hc->hw.pci_io =
- (char __iomem *)(unsigned long)hc->pdev->resource[1].start;
-
- if (!hc->hw.pci_io) {
- printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
- return -ENOMEM;
- }
- /* Allocate memory for FIFOS */
- /* the memory needs to be on a 32k boundary within the first 4G */
- if (dma_set_mask(&hc->pdev->dev, 0xFFFF8000)) {
- printk(KERN_WARNING
- "HFC-PCI: No usable DMA configuration!\n");
- return -EIO;
- }
- buffer = dma_alloc_coherent(&hc->pdev->dev, 0x8000, &hc->hw.dmahandle,
- GFP_KERNEL);
- /* We silently assume the address is okay if nonzero */
- if (!buffer) {
- printk(KERN_WARNING
- "HFC-PCI: Error allocating memory for FIFO!\n");
- return -ENOMEM;
- }
- hc->hw.fifos = buffer;
- pci_write_config_dword(hc->pdev, 0x80, hc->hw.dmahandle);
- hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256);
- if (unlikely(!hc->hw.pci_io)) {
- printk(KERN_WARNING
- "HFC-PCI: Error in ioremap for PCI!\n");
- dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos,
- hc->hw.dmahandle);
- return -ENOMEM;
- }
-
- printk(KERN_INFO
- "HFC-PCI: defined at mem %#lx fifo %p(%pad) IRQ %d HZ %d\n",
- (u_long) hc->hw.pci_io, hc->hw.fifos,
- &hc->hw.dmahandle, hc->irq, HZ);
-
- /* enable memory mapped ports, disable busmaster */
- pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO);
- hc->hw.int_m2 = 0;
- disable_hwirq(hc);
- hc->hw.int_m1 = 0;
- Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
- /* At this point the needed PCI config is done */
- /* fifos are still not enabled */
- timer_setup(&hc->hw.timer, hfcpci_Timer, 0);
- /* default PCM master */
- test_and_set_bit(HFC_CFG_MASTER, &hc->cfg);
- return 0;
-}
-
-static void
-release_card(struct hfc_pci *hc) {
- u_long flags;
-
- spin_lock_irqsave(&hc->lock, flags);
- hc->hw.int_m2 = 0; /* interrupt output off ! */
- disable_hwirq(hc);
- mode_hfcpci(&hc->bch[0], 1, ISDN_P_NONE);
- mode_hfcpci(&hc->bch[1], 2, ISDN_P_NONE);
- if (hc->dch.timer.function != NULL) {
- timer_delete(&hc->dch.timer);
- hc->dch.timer.function = NULL;
- }
- spin_unlock_irqrestore(&hc->lock, flags);
- if (hc->hw.protocol == ISDN_P_TE_S0)
- l1_event(hc->dch.l1, CLOSE_CHANNEL);
- if (hc->initdone)
- free_irq(hc->irq, hc);
- release_io_hfcpci(hc); /* must release after free_irq! */
- mISDN_unregister_device(&hc->dch.dev);
- mISDN_freebchannel(&hc->bch[1]);
- mISDN_freebchannel(&hc->bch[0]);
- mISDN_freedchannel(&hc->dch);
- pci_set_drvdata(hc->pdev, NULL);
- kfree(hc);
-}
-
-static int
-setup_card(struct hfc_pci *card)
-{
- int err = -EINVAL;
- u_int i;
- char name[MISDN_MAX_IDLEN];
-
- card->dch.debug = debug;
- spin_lock_init(&card->lock);
- mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state);
- card->dch.hw = card;
- card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0);
- card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
- card->dch.dev.D.send = hfcpci_l2l1D;
- card->dch.dev.D.ctrl = hfc_dctrl;
- card->dch.dev.nrbchan = 2;
- for (i = 0; i < 2; i++) {
- card->bch[i].nr = i + 1;
- set_channelmap(i + 1, card->dch.dev.channelmap);
- card->bch[i].debug = debug;
- mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, poll >> 1);
- card->bch[i].hw = card;
- card->bch[i].ch.send = hfcpci_l2l1B;
- card->bch[i].ch.ctrl = hfc_bctrl;
- card->bch[i].ch.nr = i + 1;
- list_add(&card->bch[i].ch.list, &card->dch.dev.bchannels);
- }
- err = setup_hw(card);
- if (err)
- goto error;
- snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1);
- err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name);
- if (err)
- goto error;
- HFC_cnt++;
- printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt);
- return 0;
-error:
- mISDN_freebchannel(&card->bch[1]);
- mISDN_freebchannel(&card->bch[0]);
- mISDN_freedchannel(&card->dch);
- kfree(card);
- return err;
-}
-
-/* private data in the PCI devices list */
-struct _hfc_map {
- u_int subtype;
- u_int flag;
- char *name;
-};
-
-static const struct _hfc_map hfc_map[] =
-{
- {HFC_CCD_2BD0, 0, "CCD/Billion/Asuscom 2BD0"},
- {HFC_CCD_B000, 0, "Billion B000"},
- {HFC_CCD_B006, 0, "Billion B006"},
- {HFC_CCD_B007, 0, "Billion B007"},
- {HFC_CCD_B008, 0, "Billion B008"},
- {HFC_CCD_B009, 0, "Billion B009"},
- {HFC_CCD_B00A, 0, "Billion B00A"},
- {HFC_CCD_B00B, 0, "Billion B00B"},
- {HFC_CCD_B00C, 0, "Billion B00C"},
- {HFC_CCD_B100, 0, "Seyeon B100"},
- {HFC_CCD_B700, 0, "Primux II S0 B700"},
- {HFC_CCD_B701, 0, "Primux II S0 NT B701"},
- {HFC_ABOCOM_2BD1, 0, "Abocom/Magitek 2BD1"},
- {HFC_ASUS_0675, 0, "Asuscom/Askey 675"},
- {HFC_BERKOM_TCONCEPT, 0, "German telekom T-Concept"},
- {HFC_BERKOM_A1T, 0, "German telekom A1T"},
- {HFC_ANIGMA_MC145575, 0, "Motorola MC145575"},
- {HFC_ZOLTRIX_2BD0, 0, "Zoltrix 2BD0"},
- {HFC_DIGI_DF_M_IOM2_E, 0,
- "Digi International DataFire Micro V IOM2 (Europe)"},
- {HFC_DIGI_DF_M_E, 0,
- "Digi International DataFire Micro V (Europe)"},
- {HFC_DIGI_DF_M_IOM2_A, 0,
- "Digi International DataFire Micro V IOM2 (North America)"},
- {HFC_DIGI_DF_M_A, 0,
- "Digi International DataFire Micro V (North America)"},
- {HFC_SITECOM_DC105V2, 0, "Sitecom Connectivity DC-105 ISDN TA"},
- {},
-};
-
-static const struct pci_device_id hfc_ids[] =
-{
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0),
- (unsigned long) &hfc_map[0] },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000),
- (unsigned long) &hfc_map[1] },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006),
- (unsigned long) &hfc_map[2] },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007),
- (unsigned long) &hfc_map[3] },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008),
- (unsigned long) &hfc_map[4] },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009),
- (unsigned long) &hfc_map[5] },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A),
- (unsigned long) &hfc_map[6] },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B),
- (unsigned long) &hfc_map[7] },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C),
- (unsigned long) &hfc_map[8] },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100),
- (unsigned long) &hfc_map[9] },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700),
- (unsigned long) &hfc_map[10] },
- { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701),
- (unsigned long) &hfc_map[11] },
- { PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1),
- (unsigned long) &hfc_map[12] },
- { PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675),
- (unsigned long) &hfc_map[13] },
- { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT),
- (unsigned long) &hfc_map[14] },
- { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T),
- (unsigned long) &hfc_map[15] },
- { PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575),
- (unsigned long) &hfc_map[16] },
- { PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0),
- (unsigned long) &hfc_map[17] },
- { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E),
- (unsigned long) &hfc_map[18] },
- { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E),
- (unsigned long) &hfc_map[19] },
- { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A),
- (unsigned long) &hfc_map[20] },
- { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A),
- (unsigned long) &hfc_map[21] },
- { PCI_VDEVICE(SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2),
- (unsigned long) &hfc_map[22] },
- {},
-};
-
-static int
-hfc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int err = -ENOMEM;
- struct hfc_pci *card;
- struct _hfc_map *m = (struct _hfc_map *)ent->driver_data;
-
- card = kzalloc_obj(struct hfc_pci);
- if (!card) {
- printk(KERN_ERR "No kmem for HFC card\n");
- return err;
- }
- card->pdev = pdev;
- card->subtype = m->subtype;
- err = pci_enable_device(pdev);
- if (err) {
- kfree(card);
- return err;
- }
-
- printk(KERN_INFO "mISDN_hfcpci: found adapter %s at %s\n",
- m->name, pci_name(pdev));
-
- card->irq = pdev->irq;
- pci_set_drvdata(pdev, card);
- err = setup_card(card);
- if (err)
- pci_set_drvdata(pdev, NULL);
- return err;
-}
-
-static void
-hfc_remove_pci(struct pci_dev *pdev)
-{
- struct hfc_pci *card = pci_get_drvdata(pdev);
-
- if (card)
- release_card(card);
- else
- if (debug)
- printk(KERN_DEBUG "%s: drvdata already removed\n",
- __func__);
-}
-
-
-static struct pci_driver hfc_driver = {
- .name = "hfcpci",
- .probe = hfc_probe,
- .remove = hfc_remove_pci,
- .id_table = hfc_ids,
-};
-
-static int
-_hfcpci_softirq(struct device *dev, void *unused)
-{
- struct hfc_pci *hc = dev_get_drvdata(dev);
- struct bchannel *bch;
- if (hc == NULL)
- return 0;
-
- if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) {
- spin_lock_irq(&hc->lock);
- bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
- if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */
- main_rec_hfcpci(bch);
- tx_birq(bch);
- }
- bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2);
- if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */
- main_rec_hfcpci(bch);
- tx_birq(bch);
- }
- spin_unlock_irq(&hc->lock);
- }
- return 0;
-}
-
-static void
-hfcpci_softirq(struct timer_list *unused)
-{
- WARN_ON_ONCE(driver_for_each_device(&hfc_driver.driver, NULL, NULL,
- _hfcpci_softirq) != 0);
-
- /* if next event would be in the past ... */
- if ((s32)(hfc_jiffies + tics - jiffies) <= 0)
- hfc_jiffies = jiffies + 1;
- else
- hfc_jiffies += tics;
- mod_timer(&hfc_tl, hfc_jiffies);
-}
-
-static int __init
-HFC_init(void)
-{
- int err;
-
- if (!poll)
- poll = HFCPCI_BTRANS_THRESHOLD;
-
- if (poll != HFCPCI_BTRANS_THRESHOLD) {
- tics = (poll * HZ) / 8000;
- if (tics < 1)
- tics = 1;
- poll = (tics * 8000) / HZ;
- if (poll > 256 || poll < 8) {
- printk(KERN_ERR "%s: Wrong poll value %d not in range "
- "of 8..256.\n", __func__, poll);
- err = -EINVAL;
- return err;
- }
- }
- if (poll != HFCPCI_BTRANS_THRESHOLD) {
- printk(KERN_INFO "%s: Using alternative poll value of %d\n",
- __func__, poll);
- hfc_jiffies = jiffies + tics;
- mod_timer(&hfc_tl, hfc_jiffies);
- } else
- tics = 0; /* indicate the use of controller's timer */
-
- err = pci_register_driver(&hfc_driver);
- if (err) {
- if (timer_pending(&hfc_tl))
- timer_delete(&hfc_tl);
- }
-
- return err;
-}
-
-static void __exit
-HFC_cleanup(void)
-{
- timer_delete_sync(&hfc_tl);
-
- pci_unregister_driver(&hfc_driver);
-}
-
-module_init(HFC_init);
-module_exit(HFC_cleanup);
-
-MODULE_DEVICE_TABLE(pci, hfc_ids);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* hfcsusb.c
- * mISDN driver for Colognechip HFC-S USB chip
- *
- * Copyright 2001 by Peter Sprenger (sprenger@moving-bytes.de)
- * Copyright 2008 by Martin Bachem (info@bachem-it.com)
- *
- * module params
- * debug=<n>, default=0, with n=0xHHHHGGGG
- * H - l1 driver flags described in hfcsusb.h
- * G - common mISDN debug flags described at mISDNhw.h
- *
- * poll=<n>, default 128
- * n : burst size of PH_DATA_IND at transparent rx data
- *
- * Revision: 0.3.3 (socket), 2008-11-05
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/usb.h>
-#include <linux/mISDNhw.h>
-#include <linux/slab.h>
-#include "hfcsusb.h"
-
-static unsigned int debug;
-static int poll = DEFAULT_TRANSP_BURST_SZ;
-
-static LIST_HEAD(HFClist);
-static DEFINE_RWLOCK(HFClock);
-
-
-MODULE_AUTHOR("Martin Bachem");
-MODULE_DESCRIPTION("mISDN driver for Colognechip HFC-S USB chip");
-MODULE_LICENSE("GPL");
-module_param(debug, uint, S_IRUGO | S_IWUSR);
-module_param(poll, int, 0);
-
-static int hfcsusb_cnt;
-
-/* some function prototypes */
-static void hfcsusb_ph_command(struct hfcsusb *hw, u_char command);
-static void release_hw(struct hfcsusb *hw);
-static void reset_hfcsusb(struct hfcsusb *hw);
-static void setPortMode(struct hfcsusb *hw);
-static void hfcsusb_start_endpoint(struct hfcsusb *hw, int channel);
-static void hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel);
-static int hfcsusb_setup_bch(struct bchannel *bch, int protocol);
-static void deactivate_bchannel(struct bchannel *bch);
-static int hfcsusb_ph_info(struct hfcsusb *hw);
-
-/* start next background transfer for control channel */
-static void
-ctrl_start_transfer(struct hfcsusb *hw)
-{
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
-
- if (hw->ctrl_cnt) {
- hw->ctrl_urb->pipe = hw->ctrl_out_pipe;
- hw->ctrl_urb->setup_packet = (u_char *)&hw->ctrl_write;
- hw->ctrl_urb->transfer_buffer = NULL;
- hw->ctrl_urb->transfer_buffer_length = 0;
- hw->ctrl_write.wIndex =
- cpu_to_le16(hw->ctrl_buff[hw->ctrl_out_idx].hfcs_reg);
- hw->ctrl_write.wValue =
- cpu_to_le16(hw->ctrl_buff[hw->ctrl_out_idx].reg_val);
-
- usb_submit_urb(hw->ctrl_urb, GFP_ATOMIC);
- }
-}
-
-/*
- * queue a control transfer request to write HFC-S USB
- * chip register using CTRL resuest queue
- */
-static int write_reg(struct hfcsusb *hw, __u8 reg, __u8 val)
-{
- struct ctrl_buf *buf;
-
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s reg(0x%02x) val(0x%02x)\n",
- hw->name, __func__, reg, val);
-
- spin_lock(&hw->ctrl_lock);
- if (hw->ctrl_cnt >= HFC_CTRL_BUFSIZE) {
- spin_unlock(&hw->ctrl_lock);
- return 1;
- }
- buf = &hw->ctrl_buff[hw->ctrl_in_idx];
- buf->hfcs_reg = reg;
- buf->reg_val = val;
- if (++hw->ctrl_in_idx >= HFC_CTRL_BUFSIZE)
- hw->ctrl_in_idx = 0;
- if (++hw->ctrl_cnt == 1)
- ctrl_start_transfer(hw);
- spin_unlock(&hw->ctrl_lock);
-
- return 0;
-}
-
-/* control completion routine handling background control cmds */
-static void
-ctrl_complete(struct urb *urb)
-{
- struct hfcsusb *hw = (struct hfcsusb *) urb->context;
-
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
-
- urb->dev = hw->dev;
- if (hw->ctrl_cnt) {
- hw->ctrl_cnt--; /* decrement actual count */
- if (++hw->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
- hw->ctrl_out_idx = 0; /* pointer wrap */
-
- ctrl_start_transfer(hw); /* start next transfer */
- }
-}
-
-/* handle LED bits */
-static void
-set_led_bit(struct hfcsusb *hw, signed short led_bits, int set_on)
-{
- if (set_on) {
- if (led_bits < 0)
- hw->led_state &= ~abs(led_bits);
- else
- hw->led_state |= led_bits;
- } else {
- if (led_bits < 0)
- hw->led_state |= abs(led_bits);
- else
- hw->led_state &= ~led_bits;
- }
-}
-
-/* handle LED requests */
-static void
-handle_led(struct hfcsusb *hw, int event)
-{
- struct hfcsusb_vdata *driver_info = (struct hfcsusb_vdata *)
- hfcsusb_idtab[hw->vend_idx].driver_info;
- __u8 tmpled;
-
- if (driver_info->led_scheme == LED_OFF)
- return;
- tmpled = hw->led_state;
-
- switch (event) {
- case LED_POWER_ON:
- set_led_bit(hw, driver_info->led_bits[0], 1);
- set_led_bit(hw, driver_info->led_bits[1], 0);
- set_led_bit(hw, driver_info->led_bits[2], 0);
- set_led_bit(hw, driver_info->led_bits[3], 0);
- break;
- case LED_POWER_OFF:
- set_led_bit(hw, driver_info->led_bits[0], 0);
- set_led_bit(hw, driver_info->led_bits[1], 0);
- set_led_bit(hw, driver_info->led_bits[2], 0);
- set_led_bit(hw, driver_info->led_bits[3], 0);
- break;
- case LED_S0_ON:
- set_led_bit(hw, driver_info->led_bits[1], 1);
- break;
- case LED_S0_OFF:
- set_led_bit(hw, driver_info->led_bits[1], 0);
- break;
- case LED_B1_ON:
- set_led_bit(hw, driver_info->led_bits[2], 1);
- break;
- case LED_B1_OFF:
- set_led_bit(hw, driver_info->led_bits[2], 0);
- break;
- case LED_B2_ON:
- set_led_bit(hw, driver_info->led_bits[3], 1);
- break;
- case LED_B2_OFF:
- set_led_bit(hw, driver_info->led_bits[3], 0);
- break;
- }
-
- if (hw->led_state != tmpled) {
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s reg(0x%02x) val(x%02x)\n",
- hw->name, __func__,
- HFCUSB_P_DATA, hw->led_state);
-
- write_reg(hw, HFCUSB_P_DATA, hw->led_state);
- }
-}
-
-/*
- * Layer2 -> Layer 1 Bchannel data
- */
-static int
-hfcusb_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct hfcsusb *hw = bch->hw;
- int ret = -EINVAL;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- u_long flags;
-
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- spin_lock_irqsave(&hw->lock, flags);
- ret = bchannel_senddata(bch, skb);
- spin_unlock_irqrestore(&hw->lock, flags);
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s PH_DATA_REQ ret(%i)\n",
- hw->name, __func__, ret);
- if (ret > 0)
- ret = 0;
- return ret;
- case PH_ACTIVATE_REQ:
- if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
- hfcsusb_start_endpoint(hw, bch->nr - 1);
- ret = hfcsusb_setup_bch(bch, ch->protocol);
- } else
- ret = 0;
- if (!ret)
- _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
- 0, NULL, GFP_KERNEL);
- break;
- case PH_DEACTIVATE_REQ:
- deactivate_bchannel(bch);
- _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY,
- 0, NULL, GFP_KERNEL);
- ret = 0;
- break;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-/*
- * send full D/B channel status information
- * as MPH_INFORMATION_IND
- */
-static int
-hfcsusb_ph_info(struct hfcsusb *hw)
-{
- struct ph_info *phi;
- struct dchannel *dch = &hw->dch;
- int i;
-
- phi = kzalloc_flex(*phi, bch, dch->dev.nrbchan, GFP_ATOMIC);
- if (!phi)
- return -ENOMEM;
-
- phi->dch.ch.protocol = hw->protocol;
- phi->dch.ch.Flags = dch->Flags;
- phi->dch.state = dch->state;
- phi->dch.num_bch = dch->dev.nrbchan;
- for (i = 0; i < dch->dev.nrbchan; i++) {
- phi->bch[i].protocol = hw->bch[i].ch.protocol;
- phi->bch[i].Flags = hw->bch[i].Flags;
- }
- _queue_data(&dch->dev.D, MPH_INFORMATION_IND, MISDN_ID_ANY,
- struct_size(phi, bch, dch->dev.nrbchan), phi, GFP_ATOMIC);
- kfree(phi);
-
- return 0;
-}
-
-/*
- * Layer2 -> Layer 1 Dchannel data
- */
-static int
-hfcusb_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- struct hfcsusb *hw = dch->hw;
- int ret = -EINVAL;
- u_long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s: PH_DATA_REQ\n",
- hw->name, __func__);
-
- spin_lock_irqsave(&hw->lock, flags);
- ret = dchannel_senddata(dch, skb);
- spin_unlock_irqrestore(&hw->lock, flags);
- if (ret > 0) {
- ret = 0;
- queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL);
- }
- break;
-
- case PH_ACTIVATE_REQ:
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s: PH_ACTIVATE_REQ %s\n",
- hw->name, __func__,
- (hw->protocol == ISDN_P_NT_S0) ? "NT" : "TE");
-
- if (hw->protocol == ISDN_P_NT_S0) {
- ret = 0;
- if (test_bit(FLG_ACTIVE, &dch->Flags)) {
- _queue_data(&dch->dev.D,
- PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_ATOMIC);
- } else {
- hfcsusb_ph_command(hw,
- HFC_L1_ACTIVATE_NT);
- test_and_set_bit(FLG_L2_ACTIVATED,
- &dch->Flags);
- }
- } else {
- hfcsusb_ph_command(hw, HFC_L1_ACTIVATE_TE);
- ret = l1_event(dch->l1, hh->prim);
- }
- break;
-
- case PH_DEACTIVATE_REQ:
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s: PH_DEACTIVATE_REQ\n",
- hw->name, __func__);
- test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
-
- if (hw->protocol == ISDN_P_NT_S0) {
- struct sk_buff_head free_queue;
-
- __skb_queue_head_init(&free_queue);
- hfcsusb_ph_command(hw, HFC_L1_DEACTIVATE_NT);
- spin_lock_irqsave(&hw->lock, flags);
- skb_queue_splice_init(&dch->squeue, &free_queue);
- if (dch->tx_skb) {
- __skb_queue_tail(&free_queue, dch->tx_skb);
- dch->tx_skb = NULL;
- }
- dch->tx_idx = 0;
- if (dch->rx_skb) {
- __skb_queue_tail(&free_queue, dch->rx_skb);
- dch->rx_skb = NULL;
- }
- test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
- spin_unlock_irqrestore(&hw->lock, flags);
- __skb_queue_purge(&free_queue);
-#ifdef FIXME
- if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
- dchannel_sched_event(&hc->dch, D_CLEARBUSY);
-#endif
- ret = 0;
- } else
- ret = l1_event(dch->l1, hh->prim);
- break;
- case MPH_INFORMATION_REQ:
- ret = hfcsusb_ph_info(hw);
- break;
- }
-
- return ret;
-}
-
-/*
- * Layer 1 callback function
- */
-static int
-hfc_l1callback(struct dchannel *dch, u_int cmd)
-{
- struct hfcsusb *hw = dch->hw;
-
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s cmd 0x%x\n",
- hw->name, __func__, cmd);
-
- switch (cmd) {
- case INFO3_P8:
- case INFO3_P10:
- case HW_RESET_REQ:
- case HW_POWERUP_REQ:
- break;
-
- case HW_DEACT_REQ:
- skb_queue_purge(&dch->squeue);
- if (dch->tx_skb) {
- dev_kfree_skb(dch->tx_skb);
- dch->tx_skb = NULL;
- }
- dch->tx_idx = 0;
- if (dch->rx_skb) {
- dev_kfree_skb(dch->rx_skb);
- dch->rx_skb = NULL;
- }
- test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
- break;
- case PH_ACTIVATE_IND:
- test_and_set_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
- GFP_ATOMIC);
- break;
- case PH_DEACTIVATE_IND:
- test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
- GFP_ATOMIC);
- break;
- default:
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s: unknown cmd %x\n",
- hw->name, __func__, cmd);
- return -1;
- }
- return hfcsusb_ph_info(hw);
-}
-
-static int
-open_dchannel(struct hfcsusb *hw, struct mISDNchannel *ch,
- struct channel_req *rq)
-{
- int err = 0;
-
- if (debug & DEBUG_HW_OPEN)
- printk(KERN_DEBUG "%s: %s: dev(%d) open addr(%i) from %p\n",
- hw->name, __func__, hw->dch.dev.id, rq->adr.channel,
- __builtin_return_address(0));
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
-
- test_and_clear_bit(FLG_ACTIVE, &hw->dch.Flags);
- test_and_clear_bit(FLG_ACTIVE, &hw->ech.Flags);
- hfcsusb_start_endpoint(hw, HFC_CHAN_D);
-
- /* E-Channel logging */
- if (rq->adr.channel == 1) {
- if (hw->fifos[HFCUSB_PCM_RX].pipe) {
- hfcsusb_start_endpoint(hw, HFC_CHAN_E);
- set_bit(FLG_ACTIVE, &hw->ech.Flags);
- _queue_data(&hw->ech.dev.D, PH_ACTIVATE_IND,
- MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
- } else
- return -EINVAL;
- }
-
- if (!hw->initdone) {
- hw->protocol = rq->protocol;
- if (rq->protocol == ISDN_P_TE_S0) {
- err = create_l1(&hw->dch, hfc_l1callback);
- if (err)
- return err;
- }
- setPortMode(hw);
- ch->protocol = rq->protocol;
- hw->initdone = 1;
- } else {
- if (rq->protocol != ch->protocol)
- return -EPROTONOSUPPORT;
- }
-
- if (((ch->protocol == ISDN_P_NT_S0) && (hw->dch.state == 3)) ||
- ((ch->protocol == ISDN_P_TE_S0) && (hw->dch.state == 7)))
- _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
- 0, NULL, GFP_KERNEL);
- rq->ch = ch;
- if (!try_module_get(THIS_MODULE))
- printk(KERN_WARNING "%s: %s: cannot get module\n",
- hw->name, __func__);
- return 0;
-}
-
-static int
-open_bchannel(struct hfcsusb *hw, struct channel_req *rq)
-{
- struct bchannel *bch;
-
- if (rq->adr.channel == 0 || rq->adr.channel > 2)
- return -EINVAL;
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
-
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s B%i\n",
- hw->name, __func__, rq->adr.channel);
-
- bch = &hw->bch[rq->adr.channel - 1];
- if (test_and_set_bit(FLG_OPEN, &bch->Flags))
- return -EBUSY; /* b-channel can be only open once */
- bch->ch.protocol = rq->protocol;
- rq->ch = &bch->ch;
-
- if (!try_module_get(THIS_MODULE))
- printk(KERN_WARNING "%s: %s:cannot get module\n",
- hw->name, __func__);
- return 0;
-}
-
-static int
-channel_ctrl(struct hfcsusb *hw, struct mISDN_ctrl_req *cq)
-{
- int ret = 0;
-
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s op(0x%x) channel(0x%x)\n",
- hw->name, __func__, (cq->op), (cq->channel));
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT |
- MISDN_CTRL_DISCONNECT;
- break;
- default:
- printk(KERN_WARNING "%s: %s: unknown Op %x\n",
- hw->name, __func__, cq->op);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-/*
- * device control function
- */
-static int
-hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct hfcsusb *hw = dch->hw;
- struct channel_req *rq;
- int err = 0;
-
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s: cmd:%x %p\n",
- hw->name, __func__, cmd, arg);
- switch (cmd) {
- case OPEN_CHANNEL:
- rq = arg;
- if ((rq->protocol == ISDN_P_TE_S0) ||
- (rq->protocol == ISDN_P_NT_S0))
- err = open_dchannel(hw, ch, rq);
- else
- err = open_bchannel(hw, rq);
- if (!err)
- hw->open++;
- break;
- case CLOSE_CHANNEL:
- hw->open--;
- if (debug & DEBUG_HW_OPEN)
- printk(KERN_DEBUG
- "%s: %s: dev(%d) close from %p (open %d)\n",
- hw->name, __func__, hw->dch.dev.id,
- __builtin_return_address(0), hw->open);
- if (!hw->open) {
- hfcsusb_stop_endpoint(hw, HFC_CHAN_D);
- if (hw->fifos[HFCUSB_PCM_RX].pipe)
- hfcsusb_stop_endpoint(hw, HFC_CHAN_E);
- handle_led(hw, LED_POWER_ON);
- }
- module_put(THIS_MODULE);
- break;
- case CONTROL_CHANNEL:
- err = channel_ctrl(hw, arg);
- break;
- default:
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s: unknown command %x\n",
- hw->name, __func__, cmd);
- return -EINVAL;
- }
- return err;
-}
-
-/*
- * S0 TE state change event handler
- */
-static void
-ph_state_te(struct dchannel *dch)
-{
- struct hfcsusb *hw = dch->hw;
-
- if (debug & DEBUG_HW) {
- if (dch->state <= HFC_MAX_TE_LAYER1_STATE)
- printk(KERN_DEBUG "%s: %s: %s\n", hw->name, __func__,
- HFC_TE_LAYER1_STATES[dch->state]);
- else
- printk(KERN_DEBUG "%s: %s: TE F%d\n",
- hw->name, __func__, dch->state);
- }
-
- switch (dch->state) {
- case 0:
- l1_event(dch->l1, HW_RESET_IND);
- break;
- case 3:
- l1_event(dch->l1, HW_DEACT_IND);
- break;
- case 5:
- case 8:
- l1_event(dch->l1, ANYSIGNAL);
- break;
- case 6:
- l1_event(dch->l1, INFO2);
- break;
- case 7:
- l1_event(dch->l1, INFO4_P8);
- break;
- }
- if (dch->state == 7)
- handle_led(hw, LED_S0_ON);
- else
- handle_led(hw, LED_S0_OFF);
-}
-
-/*
- * S0 NT state change event handler
- */
-static void
-ph_state_nt(struct dchannel *dch)
-{
- struct hfcsusb *hw = dch->hw;
-
- if (debug & DEBUG_HW) {
- if (dch->state <= HFC_MAX_NT_LAYER1_STATE)
- printk(KERN_DEBUG "%s: %s: %s\n",
- hw->name, __func__,
- HFC_NT_LAYER1_STATES[dch->state]);
-
- else
- printk(KERN_INFO DRIVER_NAME "%s: %s: NT G%d\n",
- hw->name, __func__, dch->state);
- }
-
- switch (dch->state) {
- case (1):
- test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
- test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
- hw->nt_timer = 0;
- hw->timers &= ~NT_ACTIVATION_TIMER;
- handle_led(hw, LED_S0_OFF);
- break;
-
- case (2):
- if (hw->nt_timer < 0) {
- hw->nt_timer = 0;
- hw->timers &= ~NT_ACTIVATION_TIMER;
- hfcsusb_ph_command(dch->hw, HFC_L1_DEACTIVATE_NT);
- } else {
- hw->timers |= NT_ACTIVATION_TIMER;
- hw->nt_timer = NT_T1_COUNT;
- /* allow G2 -> G3 transition */
- write_reg(hw, HFCUSB_STATES, 2 | HFCUSB_NT_G2_G3);
- }
- break;
- case (3):
- hw->nt_timer = 0;
- hw->timers &= ~NT_ACTIVATION_TIMER;
- test_and_set_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, PH_ACTIVATE_IND,
- MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
- handle_led(hw, LED_S0_ON);
- break;
- case (4):
- hw->nt_timer = 0;
- hw->timers &= ~NT_ACTIVATION_TIMER;
- break;
- default:
- break;
- }
- hfcsusb_ph_info(hw);
-}
-
-static void
-ph_state(struct dchannel *dch)
-{
- struct hfcsusb *hw = dch->hw;
-
- if (hw->protocol == ISDN_P_NT_S0)
- ph_state_nt(dch);
- else if (hw->protocol == ISDN_P_TE_S0)
- ph_state_te(dch);
-}
-
-/*
- * disable/enable BChannel for desired protocol
- */
-static int
-hfcsusb_setup_bch(struct bchannel *bch, int protocol)
-{
- struct hfcsusb *hw = bch->hw;
- __u8 conhdlc, sctrl, sctrl_r;
-
- if (debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s: protocol %x-->%x B%d\n",
- hw->name, __func__, bch->state, protocol,
- bch->nr);
-
- /* setup val for CON_HDLC */
- conhdlc = 0;
- if (protocol > ISDN_P_NONE)
- conhdlc = 8; /* enable FIFO */
-
- switch (protocol) {
- case (-1): /* used for init */
- bch->state = -1;
- fallthrough;
- case (ISDN_P_NONE):
- if (bch->state == ISDN_P_NONE)
- return 0; /* already in idle state */
- bch->state = ISDN_P_NONE;
- clear_bit(FLG_HDLC, &bch->Flags);
- clear_bit(FLG_TRANSPARENT, &bch->Flags);
- break;
- case (ISDN_P_B_RAW):
- conhdlc |= 2;
- bch->state = protocol;
- set_bit(FLG_TRANSPARENT, &bch->Flags);
- break;
- case (ISDN_P_B_HDLC):
- bch->state = protocol;
- set_bit(FLG_HDLC, &bch->Flags);
- break;
- default:
- if (debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s: prot not known %x\n",
- hw->name, __func__, protocol);
- return -ENOPROTOOPT;
- }
-
- if (protocol >= ISDN_P_NONE) {
- write_reg(hw, HFCUSB_FIFO, (bch->nr == 1) ? 0 : 2);
- write_reg(hw, HFCUSB_CON_HDLC, conhdlc);
- write_reg(hw, HFCUSB_INC_RES_F, 2);
- write_reg(hw, HFCUSB_FIFO, (bch->nr == 1) ? 1 : 3);
- write_reg(hw, HFCUSB_CON_HDLC, conhdlc);
- write_reg(hw, HFCUSB_INC_RES_F, 2);
-
- sctrl = 0x40 + ((hw->protocol == ISDN_P_TE_S0) ? 0x00 : 0x04);
- sctrl_r = 0x0;
- if (test_bit(FLG_ACTIVE, &hw->bch[0].Flags)) {
- sctrl |= 1;
- sctrl_r |= 1;
- }
- if (test_bit(FLG_ACTIVE, &hw->bch[1].Flags)) {
- sctrl |= 2;
- sctrl_r |= 2;
- }
- write_reg(hw, HFCUSB_SCTRL, sctrl);
- write_reg(hw, HFCUSB_SCTRL_R, sctrl_r);
-
- if (protocol > ISDN_P_NONE)
- handle_led(hw, (bch->nr == 1) ? LED_B1_ON : LED_B2_ON);
- else
- handle_led(hw, (bch->nr == 1) ? LED_B1_OFF :
- LED_B2_OFF);
- }
- return hfcsusb_ph_info(hw);
-}
-
-static void
-hfcsusb_ph_command(struct hfcsusb *hw, u_char command)
-{
- if (debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s: %x\n",
- hw->name, __func__, command);
-
- switch (command) {
- case HFC_L1_ACTIVATE_TE:
- /* force sending sending INFO1 */
- write_reg(hw, HFCUSB_STATES, 0x14);
- /* start l1 activation */
- write_reg(hw, HFCUSB_STATES, 0x04);
- break;
-
- case HFC_L1_FORCE_DEACTIVATE_TE:
- write_reg(hw, HFCUSB_STATES, 0x10);
- write_reg(hw, HFCUSB_STATES, 0x03);
- break;
-
- case HFC_L1_ACTIVATE_NT:
- if (hw->dch.state == 3)
- _queue_data(&hw->dch.dev.D, PH_ACTIVATE_IND,
- MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
- else
- write_reg(hw, HFCUSB_STATES, HFCUSB_ACTIVATE |
- HFCUSB_DO_ACTION | HFCUSB_NT_G2_G3);
- break;
-
- case HFC_L1_DEACTIVATE_NT:
- write_reg(hw, HFCUSB_STATES,
- HFCUSB_DO_ACTION);
- break;
- }
-}
-
-/*
- * Layer 1 B-channel hardware access
- */
-static int
-channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
-{
- return mISDN_ctrl_bchannel(bch, cq);
-}
-
-/* collect data from incoming interrupt or isochron USB data */
-static void
-hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
- int finish)
-{
- struct hfcsusb *hw = fifo->hw;
- struct sk_buff *rx_skb = NULL;
- int maxlen = 0;
- int fifon = fifo->fifonum;
- int i;
- int hdlc = 0;
- unsigned long flags;
-
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s: fifo(%i) len(%i) "
- "dch(%p) bch(%p) ech(%p)\n",
- hw->name, __func__, fifon, len,
- fifo->dch, fifo->bch, fifo->ech);
-
- if (!len)
- return;
-
- if ((!!fifo->dch + !!fifo->bch + !!fifo->ech) != 1) {
- printk(KERN_DEBUG "%s: %s: undefined channel\n",
- hw->name, __func__);
- return;
- }
-
- spin_lock_irqsave(&hw->lock, flags);
- if (fifo->dch) {
- rx_skb = fifo->dch->rx_skb;
- maxlen = fifo->dch->maxlen;
- hdlc = 1;
- }
- if (fifo->bch) {
- if (test_bit(FLG_RX_OFF, &fifo->bch->Flags)) {
- fifo->bch->dropcnt += len;
- spin_unlock_irqrestore(&hw->lock, flags);
- return;
- }
- maxlen = bchannel_get_rxbuf(fifo->bch, len);
- rx_skb = fifo->bch->rx_skb;
- if (maxlen < 0) {
- if (rx_skb)
- skb_trim(rx_skb, 0);
- pr_warn("%s.B%d: No bufferspace for %d bytes\n",
- hw->name, fifo->bch->nr, len);
- spin_unlock_irqrestore(&hw->lock, flags);
- return;
- }
- maxlen = fifo->bch->maxlen;
- hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
- }
- if (fifo->ech) {
- rx_skb = fifo->ech->rx_skb;
- maxlen = fifo->ech->maxlen;
- hdlc = 1;
- }
-
- if (fifo->dch || fifo->ech) {
- if (!rx_skb) {
- rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC);
- if (rx_skb) {
- if (fifo->dch)
- fifo->dch->rx_skb = rx_skb;
- if (fifo->ech)
- fifo->ech->rx_skb = rx_skb;
- skb_trim(rx_skb, 0);
- } else {
- printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n",
- hw->name, __func__);
- spin_unlock_irqrestore(&hw->lock, flags);
- return;
- }
- }
- /* D/E-Channel SKB range check */
- if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) {
- printk(KERN_DEBUG "%s: %s: sbk mem exceeded "
- "for fifo(%d) HFCUSB_D_RX\n",
- hw->name, __func__, fifon);
- skb_trim(rx_skb, 0);
- spin_unlock_irqrestore(&hw->lock, flags);
- return;
- }
- }
-
- skb_put_data(rx_skb, data, len);
-
- if (hdlc) {
- /* we have a complete hdlc packet */
- if (finish) {
- if ((rx_skb->len > 3) &&
- (!(rx_skb->data[rx_skb->len - 1]))) {
- if (debug & DBG_HFC_FIFO_VERBOSE) {
- printk(KERN_DEBUG "%s: %s: fifon(%i)"
- " new RX len(%i): ",
- hw->name, __func__, fifon,
- rx_skb->len);
- i = 0;
- while (i < rx_skb->len)
- printk("%02x ",
- rx_skb->data[i++]);
- printk("\n");
- }
-
- /* remove CRC & status */
- skb_trim(rx_skb, rx_skb->len - 3);
-
- if (fifo->dch)
- recv_Dchannel(fifo->dch);
- if (fifo->bch)
- recv_Bchannel(fifo->bch, MISDN_ID_ANY,
- 0);
- if (fifo->ech)
- recv_Echannel(fifo->ech,
- &hw->dch);
- } else {
- if (debug & DBG_HFC_FIFO_VERBOSE) {
- printk(KERN_DEBUG
- "%s: CRC or minlen ERROR fifon(%i) "
- "RX len(%i): ",
- hw->name, fifon, rx_skb->len);
- i = 0;
- while (i < rx_skb->len)
- printk("%02x ",
- rx_skb->data[i++]);
- printk("\n");
- }
- skb_trim(rx_skb, 0);
- }
- }
- } else {
- /* deliver transparent data to layer2 */
- recv_Bchannel(fifo->bch, MISDN_ID_ANY, false);
- }
- spin_unlock_irqrestore(&hw->lock, flags);
-}
-
-static void
-fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
- void *buf, int num_packets, int packet_size, int interval,
- usb_complete_t complete, void *context)
-{
- int k;
-
- usb_fill_bulk_urb(urb, dev, pipe, buf, packet_size * num_packets,
- complete, context);
-
- urb->number_of_packets = num_packets;
- urb->transfer_flags = URB_ISO_ASAP;
- urb->actual_length = 0;
- urb->interval = interval;
-
- for (k = 0; k < num_packets; k++) {
- urb->iso_frame_desc[k].offset = packet_size * k;
- urb->iso_frame_desc[k].length = packet_size;
- urb->iso_frame_desc[k].actual_length = 0;
- }
-}
-
-/* receive completion routine for all ISO tx fifos */
-static void
-rx_iso_complete(struct urb *urb)
-{
- struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context;
- struct usb_fifo *fifo = context_iso_urb->owner_fifo;
- struct hfcsusb *hw = fifo->hw;
- int k, len, errcode, offset, num_isoc_packets, fifon, maxlen,
- status, iso_status, i;
- __u8 *buf;
- static __u8 eof[8];
- __u8 s0_state;
- unsigned long flags;
-
- fifon = fifo->fifonum;
- status = urb->status;
-
- spin_lock_irqsave(&hw->lock, flags);
- if (fifo->stop_gracefull) {
- fifo->stop_gracefull = 0;
- fifo->active = 0;
- spin_unlock_irqrestore(&hw->lock, flags);
- return;
- }
- spin_unlock_irqrestore(&hw->lock, flags);
-
- /*
- * ISO transfer only partially completed,
- * look at individual frame status for details
- */
- if (status == -EXDEV) {
- if (debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s: with -EXDEV "
- "urb->status %d, fifonum %d\n",
- hw->name, __func__, status, fifon);
-
- /* clear status, so go on with ISO transfers */
- status = 0;
- }
-
- s0_state = 0;
- if (fifo->active && !status) {
- num_isoc_packets = iso_packets[fifon];
- maxlen = fifo->usb_packet_maxlen;
-
- for (k = 0; k < num_isoc_packets; ++k) {
- len = urb->iso_frame_desc[k].actual_length;
- offset = urb->iso_frame_desc[k].offset;
- buf = context_iso_urb->buffer + offset;
- iso_status = urb->iso_frame_desc[k].status;
-
- if (iso_status && (debug & DBG_HFC_FIFO_VERBOSE)) {
- printk(KERN_DEBUG "%s: %s: "
- "ISO packet %i, status: %i\n",
- hw->name, __func__, k, iso_status);
- }
-
- /* USB data log for every D ISO in */
- if ((fifon == HFCUSB_D_RX) &&
- (debug & DBG_HFC_USB_VERBOSE)) {
- printk(KERN_DEBUG
- "%s: %s: %d (%d/%d) len(%d) ",
- hw->name, __func__, urb->start_frame,
- k, num_isoc_packets - 1,
- len);
- for (i = 0; i < len; i++)
- printk("%x ", buf[i]);
- printk("\n");
- }
-
- if (!iso_status) {
- if (fifo->last_urblen != maxlen) {
- /*
- * save fifo fill-level threshold bits
- * to use them later in TX ISO URB
- * completions
- */
- hw->threshold_mask = buf[1];
-
- if (fifon == HFCUSB_D_RX)
- s0_state = (buf[0] >> 4);
-
- eof[fifon] = buf[0] & 1;
- if (len > 2)
- hfcsusb_rx_frame(fifo, buf + 2,
- len - 2, (len < maxlen)
- ? eof[fifon] : 0);
- } else
- hfcsusb_rx_frame(fifo, buf, len,
- (len < maxlen) ?
- eof[fifon] : 0);
- fifo->last_urblen = len;
- }
- }
-
- /* signal S0 layer1 state change */
- if ((s0_state) && (hw->initdone) &&
- (s0_state != hw->dch.state)) {
- hw->dch.state = s0_state;
- schedule_event(&hw->dch, FLG_PHCHANGE);
- }
-
- fill_isoc_urb(urb, fifo->hw->dev, fifo->pipe,
- context_iso_urb->buffer, num_isoc_packets,
- fifo->usb_packet_maxlen, fifo->intervall,
- (usb_complete_t)rx_iso_complete, urb->context);
- errcode = usb_submit_urb(urb, GFP_ATOMIC);
- if (errcode < 0) {
- if (debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s: error submitting "
- "ISO URB: %d\n",
- hw->name, __func__, errcode);
- }
- } else {
- if (status && (debug & DBG_HFC_URB_INFO))
- printk(KERN_DEBUG "%s: %s: rx_iso_complete : "
- "urb->status %d, fifonum %d\n",
- hw->name, __func__, status, fifon);
- }
-}
-
-/* receive completion routine for all interrupt rx fifos */
-static void
-rx_int_complete(struct urb *urb)
-{
- int len, status, i;
- __u8 *buf, maxlen, fifon;
- struct usb_fifo *fifo = (struct usb_fifo *) urb->context;
- struct hfcsusb *hw = fifo->hw;
- static __u8 eof[8];
- unsigned long flags;
-
- spin_lock_irqsave(&hw->lock, flags);
- if (fifo->stop_gracefull) {
- fifo->stop_gracefull = 0;
- fifo->active = 0;
- spin_unlock_irqrestore(&hw->lock, flags);
- return;
- }
- spin_unlock_irqrestore(&hw->lock, flags);
-
- fifon = fifo->fifonum;
- if ((!fifo->active) || (urb->status)) {
- if (debug & DBG_HFC_URB_ERROR)
- printk(KERN_DEBUG
- "%s: %s: RX-Fifo %i is going down (%i)\n",
- hw->name, __func__, fifon, urb->status);
-
- fifo->urb->interval = 0; /* cancel automatic rescheduling */
- return;
- }
- len = urb->actual_length;
- buf = fifo->buffer;
- maxlen = fifo->usb_packet_maxlen;
-
- /* USB data log for every D INT in */
- if ((fifon == HFCUSB_D_RX) && (debug & DBG_HFC_USB_VERBOSE)) {
- printk(KERN_DEBUG "%s: %s: D RX INT len(%d) ",
- hw->name, __func__, len);
- for (i = 0; i < len; i++)
- printk("%02x ", buf[i]);
- printk("\n");
- }
-
- if (fifo->last_urblen != fifo->usb_packet_maxlen) {
- /* the threshold mask is in the 2nd status byte */
- hw->threshold_mask = buf[1];
-
- /* signal S0 layer1 state change */
- if (hw->initdone && ((buf[0] >> 4) != hw->dch.state)) {
- hw->dch.state = (buf[0] >> 4);
- schedule_event(&hw->dch, FLG_PHCHANGE);
- }
-
- eof[fifon] = buf[0] & 1;
- /* if we have more than the 2 status bytes -> collect data */
- if (len > 2)
- hfcsusb_rx_frame(fifo, buf + 2,
- urb->actual_length - 2,
- (len < maxlen) ? eof[fifon] : 0);
- } else {
- hfcsusb_rx_frame(fifo, buf, urb->actual_length,
- (len < maxlen) ? eof[fifon] : 0);
- }
- fifo->last_urblen = urb->actual_length;
-
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status) {
- if (debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s: error resubmitting USB\n",
- hw->name, __func__);
- }
-}
-
-/* transmit completion routine for all ISO tx fifos */
-static void
-tx_iso_complete(struct urb *urb)
-{
- struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context;
- struct usb_fifo *fifo = context_iso_urb->owner_fifo;
- struct hfcsusb *hw = fifo->hw;
- struct sk_buff *tx_skb;
- int k, tx_offset, num_isoc_packets, sink, remain, current_len,
- errcode, hdlc, i;
- int *tx_idx;
- int frame_complete, fifon, status, fillempty = 0;
- __u8 threshbit, *p;
- unsigned long flags;
-
- spin_lock_irqsave(&hw->lock, flags);
- if (fifo->stop_gracefull) {
- fifo->stop_gracefull = 0;
- fifo->active = 0;
- spin_unlock_irqrestore(&hw->lock, flags);
- return;
- }
-
- if (fifo->dch) {
- tx_skb = fifo->dch->tx_skb;
- tx_idx = &fifo->dch->tx_idx;
- hdlc = 1;
- } else if (fifo->bch) {
- tx_skb = fifo->bch->tx_skb;
- tx_idx = &fifo->bch->tx_idx;
- hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
- if (!tx_skb && !hdlc &&
- test_bit(FLG_FILLEMPTY, &fifo->bch->Flags))
- fillempty = 1;
- } else {
- printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n",
- hw->name, __func__);
- spin_unlock_irqrestore(&hw->lock, flags);
- return;
- }
-
- fifon = fifo->fifonum;
- status = urb->status;
-
- tx_offset = 0;
-
- /*
- * ISO transfer only partially completed,
- * look at individual frame status for details
- */
- if (status == -EXDEV) {
- if (debug & DBG_HFC_URB_ERROR)
- printk(KERN_DEBUG "%s: %s: "
- "-EXDEV (%i) fifon (%d)\n",
- hw->name, __func__, status, fifon);
-
- /* clear status, so go on with ISO transfers */
- status = 0;
- }
-
- if (fifo->active && !status) {
- /* is FifoFull-threshold set for our channel? */
- threshbit = (hw->threshold_mask & (1 << fifon));
- num_isoc_packets = iso_packets[fifon];
-
- /* predict dataflow to avoid fifo overflow */
- if (fifon >= HFCUSB_D_TX)
- sink = (threshbit) ? SINK_DMIN : SINK_DMAX;
- else
- sink = (threshbit) ? SINK_MIN : SINK_MAX;
- fill_isoc_urb(urb, fifo->hw->dev, fifo->pipe,
- context_iso_urb->buffer, num_isoc_packets,
- fifo->usb_packet_maxlen, fifo->intervall,
- (usb_complete_t)tx_iso_complete, urb->context);
- memset(context_iso_urb->buffer, 0,
- sizeof(context_iso_urb->buffer));
- frame_complete = 0;
-
- for (k = 0; k < num_isoc_packets; ++k) {
- /* analyze tx success of previous ISO packets */
- if (debug & DBG_HFC_URB_ERROR) {
- errcode = urb->iso_frame_desc[k].status;
- if (errcode) {
- printk(KERN_DEBUG "%s: %s: "
- "ISO packet %i, status: %i\n",
- hw->name, __func__, k, errcode);
- }
- }
-
- /* Generate next ISO Packets */
- if (tx_skb)
- remain = tx_skb->len - *tx_idx;
- else if (fillempty)
- remain = 15; /* > not complete */
- else
- remain = 0;
-
- if (remain > 0) {
- fifo->bit_line -= sink;
- current_len = (0 - fifo->bit_line) / 8;
- if (current_len > 14)
- current_len = 14;
- if (current_len < 0)
- current_len = 0;
- if (remain < current_len)
- current_len = remain;
-
- /* how much bit do we put on the line? */
- fifo->bit_line += current_len * 8;
-
- context_iso_urb->buffer[tx_offset] = 0;
- if (current_len == remain) {
- if (hdlc) {
- /* signal frame completion */
- context_iso_urb->
- buffer[tx_offset] = 1;
- /* add 2 byte flags and 16bit
- * CRC at end of ISDN frame */
- fifo->bit_line += 32;
- }
- frame_complete = 1;
- }
-
- /* copy tx data to iso-urb buffer */
- p = context_iso_urb->buffer + tx_offset + 1;
- if (fillempty) {
- memset(p, fifo->bch->fill[0],
- current_len);
- } else {
- memcpy(p, (tx_skb->data + *tx_idx),
- current_len);
- *tx_idx += current_len;
- }
- urb->iso_frame_desc[k].offset = tx_offset;
- urb->iso_frame_desc[k].length = current_len + 1;
-
- /* USB data log for every D ISO out */
- if ((fifon == HFCUSB_D_RX) && !fillempty &&
- (debug & DBG_HFC_USB_VERBOSE)) {
- printk(KERN_DEBUG
- "%s: %s (%d/%d) offs(%d) len(%d) ",
- hw->name, __func__,
- k, num_isoc_packets - 1,
- urb->iso_frame_desc[k].offset,
- urb->iso_frame_desc[k].length);
-
- for (i = urb->iso_frame_desc[k].offset;
- i < (urb->iso_frame_desc[k].offset
- + urb->iso_frame_desc[k].length);
- i++)
- printk("%x ",
- context_iso_urb->buffer[i]);
-
- printk(" skb->len(%i) tx-idx(%d)\n",
- tx_skb->len, *tx_idx);
- }
-
- tx_offset += (current_len + 1);
- } else {
- urb->iso_frame_desc[k].offset = tx_offset++;
- urb->iso_frame_desc[k].length = 1;
- /* we lower data margin every msec */
- fifo->bit_line -= sink;
- if (fifo->bit_line < BITLINE_INF)
- fifo->bit_line = BITLINE_INF;
- }
-
- if (frame_complete) {
- frame_complete = 0;
-
- if (debug & DBG_HFC_FIFO_VERBOSE) {
- printk(KERN_DEBUG "%s: %s: "
- "fifon(%i) new TX len(%i): ",
- hw->name, __func__,
- fifon, tx_skb->len);
- i = 0;
- while (i < tx_skb->len)
- printk("%02x ",
- tx_skb->data[i++]);
- printk("\n");
- }
-
- dev_consume_skb_irq(tx_skb);
- tx_skb = NULL;
- if (fifo->dch && get_next_dframe(fifo->dch))
- tx_skb = fifo->dch->tx_skb;
- else if (fifo->bch &&
- get_next_bframe(fifo->bch))
- tx_skb = fifo->bch->tx_skb;
- }
- }
- errcode = usb_submit_urb(urb, GFP_ATOMIC);
- if (errcode < 0) {
- if (debug & DEBUG_HW)
- printk(KERN_DEBUG
- "%s: %s: error submitting ISO URB: %d \n",
- hw->name, __func__, errcode);
- }
-
- /*
- * abuse DChannel tx iso completion to trigger NT mode state
- * changes tx_iso_complete is assumed to be called every
- * fifo->intervall (ms)
- */
- if ((fifon == HFCUSB_D_TX) && (hw->protocol == ISDN_P_NT_S0)
- && (hw->timers & NT_ACTIVATION_TIMER)) {
- if ((--hw->nt_timer) < 0)
- schedule_event(&hw->dch, FLG_PHCHANGE);
- }
-
- } else {
- if (status && (debug & DBG_HFC_URB_ERROR))
- printk(KERN_DEBUG "%s: %s: urb->status %s (%i)"
- "fifonum=%d\n",
- hw->name, __func__,
- symbolic(urb_errlist, status), status, fifon);
- }
- spin_unlock_irqrestore(&hw->lock, flags);
-}
-
-/*
- * allocs urbs and start isoc transfer with two pending urbs to avoid
- * gaps in the transfer chain
- */
-static int
-start_isoc_chain(struct usb_fifo *fifo, int num_packets_per_urb,
- usb_complete_t complete, int packet_size)
-{
- struct hfcsusb *hw = fifo->hw;
- int i, k, errcode;
-
- if (debug)
- printk(KERN_DEBUG "%s: %s: fifo %i\n",
- hw->name, __func__, fifo->fifonum);
-
- /* allocate Memory for Iso out Urbs */
- for (i = 0; i < 2; i++) {
- if (!(fifo->iso[i].urb)) {
- fifo->iso[i].urb =
- usb_alloc_urb(num_packets_per_urb, GFP_KERNEL);
- if (!(fifo->iso[i].urb)) {
- printk(KERN_DEBUG
- "%s: %s: alloc urb for fifo %i failed",
- hw->name, __func__, fifo->fifonum);
- continue;
- }
- fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
- fifo->iso[i].indx = i;
-
- /* Init the first iso */
- if (ISO_BUFFER_SIZE >=
- (fifo->usb_packet_maxlen *
- num_packets_per_urb)) {
- fill_isoc_urb(fifo->iso[i].urb,
- fifo->hw->dev, fifo->pipe,
- fifo->iso[i].buffer,
- num_packets_per_urb,
- fifo->usb_packet_maxlen,
- fifo->intervall, complete,
- &fifo->iso[i]);
- memset(fifo->iso[i].buffer, 0,
- sizeof(fifo->iso[i].buffer));
-
- for (k = 0; k < num_packets_per_urb; k++) {
- fifo->iso[i].urb->
- iso_frame_desc[k].offset =
- k * packet_size;
- fifo->iso[i].urb->
- iso_frame_desc[k].length =
- packet_size;
- }
- } else {
- printk(KERN_DEBUG
- "%s: %s: ISO Buffer size to small!\n",
- hw->name, __func__);
- }
- }
- fifo->bit_line = BITLINE_INF;
-
- errcode = usb_submit_urb(fifo->iso[i].urb, GFP_KERNEL);
- fifo->active = (errcode >= 0) ? 1 : 0;
- fifo->stop_gracefull = 0;
- if (errcode < 0) {
- printk(KERN_DEBUG "%s: %s: %s URB nr:%d\n",
- hw->name, __func__,
- symbolic(urb_errlist, errcode), i);
- }
- }
- return fifo->active;
-}
-
-static void
-stop_iso_gracefull(struct usb_fifo *fifo)
-{
- struct hfcsusb *hw = fifo->hw;
- int i, timeout;
- u_long flags;
-
- for (i = 0; i < 2; i++) {
- spin_lock_irqsave(&hw->lock, flags);
- if (debug)
- printk(KERN_DEBUG "%s: %s for fifo %i.%i\n",
- hw->name, __func__, fifo->fifonum, i);
- fifo->stop_gracefull = 1;
- spin_unlock_irqrestore(&hw->lock, flags);
- }
-
- for (i = 0; i < 2; i++) {
- timeout = 3;
- while (fifo->stop_gracefull && timeout--)
- schedule_timeout_interruptible((HZ / 1000) * 16);
- if (debug && fifo->stop_gracefull)
- printk(KERN_DEBUG "%s: ERROR %s for fifo %i.%i\n",
- hw->name, __func__, fifo->fifonum, i);
- }
-}
-
-static void
-stop_int_gracefull(struct usb_fifo *fifo)
-{
- struct hfcsusb *hw = fifo->hw;
- int timeout;
- u_long flags;
-
- spin_lock_irqsave(&hw->lock, flags);
- if (debug)
- printk(KERN_DEBUG "%s: %s for fifo %i\n",
- hw->name, __func__, fifo->fifonum);
- fifo->stop_gracefull = 1;
- spin_unlock_irqrestore(&hw->lock, flags);
-
- timeout = 3;
- while (fifo->stop_gracefull && timeout--)
- schedule_timeout_interruptible((HZ / 1000) * 3);
- if (debug && fifo->stop_gracefull)
- printk(KERN_DEBUG "%s: ERROR %s for fifo %i\n",
- hw->name, __func__, fifo->fifonum);
-}
-
-/* start the interrupt transfer for the given fifo */
-static void
-start_int_fifo(struct usb_fifo *fifo)
-{
- struct hfcsusb *hw = fifo->hw;
- int errcode;
-
- if (debug)
- printk(KERN_DEBUG "%s: %s: INT IN fifo:%d\n",
- hw->name, __func__, fifo->fifonum);
-
- if (!fifo->urb) {
- fifo->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!fifo->urb)
- return;
- }
- usb_fill_int_urb(fifo->urb, fifo->hw->dev, fifo->pipe,
- fifo->buffer, fifo->usb_packet_maxlen,
- (usb_complete_t)rx_int_complete, fifo, fifo->intervall);
- fifo->active = 1;
- fifo->stop_gracefull = 0;
- errcode = usb_submit_urb(fifo->urb, GFP_KERNEL);
- if (errcode) {
- printk(KERN_DEBUG "%s: %s: submit URB: status:%i\n",
- hw->name, __func__, errcode);
- fifo->active = 0;
- }
-}
-
-static void
-setPortMode(struct hfcsusb *hw)
-{
- if (debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s %s\n", hw->name, __func__,
- (hw->protocol == ISDN_P_TE_S0) ? "TE" : "NT");
-
- if (hw->protocol == ISDN_P_TE_S0) {
- write_reg(hw, HFCUSB_SCTRL, 0x40);
- write_reg(hw, HFCUSB_SCTRL_E, 0x00);
- write_reg(hw, HFCUSB_CLKDEL, CLKDEL_TE);
- write_reg(hw, HFCUSB_STATES, 3 | 0x10);
- write_reg(hw, HFCUSB_STATES, 3);
- } else {
- write_reg(hw, HFCUSB_SCTRL, 0x44);
- write_reg(hw, HFCUSB_SCTRL_E, 0x09);
- write_reg(hw, HFCUSB_CLKDEL, CLKDEL_NT);
- write_reg(hw, HFCUSB_STATES, 1 | 0x10);
- write_reg(hw, HFCUSB_STATES, 1);
- }
-}
-
-static void
-reset_hfcsusb(struct hfcsusb *hw)
-{
- struct usb_fifo *fifo;
- int i;
-
- if (debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
-
- /* do Chip reset */
- write_reg(hw, HFCUSB_CIRM, 8);
-
- /* aux = output, reset off */
- write_reg(hw, HFCUSB_CIRM, 0x10);
-
- /* set USB_SIZE to match the wMaxPacketSize for INT or BULK transfers */
- write_reg(hw, HFCUSB_USB_SIZE, (hw->packet_size / 8) |
- ((hw->packet_size / 8) << 4));
-
- /* set USB_SIZE_I to match the wMaxPacketSize for ISO transfers */
- write_reg(hw, HFCUSB_USB_SIZE_I, hw->iso_packet_size);
-
- /* enable PCM/GCI master mode */
- write_reg(hw, HFCUSB_MST_MODE1, 0); /* set default values */
- write_reg(hw, HFCUSB_MST_MODE0, 1); /* enable master mode */
-
- /* init the fifos */
- write_reg(hw, HFCUSB_F_THRES,
- (HFCUSB_TX_THRESHOLD / 8) | ((HFCUSB_RX_THRESHOLD / 8) << 4));
-
- fifo = hw->fifos;
- for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
- write_reg(hw, HFCUSB_FIFO, i); /* select the desired fifo */
- fifo[i].max_size =
- (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
- fifo[i].last_urblen = 0;
-
- /* set 2 bit for D- & E-channel */
- write_reg(hw, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2));
-
- /* enable all fifos */
- if (i == HFCUSB_D_TX)
- write_reg(hw, HFCUSB_CON_HDLC,
- (hw->protocol == ISDN_P_NT_S0) ? 0x08 : 0x09);
- else
- write_reg(hw, HFCUSB_CON_HDLC, 0x08);
- write_reg(hw, HFCUSB_INC_RES_F, 2); /* reset the fifo */
- }
-
- write_reg(hw, HFCUSB_SCTRL_R, 0); /* disable both B receivers */
- handle_led(hw, LED_POWER_ON);
-}
-
-/* start USB data pipes dependand on device's endpoint configuration */
-static void
-hfcsusb_start_endpoint(struct hfcsusb *hw, int channel)
-{
- /* quick check if endpoint already running */
- if ((channel == HFC_CHAN_D) && (hw->fifos[HFCUSB_D_RX].active))
- return;
- if ((channel == HFC_CHAN_B1) && (hw->fifos[HFCUSB_B1_RX].active))
- return;
- if ((channel == HFC_CHAN_B2) && (hw->fifos[HFCUSB_B2_RX].active))
- return;
- if ((channel == HFC_CHAN_E) && (hw->fifos[HFCUSB_PCM_RX].active))
- return;
-
- /* start rx endpoints using USB INT IN method */
- if (hw->cfg_used == CNF_3INT3ISO || hw->cfg_used == CNF_4INT3ISO)
- start_int_fifo(hw->fifos + channel * 2 + 1);
-
- /* start rx endpoints using USB ISO IN method */
- if (hw->cfg_used == CNF_3ISO3ISO || hw->cfg_used == CNF_4ISO3ISO) {
- switch (channel) {
- case HFC_CHAN_D:
- start_isoc_chain(hw->fifos + HFCUSB_D_RX,
- ISOC_PACKETS_D,
- (usb_complete_t)rx_iso_complete,
- 16);
- break;
- case HFC_CHAN_E:
- start_isoc_chain(hw->fifos + HFCUSB_PCM_RX,
- ISOC_PACKETS_D,
- (usb_complete_t)rx_iso_complete,
- 16);
- break;
- case HFC_CHAN_B1:
- start_isoc_chain(hw->fifos + HFCUSB_B1_RX,
- ISOC_PACKETS_B,
- (usb_complete_t)rx_iso_complete,
- 16);
- break;
- case HFC_CHAN_B2:
- start_isoc_chain(hw->fifos + HFCUSB_B2_RX,
- ISOC_PACKETS_B,
- (usb_complete_t)rx_iso_complete,
- 16);
- break;
- }
- }
-
- /* start tx endpoints using USB ISO OUT method */
- switch (channel) {
- case HFC_CHAN_D:
- start_isoc_chain(hw->fifos + HFCUSB_D_TX,
- ISOC_PACKETS_B,
- (usb_complete_t)tx_iso_complete, 1);
- break;
- case HFC_CHAN_B1:
- start_isoc_chain(hw->fifos + HFCUSB_B1_TX,
- ISOC_PACKETS_D,
- (usb_complete_t)tx_iso_complete, 1);
- break;
- case HFC_CHAN_B2:
- start_isoc_chain(hw->fifos + HFCUSB_B2_TX,
- ISOC_PACKETS_B,
- (usb_complete_t)tx_iso_complete, 1);
- break;
- }
-}
-
-/* stop USB data pipes dependand on device's endpoint configuration */
-static void
-hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel)
-{
- /* quick check if endpoint currently running */
- if ((channel == HFC_CHAN_D) && (!hw->fifos[HFCUSB_D_RX].active))
- return;
- if ((channel == HFC_CHAN_B1) && (!hw->fifos[HFCUSB_B1_RX].active))
- return;
- if ((channel == HFC_CHAN_B2) && (!hw->fifos[HFCUSB_B2_RX].active))
- return;
- if ((channel == HFC_CHAN_E) && (!hw->fifos[HFCUSB_PCM_RX].active))
- return;
-
- /* rx endpoints using USB INT IN method */
- if (hw->cfg_used == CNF_3INT3ISO || hw->cfg_used == CNF_4INT3ISO)
- stop_int_gracefull(hw->fifos + channel * 2 + 1);
-
- /* rx endpoints using USB ISO IN method */
- if (hw->cfg_used == CNF_3ISO3ISO || hw->cfg_used == CNF_4ISO3ISO)
- stop_iso_gracefull(hw->fifos + channel * 2 + 1);
-
- /* tx endpoints using USB ISO OUT method */
- if (channel != HFC_CHAN_E)
- stop_iso_gracefull(hw->fifos + channel * 2);
-}
-
-
-/* Hardware Initialization */
-static int
-setup_hfcsusb(struct hfcsusb *hw)
-{
- void *dmabuf = kmalloc_obj(u_char);
- u_char b;
- int ret;
-
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
-
- if (!dmabuf)
- return -ENOMEM;
-
- ret = read_reg_atomic(hw, HFCUSB_CHIP_ID, dmabuf);
-
- memcpy(&b, dmabuf, sizeof(u_char));
- kfree(dmabuf);
-
- /* check the chip id */
- if (ret != 1) {
- printk(KERN_DEBUG "%s: %s: cannot read chip id\n",
- hw->name, __func__);
- return 1;
- }
- if (b != HFCUSB_CHIPID) {
- printk(KERN_DEBUG "%s: %s: Invalid chip id 0x%02x\n",
- hw->name, __func__, b);
- return 1;
- }
-
- /* first set the needed config, interface and alternate */
- (void) usb_set_interface(hw->dev, hw->if_used, hw->alt_used);
-
- hw->led_state = 0;
-
- /* init the background machinery for control requests */
- hw->ctrl_read.bRequestType = 0xc0;
- hw->ctrl_read.bRequest = 1;
- hw->ctrl_read.wLength = cpu_to_le16(1);
- hw->ctrl_write.bRequestType = 0x40;
- hw->ctrl_write.bRequest = 0;
- hw->ctrl_write.wLength = 0;
- usb_fill_control_urb(hw->ctrl_urb, hw->dev, hw->ctrl_out_pipe,
- (u_char *)&hw->ctrl_write, NULL, 0,
- (usb_complete_t)ctrl_complete, hw);
-
- reset_hfcsusb(hw);
- return 0;
-}
-
-static void
-release_hw(struct hfcsusb *hw)
-{
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
-
- /*
- * stop all endpoints gracefully
- * TODO: mISDN_core should generate CLOSE_CHANNEL
- * signals after calling mISDN_unregister_device()
- */
- hfcsusb_stop_endpoint(hw, HFC_CHAN_D);
- hfcsusb_stop_endpoint(hw, HFC_CHAN_B1);
- hfcsusb_stop_endpoint(hw, HFC_CHAN_B2);
- if (hw->fifos[HFCUSB_PCM_RX].pipe)
- hfcsusb_stop_endpoint(hw, HFC_CHAN_E);
- if (hw->protocol == ISDN_P_TE_S0)
- l1_event(hw->dch.l1, CLOSE_CHANNEL);
-
- mISDN_unregister_device(&hw->dch.dev);
- mISDN_freebchannel(&hw->bch[1]);
- mISDN_freebchannel(&hw->bch[0]);
- mISDN_freedchannel(&hw->dch);
-
- if (hw->ctrl_urb) {
- usb_kill_urb(hw->ctrl_urb);
- usb_free_urb(hw->ctrl_urb);
- hw->ctrl_urb = NULL;
- }
-
- if (hw->intf)
- usb_set_intfdata(hw->intf, NULL);
- list_del(&hw->list);
- kfree(hw);
- hw = NULL;
-}
-
-static void
-deactivate_bchannel(struct bchannel *bch)
-{
- struct hfcsusb *hw = bch->hw;
- u_long flags;
-
- if (bch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: %s: bch->nr(%i)\n",
- hw->name, __func__, bch->nr);
-
- spin_lock_irqsave(&hw->lock, flags);
- mISDN_clear_bchannel(bch);
- spin_unlock_irqrestore(&hw->lock, flags);
- hfcsusb_setup_bch(bch, ISDN_P_NONE);
- hfcsusb_stop_endpoint(hw, bch->nr - 1);
-}
-
-/*
- * Layer 1 B-channel hardware access
- */
-static int
-hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- int ret = -EINVAL;
-
- if (bch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg);
-
- switch (cmd) {
- case HW_TESTRX_RAW:
- case HW_TESTRX_HDLC:
- case HW_TESTRX_OFF:
- ret = -EINVAL;
- break;
-
- case CLOSE_CHANNEL:
- test_and_clear_bit(FLG_OPEN, &bch->Flags);
- deactivate_bchannel(bch);
- ch->protocol = ISDN_P_NONE;
- ch->peer = NULL;
- module_put(THIS_MODULE);
- ret = 0;
- break;
- case CONTROL_CHANNEL:
- ret = channel_bctrl(bch, arg);
- break;
- default:
- printk(KERN_WARNING "%s: unknown prim(%x)\n",
- __func__, cmd);
- }
- return ret;
-}
-
-static int
-setup_instance(struct hfcsusb *hw, struct device *parent)
-{
- u_long flags;
- int err, i;
-
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
-
- spin_lock_init(&hw->ctrl_lock);
- spin_lock_init(&hw->lock);
-
- mISDN_initdchannel(&hw->dch, MAX_DFRAME_LEN_L1, ph_state);
- hw->dch.debug = debug & 0xFFFF;
- hw->dch.hw = hw;
- hw->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0);
- hw->dch.dev.D.send = hfcusb_l2l1D;
- hw->dch.dev.D.ctrl = hfc_dctrl;
-
- /* enable E-Channel logging */
- if (hw->fifos[HFCUSB_PCM_RX].pipe)
- mISDN_initdchannel(&hw->ech, MAX_DFRAME_LEN_L1, NULL);
-
- hw->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
- hw->dch.dev.nrbchan = 2;
- for (i = 0; i < 2; i++) {
- hw->bch[i].nr = i + 1;
- set_channelmap(i + 1, hw->dch.dev.channelmap);
- hw->bch[i].debug = debug;
- mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM, poll >> 1);
- hw->bch[i].hw = hw;
- hw->bch[i].ch.send = hfcusb_l2l1B;
- hw->bch[i].ch.ctrl = hfc_bctrl;
- hw->bch[i].ch.nr = i + 1;
- list_add(&hw->bch[i].ch.list, &hw->dch.dev.bchannels);
- }
-
- hw->fifos[HFCUSB_B1_TX].bch = &hw->bch[0];
- hw->fifos[HFCUSB_B1_RX].bch = &hw->bch[0];
- hw->fifos[HFCUSB_B2_TX].bch = &hw->bch[1];
- hw->fifos[HFCUSB_B2_RX].bch = &hw->bch[1];
- hw->fifos[HFCUSB_D_TX].dch = &hw->dch;
- hw->fifos[HFCUSB_D_RX].dch = &hw->dch;
- hw->fifos[HFCUSB_PCM_RX].ech = &hw->ech;
- hw->fifos[HFCUSB_PCM_TX].ech = &hw->ech;
-
- err = setup_hfcsusb(hw);
- if (err)
- goto out;
-
- snprintf(hw->name, MISDN_MAX_IDLEN - 1, "%s.%d", DRIVER_NAME,
- hfcsusb_cnt + 1);
- printk(KERN_INFO "%s: registered as '%s'\n",
- DRIVER_NAME, hw->name);
-
- err = mISDN_register_device(&hw->dch.dev, parent, hw->name);
- if (err)
- goto out;
-
- hfcsusb_cnt++;
- write_lock_irqsave(&HFClock, flags);
- list_add_tail(&hw->list, &HFClist);
- write_unlock_irqrestore(&HFClock, flags);
- return 0;
-
-out:
- mISDN_freebchannel(&hw->bch[1]);
- mISDN_freebchannel(&hw->bch[0]);
- mISDN_freedchannel(&hw->dch);
- return err;
-}
-
-static int
-hfcsusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
- int err;
- struct hfcsusb *hw;
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usb_host_interface *iface = intf->cur_altsetting;
- struct usb_host_interface *iface_used = NULL;
- struct usb_host_endpoint *ep;
- struct hfcsusb_vdata *driver_info;
- int ifnum = iface->desc.bInterfaceNumber, i, idx, alt_idx,
- probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found,
- ep_addr, cmptbl[16], small_match, iso_packet_size, packet_size,
- alt_used = 0;
-
- vend_idx = 0xffff;
- for (i = 0; hfcsusb_idtab[i].idVendor; i++) {
- if ((le16_to_cpu(dev->descriptor.idVendor)
- == hfcsusb_idtab[i].idVendor) &&
- (le16_to_cpu(dev->descriptor.idProduct)
- == hfcsusb_idtab[i].idProduct)) {
- vend_idx = i;
- continue;
- }
- }
-
- printk(KERN_DEBUG
- "%s: interface(%d) actalt(%d) minor(%d) vend_idx(%d)\n",
- __func__, ifnum, iface->desc.bAlternateSetting,
- intf->minor, vend_idx);
-
- if (vend_idx == 0xffff) {
- printk(KERN_WARNING
- "%s: no valid vendor found in USB descriptor\n",
- __func__);
- return -EIO;
- }
- /* if vendor and product ID is OK, start probing alternate settings */
- alt_idx = 0;
- small_match = -1;
-
- /* default settings */
- iso_packet_size = 16;
- packet_size = 64;
-
- while (alt_idx < intf->num_altsetting) {
- iface = intf->altsetting + alt_idx;
- probe_alt_setting = iface->desc.bAlternateSetting;
- cfg_used = 0;
-
- while (validconf[cfg_used][0]) {
- cfg_found = 1;
- vcf = validconf[cfg_used];
- ep = iface->endpoint;
- memcpy(cmptbl, vcf, 16 * sizeof(int));
-
- /* check for all endpoints in this alternate setting */
- for (i = 0; i < iface->desc.bNumEndpoints; i++) {
- ep_addr = ep->desc.bEndpointAddress;
-
- /* get endpoint base */
- idx = ((ep_addr & 0x7f) - 1) * 2;
- if (idx > 15)
- return -EIO;
-
- if (ep_addr & 0x80)
- idx++;
- attr = ep->desc.bmAttributes;
-
- if (cmptbl[idx] != EP_NOP) {
- if (cmptbl[idx] == EP_NUL)
- cfg_found = 0;
- if (attr == USB_ENDPOINT_XFER_INT
- && cmptbl[idx] == EP_INT)
- cmptbl[idx] = EP_NUL;
- if (attr == USB_ENDPOINT_XFER_BULK
- && cmptbl[idx] == EP_BLK)
- cmptbl[idx] = EP_NUL;
- if (attr == USB_ENDPOINT_XFER_ISOC
- && cmptbl[idx] == EP_ISO)
- cmptbl[idx] = EP_NUL;
-
- if (attr == USB_ENDPOINT_XFER_INT &&
- ep->desc.bInterval < vcf[17]) {
- cfg_found = 0;
- }
- }
- ep++;
- }
-
- for (i = 0; i < 16; i++)
- if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL)
- cfg_found = 0;
-
- if (cfg_found) {
- if (small_match < cfg_used) {
- small_match = cfg_used;
- alt_used = probe_alt_setting;
- iface_used = iface;
- }
- }
- cfg_used++;
- }
- alt_idx++;
- } /* (alt_idx < intf->num_altsetting) */
-
- /* not found a valid USB Ta Endpoint config */
- if (small_match == -1)
- return -EIO;
-
- iface = iface_used;
- hw = kzalloc_obj(struct hfcsusb);
- if (!hw)
- return -ENOMEM; /* got no mem */
- snprintf(hw->name, MISDN_MAX_IDLEN - 1, "%s", DRIVER_NAME);
-
- ep = iface->endpoint;
- vcf = validconf[small_match];
-
- for (i = 0; i < iface->desc.bNumEndpoints; i++) {
- struct usb_fifo *f;
-
- ep_addr = ep->desc.bEndpointAddress;
- /* get endpoint base */
- idx = ((ep_addr & 0x7f) - 1) * 2;
- if (ep_addr & 0x80)
- idx++;
- f = &hw->fifos[idx & 7];
-
- /* init Endpoints */
- if (vcf[idx] == EP_NOP || vcf[idx] == EP_NUL) {
- ep++;
- continue;
- }
- switch (ep->desc.bmAttributes) {
- case USB_ENDPOINT_XFER_INT:
- f->pipe = usb_rcvintpipe(dev,
- ep->desc.bEndpointAddress);
- f->usb_transfer_mode = USB_INT;
- packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
- break;
- case USB_ENDPOINT_XFER_BULK:
- if (ep_addr & 0x80)
- f->pipe = usb_rcvbulkpipe(dev,
- ep->desc.bEndpointAddress);
- else
- f->pipe = usb_sndbulkpipe(dev,
- ep->desc.bEndpointAddress);
- f->usb_transfer_mode = USB_BULK;
- packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
- break;
- case USB_ENDPOINT_XFER_ISOC:
- if (ep_addr & 0x80)
- f->pipe = usb_rcvisocpipe(dev,
- ep->desc.bEndpointAddress);
- else
- f->pipe = usb_sndisocpipe(dev,
- ep->desc.bEndpointAddress);
- f->usb_transfer_mode = USB_ISOC;
- iso_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
- break;
- default:
- f->pipe = 0;
- }
-
- if (f->pipe) {
- f->fifonum = idx & 7;
- f->hw = hw;
- f->usb_packet_maxlen =
- le16_to_cpu(ep->desc.wMaxPacketSize);
- f->intervall = ep->desc.bInterval;
- }
- ep++;
- }
- hw->dev = dev; /* save device */
- hw->if_used = ifnum; /* save used interface */
- hw->alt_used = alt_used; /* and alternate config */
- hw->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */
- hw->cfg_used = vcf[16]; /* store used config */
- hw->vend_idx = vend_idx; /* store found vendor */
- hw->packet_size = packet_size;
- hw->iso_packet_size = iso_packet_size;
-
- /* create the control pipes needed for register access */
- hw->ctrl_in_pipe = usb_rcvctrlpipe(hw->dev, 0);
- hw->ctrl_out_pipe = usb_sndctrlpipe(hw->dev, 0);
-
- driver_info = (struct hfcsusb_vdata *)
- hfcsusb_idtab[vend_idx].driver_info;
-
- hw->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!hw->ctrl_urb) {
- pr_warn("%s: No memory for control urb\n",
- driver_info->vend_name);
- err = -ENOMEM;
- goto err_free_hw;
- }
-
- pr_info("%s: %s: detected \"%s\" (%s, if=%d alt=%d)\n",
- hw->name, __func__, driver_info->vend_name,
- conf_str[small_match], ifnum, alt_used);
-
- if (setup_instance(hw, dev->dev.parent)) {
- err = -EIO;
- goto err_free_urb;
- }
-
- hw->intf = intf;
- usb_set_intfdata(hw->intf, hw);
- return 0;
-
-err_free_urb:
- usb_free_urb(hw->ctrl_urb);
-err_free_hw:
- kfree(hw);
- return err;
-}
-
-/* function called when an active device is removed */
-static void
-hfcsusb_disconnect(struct usb_interface *intf)
-{
- struct hfcsusb *hw = usb_get_intfdata(intf);
- struct hfcsusb *next;
- int cnt = 0;
-
- printk(KERN_INFO "%s: device disconnected\n", hw->name);
-
- handle_led(hw, LED_POWER_OFF);
- release_hw(hw);
-
- list_for_each_entry_safe(hw, next, &HFClist, list)
- cnt++;
- if (!cnt)
- hfcsusb_cnt = 0;
-
- usb_set_intfdata(intf, NULL);
-}
-
-static struct usb_driver hfcsusb_drv = {
- .name = DRIVER_NAME,
- .id_table = hfcsusb_idtab,
- .probe = hfcsusb_probe,
- .disconnect = hfcsusb_disconnect,
- .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(hfcsusb_drv);
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * hfcsusb.h, HFC-S USB mISDN driver
- */
-
-#ifndef __HFCSUSB_H__
-#define __HFCSUSB_H__
-
-
-#define DRIVER_NAME "HFC-S_USB"
-
-#define DBG_HFC_CALL_TRACE 0x00010000
-#define DBG_HFC_FIFO_VERBOSE 0x00020000
-#define DBG_HFC_USB_VERBOSE 0x00100000
-#define DBG_HFC_URB_INFO 0x00200000
-#define DBG_HFC_URB_ERROR 0x00400000
-
-#define DEFAULT_TRANSP_BURST_SZ 128
-
-#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */
-#define CLKDEL_TE 0x0f /* CLKDEL in TE mode */
-#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */
-
-/* hfcsusb Layer1 commands */
-#define HFC_L1_ACTIVATE_TE 1
-#define HFC_L1_ACTIVATE_NT 2
-#define HFC_L1_DEACTIVATE_NT 3
-#define HFC_L1_FORCE_DEACTIVATE_TE 4
-
-/* cmd FLAGS in HFCUSB_STATES register */
-#define HFCUSB_LOAD_STATE 0x10
-#define HFCUSB_ACTIVATE 0x20
-#define HFCUSB_DO_ACTION 0x40
-#define HFCUSB_NT_G2_G3 0x80
-
-/* timers */
-#define NT_ACTIVATION_TIMER 0x01 /* enables NT mode activation Timer */
-#define NT_T1_COUNT 10
-
-#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
-
-#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
-#define HFCUSB_TX_THRESHOLD 96 /* threshold for fifo report bit tx */
-
-#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */
-#define HFCUSB_CIRM 0x00 /* cirm register index */
-#define HFCUSB_USB_SIZE 0x07 /* int length register */
-#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */
-#define HFCUSB_F_CROSS 0x0b /* bit order register */
-#define HFCUSB_CLKDEL 0x37 /* bit delay register */
-#define HFCUSB_CON_HDLC 0xfa /* channel connect register */
-#define HFCUSB_HDLC_PAR 0xfb
-#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */
-#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */
-#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */
-#define HFCUSB_F_THRES 0x0c /* threshold register */
-#define HFCUSB_FIFO 0x0f /* fifo select register */
-#define HFCUSB_F_USAGE 0x1a /* fifo usage register */
-#define HFCUSB_MST_MODE0 0x14
-#define HFCUSB_MST_MODE1 0x15
-#define HFCUSB_P_DATA 0x1f
-#define HFCUSB_INC_RES_F 0x0e
-#define HFCUSB_B1_SSL 0x20
-#define HFCUSB_B2_SSL 0x21
-#define HFCUSB_B1_RSL 0x24
-#define HFCUSB_B2_RSL 0x25
-#define HFCUSB_STATES 0x30
-
-
-#define HFCUSB_CHIPID 0x40 /* ID value of HFC-S USB */
-
-/* fifo registers */
-#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */
-#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */
-#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */
-#define HFCUSB_B2_TX 2
-#define HFCUSB_B2_RX 3
-#define HFCUSB_D_TX 4
-#define HFCUSB_D_RX 5
-#define HFCUSB_PCM_TX 6
-#define HFCUSB_PCM_RX 7
-
-
-#define USB_INT 0
-#define USB_BULK 1
-#define USB_ISOC 2
-
-#define ISOC_PACKETS_D 8
-#define ISOC_PACKETS_B 8
-#define ISO_BUFFER_SIZE 128
-
-/* defines how much ISO packets are handled in one URB */
-static int iso_packets[8] =
-{ ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B,
- ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D
-};
-
-
-/* Fifo flow Control for TX ISO */
-#define SINK_MAX 68
-#define SINK_MIN 48
-#define SINK_DMIN 12
-#define SINK_DMAX 18
-#define BITLINE_INF (-96 * 8)
-
-/* HFC-S USB register access by Control-URSs */
-#define write_reg_atomic(a, b, c) \
- usb_control_msg((a)->dev, (a)->ctrl_out_pipe, 0, 0x40, (c), (b), \
- 0, 0, HFC_CTRL_TIMEOUT)
-#define read_reg_atomic(a, b, c) \
- usb_control_msg((a)->dev, (a)->ctrl_in_pipe, 1, 0xC0, 0, (b), (c), \
- 1, HFC_CTRL_TIMEOUT)
-#define HFC_CTRL_BUFSIZE 64
-
-struct ctrl_buf {
- __u8 hfcs_reg; /* register number */
- __u8 reg_val; /* value to be written (or read) */
-};
-
-/*
- * URB error codes
- * Used to represent a list of values and their respective symbolic names
- */
-struct hfcusb_symbolic_list {
- const int num;
- const char *name;
-};
-
-static struct hfcusb_symbolic_list urb_errlist[] = {
- {-ENOMEM, "No memory for allocation of internal structures"},
- {-ENOSPC, "The host controller's bandwidth is already consumed"},
- {-ENOENT, "URB was canceled by unlink_urb"},
- {-EXDEV, "ISO transfer only partially completed"},
- {-EAGAIN, "Too match scheduled for the future"},
- {-ENXIO, "URB already queued"},
- {-EFBIG, "Too much ISO frames requested"},
- {-ENOSR, "Buffer error (overrun)"},
- {-EPIPE, "Specified endpoint is stalled (device not responding)"},
- {-EOVERFLOW, "Babble (bad cable?)"},
- {-EPROTO, "Bit-stuff error (bad cable?)"},
- {-EILSEQ, "CRC/Timeout"},
- {-ETIMEDOUT, "NAK (device does not respond)"},
- {-ESHUTDOWN, "Device unplugged"},
- {-1, NULL}
-};
-
-static inline const char *
-symbolic(struct hfcusb_symbolic_list list[], const int num)
-{
- int i;
- for (i = 0; list[i].name != NULL; i++)
- if (list[i].num == num)
- return list[i].name;
- return "<unknown USB Error>";
-}
-
-/* USB descriptor need to contain one of the following EndPoint combination: */
-#define CNF_4INT3ISO 1 /* 4 INT IN, 3 ISO OUT */
-#define CNF_3INT3ISO 2 /* 3 INT IN, 3 ISO OUT */
-#define CNF_4ISO3ISO 3 /* 4 ISO IN, 3 ISO OUT */
-#define CNF_3ISO3ISO 4 /* 3 ISO IN, 3 ISO OUT */
-
-#define EP_NUL 1 /* Endpoint at this position not allowed */
-#define EP_NOP 2 /* all type of endpoints allowed at this position */
-#define EP_ISO 3 /* Isochron endpoint mandatory at this position */
-#define EP_BLK 4 /* Bulk endpoint mandatory at this position */
-#define EP_INT 5 /* Interrupt endpoint mandatory at this position */
-
-#define HFC_CHAN_B1 0
-#define HFC_CHAN_B2 1
-#define HFC_CHAN_D 2
-#define HFC_CHAN_E 3
-
-
-/*
- * List of all supported endpoint configuration sets, used to find the
- * best matching endpoint configuration within a device's USB descriptor.
- * We need at least 3 RX endpoints, and 3 TX endpoints, either
- * INT-in and ISO-out, or ISO-in and ISO-out)
- * with 4 RX endpoints even E-Channel logging is possible
- */
-static int
-validconf[][19] = {
- /* INT in, ISO out config */
- {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
- EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
- CNF_4INT3ISO, 2, 1},
- {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL,
- EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
- CNF_3INT3ISO, 2, 0},
- /* ISO in, ISO out config */
- {EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP,
- EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO,
- CNF_4ISO3ISO, 2, 1},
- {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
- EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL,
- CNF_3ISO3ISO, 2, 0},
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* EOL element */
-};
-
-/* string description of chosen config */
-static char *conf_str[] = {
- "4 Interrupt IN + 3 Isochron OUT",
- "3 Interrupt IN + 3 Isochron OUT",
- "4 Isochron IN + 3 Isochron OUT",
- "3 Isochron IN + 3 Isochron OUT"
-};
-
-
-#define LED_OFF 0 /* no LED support */
-#define LED_SCHEME1 1 /* LED standard scheme */
-#define LED_SCHEME2 2 /* not used yet... */
-
-#define LED_POWER_ON 1
-#define LED_POWER_OFF 2
-#define LED_S0_ON 3
-#define LED_S0_OFF 4
-#define LED_B1_ON 5
-#define LED_B1_OFF 6
-#define LED_B1_DATA 7
-#define LED_B2_ON 8
-#define LED_B2_OFF 9
-#define LED_B2_DATA 10
-
-#define LED_NORMAL 0 /* LEDs are normal */
-#define LED_INVERTED 1 /* LEDs are inverted */
-
-/* time in ms to perform a Flashing LED when B-Channel has traffic */
-#define LED_TIME 250
-
-
-
-struct hfcsusb;
-struct usb_fifo;
-
-/* structure defining input+output fifos (interrupt/bulk mode) */
-struct iso_urb {
- struct urb *urb;
- __u8 buffer[ISO_BUFFER_SIZE]; /* buffer rx/tx USB URB data */
- struct usb_fifo *owner_fifo; /* pointer to owner fifo */
- __u8 indx; /* Fifos's ISO double buffer 0 or 1 ? */
-#ifdef ISO_FRAME_START_DEBUG
- int start_frames[ISO_FRAME_START_RING_COUNT];
- __u8 iso_frm_strt_pos; /* index in start_frame[] */
-#endif
-};
-
-struct usb_fifo {
- int fifonum; /* fifo index attached to this structure */
- int active; /* fifo is currently active */
- struct hfcsusb *hw; /* pointer to main structure */
- int pipe; /* address of endpoint */
- __u8 usb_packet_maxlen; /* maximum length for usb transfer */
- unsigned int max_size; /* maximum size of receive/send packet */
- __u8 intervall; /* interrupt interval */
- struct urb *urb; /* transfer structure for usb routines */
- __u8 buffer[128]; /* buffer USB INT OUT URB data */
- int bit_line; /* how much bits are in the fifo? */
-
- __u8 usb_transfer_mode; /* switched between ISO and INT */
- struct iso_urb iso[2]; /* two urbs to have one always
- one pending */
-
- struct dchannel *dch; /* link to hfcsusb_t->dch */
- struct bchannel *bch; /* link to hfcsusb_t->bch */
- struct dchannel *ech; /* link to hfcsusb_t->ech, TODO: E-CHANNEL */
- int last_urblen; /* remember length of last packet */
- __u8 stop_gracefull; /* stops URB retransmission */
-};
-
-struct hfcsusb {
- struct list_head list;
- struct dchannel dch;
- struct bchannel bch[2];
- struct dchannel ech; /* TODO : wait for struct echannel ;) */
-
- struct usb_device *dev; /* our device */
- struct usb_interface *intf; /* used interface */
- int if_used; /* used interface number */
- int alt_used; /* used alternate config */
- int cfg_used; /* configuration index used */
- int vend_idx; /* index in hfcsusb_idtab */
- int packet_size;
- int iso_packet_size;
- struct usb_fifo fifos[HFCUSB_NUM_FIFOS];
-
- /* control pipe background handling */
- struct ctrl_buf ctrl_buff[HFC_CTRL_BUFSIZE];
- int ctrl_in_idx, ctrl_out_idx, ctrl_cnt;
- struct urb *ctrl_urb;
- struct usb_ctrlrequest ctrl_write;
- struct usb_ctrlrequest ctrl_read;
- int ctrl_paksize;
- int ctrl_in_pipe, ctrl_out_pipe;
- spinlock_t ctrl_lock; /* lock for ctrl */
- spinlock_t lock;
-
- __u8 threshold_mask;
- __u8 led_state;
-
- __u8 protocol;
- int nt_timer;
- int open;
- __u8 timers;
- __u8 initdone;
- char name[MISDN_MAX_IDLEN];
-};
-
-/* private vendor specific data */
-struct hfcsusb_vdata {
- __u8 led_scheme; /* led display scheme */
- signed short led_bits[8]; /* array of 8 possible LED bitmask */
- char *vend_name; /* device name */
-};
-
-
-#define HFC_MAX_TE_LAYER1_STATE 8
-#define HFC_MAX_NT_LAYER1_STATE 4
-
-static const char *HFC_TE_LAYER1_STATES[HFC_MAX_TE_LAYER1_STATE + 1] = {
- "TE F0 - Reset",
- "TE F1 - Reset",
- "TE F2 - Sensing",
- "TE F3 - Deactivated",
- "TE F4 - Awaiting signal",
- "TE F5 - Identifying input",
- "TE F6 - Synchronized",
- "TE F7 - Activated",
- "TE F8 - Lost framing",
-};
-
-static const char *HFC_NT_LAYER1_STATES[HFC_MAX_NT_LAYER1_STATE + 1] = {
- "NT G0 - Reset",
- "NT G1 - Deactive",
- "NT G2 - Pending activation",
- "NT G3 - Active",
- "NT G4 - Pending deactivation",
-};
-
-/* supported devices */
-static const struct usb_device_id hfcsusb_idtab[] = {
- {
- USB_DEVICE(0x0959, 0x2bd0),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_OFF, {4, 0, 2, 1},
- "ISDN USB TA (Cologne Chip HFC-S USB based)"}),
- },
- {
- USB_DEVICE(0x0675, 0x1688),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {1, 2, 0, 0},
- "DrayTek miniVigor 128 USB ISDN TA"}),
- },
- {
- USB_DEVICE(0x07b0, 0x0007),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {0x80, -64, -32, -16},
- "Billion tiny USB ISDN TA 128"}),
- },
- {
- USB_DEVICE(0x0742, 0x2008),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {4, 0, 2, 1},
- "Stollmann USB TA"}),
- },
- {
- USB_DEVICE(0x0742, 0x2009),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {4, 0, 2, 1},
- "Aceex USB ISDN TA"}),
- },
- {
- USB_DEVICE(0x0742, 0x200A),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {4, 0, 2, 1},
- "OEM USB ISDN TA"}),
- },
- {
- USB_DEVICE(0x08e3, 0x0301),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {2, 0, 1, 4},
- "Olitec USB RNIS"}),
- },
- {
- USB_DEVICE(0x07fa, 0x0846),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {0x80, -64, -32, -16},
- "Bewan Modem RNIS USB"}),
- },
- {
- USB_DEVICE(0x07fa, 0x0847),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {0x80, -64, -32, -16},
- "Djinn Numeris USB"}),
- },
- {
- USB_DEVICE(0x07b0, 0x0006),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {0x80, -64, -32, -16},
- "Twister ISDN TA"}),
- },
- {
- USB_DEVICE(0x071d, 0x1005),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {0x02, 0, 0x01, 0x04},
- "Eicon DIVA USB 4.0"}),
- },
- {
- USB_DEVICE(0x0586, 0x0102),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {0x88, -64, -32, -16},
- "ZyXEL OMNI.NET USB II"}),
- },
- {
- USB_DEVICE(0x1ae7, 0x0525),
- .driver_info = (unsigned long) &((struct hfcsusb_vdata)
- {LED_SCHEME1, {0x88, -64, -32, -16},
- "X-Tensions USB ISDN TA XC-525"}),
- },
- { }
-};
-
-MODULE_DEVICE_TABLE(usb, hfcsusb_idtab);
-
-#endif /* __HFCSUSB_H__ */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * iohelper.h
- * helper for define functions to access ISDN hardware
- * supported are memory mapped IO
- * indirect port IO (one port for address, one for data)
- *
- * Author Karsten Keil <keil@isdn4linux.de>
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-
-#ifndef _IOHELPER_H
-#define _IOHELPER_H
-
-typedef u8 (read_reg_func)(void *hwp, u8 offset);
-typedef void (write_reg_func)(void *hwp, u8 offset, u8 value);
-typedef void (fifo_func)(void *hwp, u8 offset, u8 *datap, int size);
-
-struct _ioport {
- u32 port;
- u32 ale;
-};
-
-#define IOFUNC_IO(name, hws, ap) \
- static u8 Read##name##_IO(void *p, u8 off) { \
- struct hws *hw = p; \
- return inb(hw->ap.port + off); \
- } \
- static void Write##name##_IO(void *p, u8 off, u8 val) { \
- struct hws *hw = p; \
- outb(val, hw->ap.port + off); \
- } \
- static void ReadFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) { \
- struct hws *hw = p; \
- insb(hw->ap.port + off, dp, size); \
- } \
- static void WriteFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) { \
- struct hws *hw = p; \
- outsb(hw->ap.port + off, dp, size); \
- }
-
-#define IOFUNC_IND(name, hws, ap) \
- static u8 Read##name##_IND(void *p, u8 off) { \
- struct hws *hw = p; \
- outb(off, hw->ap.ale); \
- return inb(hw->ap.port); \
- } \
- static void Write##name##_IND(void *p, u8 off, u8 val) { \
- struct hws *hw = p; \
- outb(off, hw->ap.ale); \
- outb(val, hw->ap.port); \
- } \
- static void ReadFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) { \
- struct hws *hw = p; \
- outb(off, hw->ap.ale); \
- insb(hw->ap.port, dp, size); \
- } \
- static void WriteFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) { \
- struct hws *hw = p; \
- outb(off, hw->ap.ale); \
- outsb(hw->ap.port, dp, size); \
- }
-
-#define IOFUNC_MEMIO(name, hws, typ, adr) \
- static u8 Read##name##_MIO(void *p, u8 off) { \
- struct hws *hw = p; \
- return readb(((typ *)hw->adr) + off); \
- } \
- static void Write##name##_MIO(void *p, u8 off, u8 val) { \
- struct hws *hw = p; \
- writeb(val, ((typ *)hw->adr) + off); \
- } \
- static void ReadFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) { \
- struct hws *hw = p; \
- while (size--) \
- *dp++ = readb(((typ *)hw->adr) + off); \
- } \
- static void WriteFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) { \
- struct hws *hw = p; \
- while (size--) \
- writeb(*dp++, ((typ *)hw->adr) + off); \
- }
-
-#define ASSIGN_FUNC(typ, name, dest) do { \
- dest.read_reg = &Read##name##_##typ; \
- dest.write_reg = &Write##name##_##typ; \
- dest.read_fifo = &ReadFiFo##name##_##typ; \
- dest.write_fifo = &WriteFiFo##name##_##typ; \
- } while (0)
-#define ASSIGN_FUNC_IPAC(typ, target) do { \
- ASSIGN_FUNC(typ, ISAC, target.isac); \
- ASSIGN_FUNC(typ, IPAC, target); \
- } while (0)
-
-#endif
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- *
- * ipac.h Defines for the Infineon (former Siemens) ISDN
- * chip series
- *
- * Author Karsten Keil <keil@isdn4linux.de>
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-
-#include "iohelper.h"
-
-struct isac_hw {
- struct dchannel dch;
- u32 type;
- u32 off; /* offset to isac regs */
- char *name;
- spinlock_t *hwlock; /* lock HW access */
- read_reg_func *read_reg;
- write_reg_func *write_reg;
- fifo_func *read_fifo;
- fifo_func *write_fifo;
- int (*monitor)(void *, u32, u8 *, int);
- void (*release)(struct isac_hw *);
- int (*init)(struct isac_hw *);
- int (*ctrl)(struct isac_hw *, u32, u_long);
- int (*open)(struct isac_hw *, struct channel_req *);
- u8 *mon_tx;
- u8 *mon_rx;
- int mon_txp;
- int mon_txc;
- int mon_rxp;
- struct arcofi_msg *arcofi_list;
- struct timer_list arcofitimer;
- wait_queue_head_t arcofi_wait;
- u8 arcofi_bc;
- u8 arcofi_state;
- u8 mocr;
- u8 adf2;
- u8 state;
-};
-
-struct ipac_hw;
-
-struct hscx_hw {
- struct bchannel bch;
- struct ipac_hw *ip;
- u8 fifo_size;
- u8 off; /* offset to ICA or ICB */
- u8 slot;
- char log[64];
-};
-
-struct ipac_hw {
- struct isac_hw isac;
- struct hscx_hw hscx[2];
- char *name;
- void *hw;
- spinlock_t *hwlock; /* lock HW access */
- struct module *owner;
- u32 type;
- read_reg_func *read_reg;
- write_reg_func *write_reg;
- fifo_func *read_fifo;
- fifo_func *write_fifo;
- void (*release)(struct ipac_hw *);
- int (*init)(struct ipac_hw *);
- int (*ctrl)(struct ipac_hw *, u32, u_long);
- u8 conf;
-};
-
-#define IPAC_TYPE_ISAC 0x0010
-#define IPAC_TYPE_IPAC 0x0020
-#define IPAC_TYPE_ISACX 0x0040
-#define IPAC_TYPE_IPACX 0x0080
-#define IPAC_TYPE_HSCX 0x0100
-
-#define ISAC_USE_ARCOFI 0x1000
-
-/* Monitor functions */
-#define MONITOR_RX_0 0x1000
-#define MONITOR_RX_1 0x1001
-#define MONITOR_TX_0 0x2000
-#define MONITOR_TX_1 0x2001
-
-/* All registers original Siemens Spec */
-/* IPAC/ISAC registers */
-#define ISAC_ISTA 0x20
-#define ISAC_MASK 0x20
-#define ISAC_CMDR 0x21
-#define ISAC_STAR 0x21
-#define ISAC_MODE 0x22
-#define ISAC_TIMR 0x23
-#define ISAC_EXIR 0x24
-#define ISAC_RBCL 0x25
-#define ISAC_RSTA 0x27
-#define ISAC_RBCH 0x2A
-#define ISAC_SPCR 0x30
-#define ISAC_CIR0 0x31
-#define ISAC_CIX0 0x31
-#define ISAC_MOR0 0x32
-#define ISAC_MOX0 0x32
-#define ISAC_CIR1 0x33
-#define ISAC_CIX1 0x33
-#define ISAC_MOR1 0x34
-#define ISAC_MOX1 0x34
-#define ISAC_STCR 0x37
-#define ISAC_ADF1 0x38
-#define ISAC_ADF2 0x39
-#define ISAC_MOCR 0x3a
-#define ISAC_MOSR 0x3a
-#define ISAC_SQRR 0x3b
-#define ISAC_SQXR 0x3b
-
-#define ISAC_RBCH_XAC 0x80
-
-#define IPAC_D_TIN2 0x01
-
-/* IPAC/HSCX */
-#define IPAC_ISTAB 0x20 /* RD */
-#define IPAC_MASKB 0x20 /* WR */
-#define IPAC_STARB 0x21 /* RD */
-#define IPAC_CMDRB 0x21 /* WR */
-#define IPAC_MODEB 0x22 /* R/W */
-#define IPAC_EXIRB 0x24 /* RD */
-#define IPAC_RBCLB 0x25 /* RD */
-#define IPAC_RAH1 0x26 /* WR */
-#define IPAC_RAH2 0x27 /* WR */
-#define IPAC_RSTAB 0x27 /* RD */
-#define IPAC_RAL1 0x28 /* R/W */
-#define IPAC_RAL2 0x29 /* WR */
-#define IPAC_RHCRB 0x29 /* RD */
-#define IPAC_XBCL 0x2A /* WR */
-#define IPAC_CCR2 0x2C /* R/W */
-#define IPAC_RBCHB 0x2D /* RD */
-#define IPAC_XBCH 0x2D /* WR */
-#define HSCX_VSTR 0x2E /* RD */
-#define IPAC_RLCR 0x2E /* WR */
-#define IPAC_CCR1 0x2F /* R/W */
-#define IPAC_TSAX 0x30 /* WR */
-#define IPAC_TSAR 0x31 /* WR */
-#define IPAC_XCCR 0x32 /* WR */
-#define IPAC_RCCR 0x33 /* WR */
-
-/* IPAC_ISTAB/IPAC_MASKB bits */
-#define IPAC_B_XPR 0x10
-#define IPAC_B_RPF 0x40
-#define IPAC_B_RME 0x80
-#define IPAC_B_ON 0x2F
-
-/* IPAC_EXIRB bits */
-#define IPAC_B_RFS 0x04
-#define IPAC_B_RFO 0x10
-#define IPAC_B_XDU 0x40
-#define IPAC_B_XMR 0x80
-
-/* IPAC special registers */
-#define IPAC_CONF 0xC0 /* R/W */
-#define IPAC_ISTA 0xC1 /* RD */
-#define IPAC_MASK 0xC1 /* WR */
-#define IPAC_ID 0xC2 /* RD */
-#define IPAC_ACFG 0xC3 /* R/W */
-#define IPAC_AOE 0xC4 /* R/W */
-#define IPAC_ARX 0xC5 /* RD */
-#define IPAC_ATX 0xC5 /* WR */
-#define IPAC_PITA1 0xC6 /* R/W */
-#define IPAC_PITA2 0xC7 /* R/W */
-#define IPAC_POTA1 0xC8 /* R/W */
-#define IPAC_POTA2 0xC9 /* R/W */
-#define IPAC_PCFG 0xCA /* R/W */
-#define IPAC_SCFG 0xCB /* R/W */
-#define IPAC_TIMR2 0xCC /* R/W */
-
-/* IPAC_ISTA/_MASK bits */
-#define IPAC__EXB 0x01
-#define IPAC__ICB 0x02
-#define IPAC__EXA 0x04
-#define IPAC__ICA 0x08
-#define IPAC__EXD 0x10
-#define IPAC__ICD 0x20
-#define IPAC__INT0 0x40
-#define IPAC__INT1 0x80
-#define IPAC__ON 0xC0
-
-/* HSCX ISTA/MASK bits */
-#define HSCX__EXB 0x01
-#define HSCX__EXA 0x02
-#define HSCX__ICA 0x04
-
-/* ISAC/ISACX/IPAC/IPACX L1 commands */
-#define ISAC_CMD_TIM 0x0
-#define ISAC_CMD_RS 0x1
-#define ISAC_CMD_SCZ 0x4
-#define ISAC_CMD_SSZ 0x2
-#define ISAC_CMD_AR8 0x8
-#define ISAC_CMD_AR10 0x9
-#define ISAC_CMD_ARL 0xA
-#define ISAC_CMD_DUI 0xF
-
-/* ISAC/ISACX/IPAC/IPACX L1 indications */
-#define ISAC_IND_DR 0x0
-#define ISAC_IND_RS 0x1
-#define ISAC_IND_SD 0x2
-#define ISAC_IND_DIS 0x3
-#define ISAC_IND_RSY 0x4
-#define ISAC_IND_DR6 0x5
-#define ISAC_IND_EI 0x6
-#define ISAC_IND_PU 0x7
-#define ISAC_IND_ARD 0x8
-#define ISAC_IND_TI 0xA
-#define ISAC_IND_ATI 0xB
-#define ISAC_IND_AI8 0xC
-#define ISAC_IND_AI10 0xD
-#define ISAC_IND_DID 0xF
-
-/* the new ISACX / IPACX */
-/* D-channel registers */
-#define ISACX_RFIFOD 0x00 /* RD */
-#define ISACX_XFIFOD 0x00 /* WR */
-#define ISACX_ISTAD 0x20 /* RD */
-#define ISACX_MASKD 0x20 /* WR */
-#define ISACX_STARD 0x21 /* RD */
-#define ISACX_CMDRD 0x21 /* WR */
-#define ISACX_MODED 0x22 /* R/W */
-#define ISACX_EXMD1 0x23 /* R/W */
-#define ISACX_TIMR1 0x24 /* R/W */
-#define ISACX_SAP1 0x25 /* WR */
-#define ISACX_SAP2 0x26 /* WR */
-#define ISACX_RBCLD 0x26 /* RD */
-#define ISACX_RBCHD 0x27 /* RD */
-#define ISACX_TEI1 0x27 /* WR */
-#define ISACX_TEI2 0x28 /* WR */
-#define ISACX_RSTAD 0x28 /* RD */
-#define ISACX_TMD 0x29 /* R/W */
-#define ISACX_CIR0 0x2E /* RD */
-#define ISACX_CIX0 0x2E /* WR */
-#define ISACX_CIR1 0x2F /* RD */
-#define ISACX_CIX1 0x2F /* WR */
-
-/* Transceiver registers */
-#define ISACX_TR_CONF0 0x30 /* R/W */
-#define ISACX_TR_CONF1 0x31 /* R/W */
-#define ISACX_TR_CONF2 0x32 /* R/W */
-#define ISACX_TR_STA 0x33 /* RD */
-#define ISACX_TR_CMD 0x34 /* R/W */
-#define ISACX_SQRR1 0x35 /* RD */
-#define ISACX_SQXR1 0x35 /* WR */
-#define ISACX_SQRR2 0x36 /* RD */
-#define ISACX_SQXR2 0x36 /* WR */
-#define ISACX_SQRR3 0x37 /* RD */
-#define ISACX_SQXR3 0x37 /* WR */
-#define ISACX_ISTATR 0x38 /* RD */
-#define ISACX_MASKTR 0x39 /* R/W */
-#define ISACX_TR_MODE 0x3A /* R/W */
-#define ISACX_ACFG1 0x3C /* R/W */
-#define ISACX_ACFG2 0x3D /* R/W */
-#define ISACX_AOE 0x3E /* R/W */
-#define ISACX_ARX 0x3F /* RD */
-#define ISACX_ATX 0x3F /* WR */
-
-/* IOM: Timeslot, DPS, CDA */
-#define ISACX_CDA10 0x40 /* R/W */
-#define ISACX_CDA11 0x41 /* R/W */
-#define ISACX_CDA20 0x42 /* R/W */
-#define ISACX_CDA21 0x43 /* R/W */
-#define ISACX_CDA_TSDP10 0x44 /* R/W */
-#define ISACX_CDA_TSDP11 0x45 /* R/W */
-#define ISACX_CDA_TSDP20 0x46 /* R/W */
-#define ISACX_CDA_TSDP21 0x47 /* R/W */
-#define ISACX_BCHA_TSDP_BC1 0x48 /* R/W */
-#define ISACX_BCHA_TSDP_BC2 0x49 /* R/W */
-#define ISACX_BCHB_TSDP_BC1 0x4A /* R/W */
-#define ISACX_BCHB_TSDP_BC2 0x4B /* R/W */
-#define ISACX_TR_TSDP_BC1 0x4C /* R/W */
-#define ISACX_TR_TSDP_BC2 0x4D /* R/W */
-#define ISACX_CDA1_CR 0x4E /* R/W */
-#define ISACX_CDA2_CR 0x4F /* R/W */
-
-/* IOM: Contol, Sync transfer, Monitor */
-#define ISACX_TR_CR 0x50 /* R/W */
-#define ISACX_TRC_CR 0x50 /* R/W */
-#define ISACX_BCHA_CR 0x51 /* R/W */
-#define ISACX_BCHB_CR 0x52 /* R/W */
-#define ISACX_DCI_CR 0x53 /* R/W */
-#define ISACX_DCIC_CR 0x53 /* R/W */
-#define ISACX_MON_CR 0x54 /* R/W */
-#define ISACX_SDS1_CR 0x55 /* R/W */
-#define ISACX_SDS2_CR 0x56 /* R/W */
-#define ISACX_IOM_CR 0x57 /* R/W */
-#define ISACX_STI 0x58 /* RD */
-#define ISACX_ASTI 0x58 /* WR */
-#define ISACX_MSTI 0x59 /* R/W */
-#define ISACX_SDS_CONF 0x5A /* R/W */
-#define ISACX_MCDA 0x5B /* RD */
-#define ISACX_MOR 0x5C /* RD */
-#define ISACX_MOX 0x5C /* WR */
-#define ISACX_MOSR 0x5D /* RD */
-#define ISACX_MOCR 0x5E /* R/W */
-#define ISACX_MSTA 0x5F /* RD */
-#define ISACX_MCONF 0x5F /* WR */
-
-/* Interrupt and general registers */
-#define ISACX_ISTA 0x60 /* RD */
-#define ISACX_MASK 0x60 /* WR */
-#define ISACX_AUXI 0x61 /* RD */
-#define ISACX_AUXM 0x61 /* WR */
-#define ISACX_MODE1 0x62 /* R/W */
-#define ISACX_MODE2 0x63 /* R/W */
-#define ISACX_ID 0x64 /* RD */
-#define ISACX_SRES 0x64 /* WR */
-#define ISACX_TIMR2 0x65 /* R/W */
-
-/* Register Bits */
-/* ISACX/IPACX _ISTAD (R) and _MASKD (W) */
-#define ISACX_D_XDU 0x04
-#define ISACX_D_XMR 0x08
-#define ISACX_D_XPR 0x10
-#define ISACX_D_RFO 0x20
-#define ISACX_D_RPF 0x40
-#define ISACX_D_RME 0x80
-
-/* ISACX/IPACX _ISTA (R) and _MASK (W) */
-#define ISACX__ICD 0x01
-#define ISACX__MOS 0x02
-#define ISACX__TRAN 0x04
-#define ISACX__AUX 0x08
-#define ISACX__CIC 0x10
-#define ISACX__ST 0x20
-#define IPACX__ON 0x2C
-#define IPACX__ICB 0x40
-#define IPACX__ICA 0x80
-
-/* ISACX/IPACX _CMDRD (W) */
-#define ISACX_CMDRD_XRES 0x01
-#define ISACX_CMDRD_XME 0x02
-#define ISACX_CMDRD_XTF 0x08
-#define ISACX_CMDRD_STI 0x10
-#define ISACX_CMDRD_RRES 0x40
-#define ISACX_CMDRD_RMC 0x80
-
-/* ISACX/IPACX _RSTAD (R) */
-#define ISACX_RSTAD_TA 0x01
-#define ISACX_RSTAD_CR 0x02
-#define ISACX_RSTAD_SA0 0x04
-#define ISACX_RSTAD_SA1 0x08
-#define ISACX_RSTAD_RAB 0x10
-#define ISACX_RSTAD_CRC 0x20
-#define ISACX_RSTAD_RDO 0x40
-#define ISACX_RSTAD_VFR 0x80
-
-/* ISACX/IPACX _CIR0 (R) */
-#define ISACX_CIR0_BAS 0x01
-#define ISACX_CIR0_SG 0x08
-#define ISACX_CIR0_CIC1 0x08
-#define ISACX_CIR0_CIC0 0x08
-
-/* B-channel registers */
-#define IPACX_OFF_ICA 0x70
-#define IPACX_OFF_ICB 0x80
-
-/* ICA: IPACX_OFF_ICA + Reg ICB: IPACX_OFF_ICB + Reg */
-
-#define IPACX_ISTAB 0x00 /* RD */
-#define IPACX_MASKB 0x00 /* WR */
-#define IPACX_STARB 0x01 /* RD */
-#define IPACX_CMDRB 0x01 /* WR */
-#define IPACX_MODEB 0x02 /* R/W */
-#define IPACX_EXMB 0x03 /* R/W */
-#define IPACX_RAH1 0x05 /* WR */
-#define IPACX_RAH2 0x06 /* WR */
-#define IPACX_RBCLB 0x06 /* RD */
-#define IPACX_RBCHB 0x07 /* RD */
-#define IPACX_RAL1 0x07 /* WR */
-#define IPACX_RAL2 0x08 /* WR */
-#define IPACX_RSTAB 0x08 /* RD */
-#define IPACX_TMB 0x09 /* R/W */
-#define IPACX_RFIFOB 0x0A /* RD */
-#define IPACX_XFIFOB 0x0A /* WR */
-
-/* IPACX_ISTAB / IPACX_MASKB bits */
-#define IPACX_B_XDU 0x04
-#define IPACX_B_XPR 0x10
-#define IPACX_B_RFO 0x20
-#define IPACX_B_RPF 0x40
-#define IPACX_B_RME 0x80
-
-#define IPACX_B_ON 0x0B
-
-extern int mISDNisac_init(struct isac_hw *, void *);
-extern irqreturn_t mISDNisac_irq(struct isac_hw *, u8);
-extern u32 mISDNipac_init(struct ipac_hw *, void *);
-extern irqreturn_t mISDNipac_irq(struct ipac_hw *, int);
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- *
- * isar.h ISAR (Siemens PSB 7110) specific defines
- *
- * Author Karsten Keil (keil@isdn4linux.de)
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-
-#include "iohelper.h"
-
-struct isar_hw;
-
-struct isar_ch {
- struct bchannel bch;
- struct isar_hw *is;
- struct timer_list ftimer;
- u8 nr;
- u8 dpath;
- u8 mml;
- u8 state;
- u8 cmd;
- u8 mod;
- u8 newcmd;
- u8 newmod;
- u8 try_mod;
- u8 conmsg[16];
-};
-
-struct isar_hw {
- struct isar_ch ch[2];
- void *hw;
- spinlock_t *hwlock; /* lock HW access */
- char *name;
- struct module *owner;
- read_reg_func *read_reg;
- write_reg_func *write_reg;
- fifo_func *read_fifo;
- fifo_func *write_fifo;
- int (*ctrl)(void *, u32, u_long);
- void (*release)(struct isar_hw *);
- int (*init)(struct isar_hw *);
- int (*open)(struct isar_hw *, struct channel_req *);
- int (*firmware)(struct isar_hw *, const u8 *, int);
- unsigned long Flags;
- int version;
- u8 bstat;
- u8 iis;
- u8 cmsb;
- u8 clsb;
- u8 buf[256];
- u8 log[256];
-};
-
-#define ISAR_IRQMSK 0x04
-#define ISAR_IRQSTA 0x04
-#define ISAR_IRQBIT 0x75
-#define ISAR_CTRL_H 0x61
-#define ISAR_CTRL_L 0x60
-#define ISAR_IIS 0x58
-#define ISAR_IIA 0x58
-#define ISAR_HIS 0x50
-#define ISAR_HIA 0x50
-#define ISAR_MBOX 0x4c
-#define ISAR_WADR 0x4a
-#define ISAR_RADR 0x48
-
-#define ISAR_HIS_VNR 0x14
-#define ISAR_HIS_DKEY 0x02
-#define ISAR_HIS_FIRM 0x1e
-#define ISAR_HIS_STDSP 0x08
-#define ISAR_HIS_DIAG 0x05
-#define ISAR_HIS_P0CFG 0x3c
-#define ISAR_HIS_P12CFG 0x24
-#define ISAR_HIS_SARTCFG 0x25
-#define ISAR_HIS_PUMPCFG 0x26
-#define ISAR_HIS_PUMPCTRL 0x2a
-#define ISAR_HIS_IOM2CFG 0x27
-#define ISAR_HIS_IOM2REQ 0x07
-#define ISAR_HIS_IOM2CTRL 0x2b
-#define ISAR_HIS_BSTREQ 0x0c
-#define ISAR_HIS_PSTREQ 0x0e
-#define ISAR_HIS_SDATA 0x20
-#define ISAR_HIS_DPS1 0x40
-#define ISAR_HIS_DPS2 0x80
-#define SET_DPS(x) ((x << 6) & 0xc0)
-
-#define ISAR_IIS_MSCMSD 0x3f
-#define ISAR_IIS_VNR 0x15
-#define ISAR_IIS_DKEY 0x03
-#define ISAR_IIS_FIRM 0x1f
-#define ISAR_IIS_STDSP 0x09
-#define ISAR_IIS_DIAG 0x25
-#define ISAR_IIS_GSTEV 0x00
-#define ISAR_IIS_BSTEV 0x28
-#define ISAR_IIS_BSTRSP 0x2c
-#define ISAR_IIS_PSTRSP 0x2e
-#define ISAR_IIS_PSTEV 0x2a
-#define ISAR_IIS_IOM2RSP 0x27
-#define ISAR_IIS_RDATA 0x20
-#define ISAR_IIS_INVMSG 0x3f
-
-#define ISAR_CTRL_SWVER 0x10
-#define ISAR_CTRL_STST 0x40
-
-#define ISAR_MSG_HWVER 0x20
-
-#define ISAR_DP1_USE 1
-#define ISAR_DP2_USE 2
-#define ISAR_RATE_REQ 3
-
-#define PMOD_DISABLE 0
-#define PMOD_FAX 1
-#define PMOD_DATAMODEM 2
-#define PMOD_HALFDUPLEX 3
-#define PMOD_V110 4
-#define PMOD_DTMF 5
-#define PMOD_DTMF_TRANS 6
-#define PMOD_BYPASS 7
-
-#define PCTRL_ORIG 0x80
-#define PV32P2_V23R 0x40
-#define PV32P2_V22A 0x20
-#define PV32P2_V22B 0x10
-#define PV32P2_V22C 0x08
-#define PV32P2_V21 0x02
-#define PV32P2_BEL 0x01
-
-/* LSB MSB in ISAR doc wrong !!! Arghhh */
-#define PV32P3_AMOD 0x80
-#define PV32P3_V32B 0x02
-#define PV32P3_V23B 0x01
-#define PV32P4_48 0x11
-#define PV32P5_48 0x05
-#define PV32P4_UT48 0x11
-#define PV32P5_UT48 0x0d
-#define PV32P4_96 0x11
-#define PV32P5_96 0x03
-#define PV32P4_UT96 0x11
-#define PV32P5_UT96 0x0f
-#define PV32P4_B96 0x91
-#define PV32P5_B96 0x0b
-#define PV32P4_UTB96 0xd1
-#define PV32P5_UTB96 0x0f
-#define PV32P4_120 0xb1
-#define PV32P5_120 0x09
-#define PV32P4_UT120 0xf1
-#define PV32P5_UT120 0x0f
-#define PV32P4_144 0x99
-#define PV32P5_144 0x09
-#define PV32P4_UT144 0xf9
-#define PV32P5_UT144 0x0f
-#define PV32P6_CTN 0x01
-#define PV32P6_ATN 0x02
-
-#define PFAXP2_CTN 0x01
-#define PFAXP2_ATN 0x04
-
-#define PSEV_10MS_TIMER 0x02
-#define PSEV_CON_ON 0x18
-#define PSEV_CON_OFF 0x19
-#define PSEV_V24_OFF 0x20
-#define PSEV_CTS_ON 0x21
-#define PSEV_CTS_OFF 0x22
-#define PSEV_DCD_ON 0x23
-#define PSEV_DCD_OFF 0x24
-#define PSEV_DSR_ON 0x25
-#define PSEV_DSR_OFF 0x26
-#define PSEV_REM_RET 0xcc
-#define PSEV_REM_REN 0xcd
-#define PSEV_GSTN_CLR 0xd4
-
-#define PSEV_RSP_READY 0xbc
-#define PSEV_LINE_TX_H 0xb3
-#define PSEV_LINE_TX_B 0xb2
-#define PSEV_LINE_RX_H 0xb1
-#define PSEV_LINE_RX_B 0xb0
-#define PSEV_RSP_CONN 0xb5
-#define PSEV_RSP_DISC 0xb7
-#define PSEV_RSP_FCERR 0xb9
-#define PSEV_RSP_SILDET 0xbe
-#define PSEV_RSP_SILOFF 0xab
-#define PSEV_FLAGS_DET 0xba
-
-#define PCTRL_CMD_TDTMF 0x5a
-
-#define PCTRL_CMD_FTH 0xa7
-#define PCTRL_CMD_FRH 0xa5
-#define PCTRL_CMD_FTM 0xa8
-#define PCTRL_CMD_FRM 0xa6
-#define PCTRL_CMD_SILON 0xac
-#define PCTRL_CMD_CONT 0xa2
-#define PCTRL_CMD_ESC 0xa4
-#define PCTRL_CMD_SILOFF 0xab
-#define PCTRL_CMD_HALT 0xa9
-
-#define PCTRL_LOC_RET 0xcf
-#define PCTRL_LOC_REN 0xce
-
-#define SMODE_DISABLE 0
-#define SMODE_V14 2
-#define SMODE_HDLC 3
-#define SMODE_BINARY 4
-#define SMODE_FSK_V14 5
-
-#define SCTRL_HDMC_BOTH 0x00
-#define SCTRL_HDMC_DTX 0x80
-#define SCTRL_HDMC_DRX 0x40
-#define S_P1_OVSP 0x40
-#define S_P1_SNP 0x20
-#define S_P1_EOP 0x10
-#define S_P1_EDP 0x08
-#define S_P1_NSB 0x04
-#define S_P1_CHS_8 0x03
-#define S_P1_CHS_7 0x02
-#define S_P1_CHS_6 0x01
-#define S_P1_CHS_5 0x00
-
-#define S_P2_BFT_DEF 0x10
-
-#define IOM_CTRL_ENA 0x80
-#define IOM_CTRL_NOPCM 0x00
-#define IOM_CTRL_ALAW 0x02
-#define IOM_CTRL_ULAW 0x04
-#define IOM_CTRL_RCV 0x01
-
-#define IOM_P1_TXD 0x10
-
-#define HDLC_FED 0x40
-#define HDLC_FSD 0x20
-#define HDLC_FST 0x20
-#define HDLC_ERROR 0x1c
-#define HDLC_ERR_FAD 0x10
-#define HDLC_ERR_RER 0x08
-#define HDLC_ERR_CER 0x04
-#define SART_NMD 0x01
-
-#define BSTAT_RDM0 0x1
-#define BSTAT_RDM1 0x2
-#define BSTAT_RDM2 0x4
-#define BSTAT_RDM3 0x8
-#define BSTEV_TBO 0x1f
-#define BSTEV_RBO 0x2f
-
-/* FAX State Machine */
-#define STFAX_NULL 0
-#define STFAX_READY 1
-#define STFAX_LINE 2
-#define STFAX_CONT 3
-#define STFAX_ACTIV 4
-#define STFAX_ESCAPE 5
-#define STFAX_SILDET 6
-
-extern u32 mISDNisar_init(struct isar_hw *, void *);
-extern void mISDNisar_irq(struct isar_hw *);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * isdnhdlc.c -- General purpose ISDN HDLC decoder.
- *
- * Copyright (C)
- * 2009 Karsten Keil <keil@b1-systems.de>
- * 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
- * 2001 Frode Isaksen <fisaksen@bewan.com>
- * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/crc-ccitt.h>
-#include <linux/bitrev.h>
-#include "isdnhdlc.h"
-
-/*-------------------------------------------------------------------*/
-
-MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
- "Frode Isaksen <fisaksen@bewan.com>, "
- "Kai Germaschewski <kai.germaschewski@gmx.de>");
-MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
-MODULE_LICENSE("GPL");
-
-/*-------------------------------------------------------------------*/
-
-enum {
- HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7,
- HDLC_GET_DATA, HDLC_FAST_FLAG
-};
-
-enum {
- HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG,
- HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG,
- HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0,
- HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE
-};
-
-void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features)
-{
- memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
- hdlc->state = HDLC_GET_DATA;
- if (features & HDLC_56KBIT)
- hdlc->do_adapt56 = 1;
- if (features & HDLC_BITREVERSE)
- hdlc->do_bitreverse = 1;
-}
-EXPORT_SYMBOL(isdnhdlc_out_init);
-
-void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features)
-{
- memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
- if (features & HDLC_DCHANNEL) {
- hdlc->dchannel = 1;
- hdlc->state = HDLC_SEND_FIRST_FLAG;
- } else {
- hdlc->dchannel = 0;
- hdlc->state = HDLC_SEND_FAST_FLAG;
- hdlc->ffvalue = 0x7e;
- }
- hdlc->cbin = 0x7e;
- if (features & HDLC_56KBIT) {
- hdlc->do_adapt56 = 1;
- hdlc->state = HDLC_SENDFLAG_B0;
- } else
- hdlc->data_bits = 8;
- if (features & HDLC_BITREVERSE)
- hdlc->do_bitreverse = 1;
-}
-EXPORT_SYMBOL(isdnhdlc_rcv_init);
-
-static int
-check_frame(struct isdnhdlc_vars *hdlc)
-{
- int status;
-
- if (hdlc->dstpos < 2) /* too small - framing error */
- status = -HDLC_FRAMING_ERROR;
- else if (hdlc->crc != 0xf0b8) /* crc error */
- status = -HDLC_CRC_ERROR;
- else {
- /* remove CRC */
- hdlc->dstpos -= 2;
- /* good frame */
- status = hdlc->dstpos;
- }
- return status;
-}
-
-/*
- isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
-
- The source buffer is scanned for valid HDLC frames looking for
- flags (01111110) to indicate the start of a frame. If the start of
- the frame is found, the bit stuffing is removed (0 after 5 1's).
- When a new flag is found, the complete frame has been received
- and the CRC is checked.
- If a valid frame is found, the function returns the frame length
- excluding the CRC with the bit HDLC_END_OF_FRAME set.
- If the beginning of a valid frame is found, the function returns
- the length.
- If a framing error is found (too many 1s and not a flag) the function
- returns the length with the bit HDLC_FRAMING_ERROR set.
- If a CRC error is found the function returns the length with the
- bit HDLC_CRC_ERROR set.
- If the frame length exceeds the destination buffer size, the function
- returns the length with the bit HDLC_LENGTH_ERROR set.
-
- src - source buffer
- slen - source buffer length
- count - number of bytes removed (decoded) from the source buffer
- dst _ destination buffer
- dsize - destination buffer size
- returns - number of decoded bytes in the destination buffer and status
- flag.
-*/
-int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen,
- int *count, u8 *dst, int dsize)
-{
- int status = 0;
-
- static const unsigned char fast_flag[] = {
- 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f
- };
-
- static const unsigned char fast_flag_value[] = {
- 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f
- };
-
- static const unsigned char fast_abort[] = {
- 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
- };
-
-#define handle_fast_flag(h) \
- do { \
- if (h->cbin == fast_flag[h->bit_shift]) { \
- h->ffvalue = fast_flag_value[h->bit_shift]; \
- h->state = HDLC_FAST_FLAG; \
- h->ffbit_shift = h->bit_shift; \
- h->bit_shift = 1; \
- } else { \
- h->state = HDLC_GET_DATA; \
- h->data_received = 0; \
- } \
- } while (0)
-
-#define handle_abort(h) \
- do { \
- h->shift_reg = fast_abort[h->ffbit_shift - 1]; \
- h->hdlc_bits1 = h->ffbit_shift - 2; \
- if (h->hdlc_bits1 < 0) \
- h->hdlc_bits1 = 0; \
- h->data_bits = h->ffbit_shift - 1; \
- h->state = HDLC_GET_DATA; \
- h->data_received = 0; \
- } while (0)
-
- *count = slen;
-
- while (slen > 0) {
- if (hdlc->bit_shift == 0) {
- /* the code is for bitreverse streams */
- if (hdlc->do_bitreverse == 0)
- hdlc->cbin = bitrev8(*src++);
- else
- hdlc->cbin = *src++;
- slen--;
- hdlc->bit_shift = 8;
- if (hdlc->do_adapt56)
- hdlc->bit_shift--;
- }
-
- switch (hdlc->state) {
- case STOPPED:
- return 0;
- case HDLC_FAST_IDLE:
- if (hdlc->cbin == 0xff) {
- hdlc->bit_shift = 0;
- break;
- }
- hdlc->state = HDLC_GET_FLAG_B0;
- hdlc->hdlc_bits1 = 0;
- hdlc->bit_shift = 8;
- break;
- case HDLC_GET_FLAG_B0:
- if (!(hdlc->cbin & 0x80)) {
- hdlc->state = HDLC_GETFLAG_B1A6;
- hdlc->hdlc_bits1 = 0;
- } else {
- if ((!hdlc->do_adapt56) &&
- (++hdlc->hdlc_bits1 >= 8) &&
- (hdlc->bit_shift == 1))
- hdlc->state = HDLC_FAST_IDLE;
- }
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- break;
- case HDLC_GETFLAG_B1A6:
- if (hdlc->cbin & 0x80) {
- hdlc->hdlc_bits1++;
- if (hdlc->hdlc_bits1 == 6)
- hdlc->state = HDLC_GETFLAG_B7;
- } else
- hdlc->hdlc_bits1 = 0;
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- break;
- case HDLC_GETFLAG_B7:
- if (hdlc->cbin & 0x80) {
- hdlc->state = HDLC_GET_FLAG_B0;
- } else {
- hdlc->state = HDLC_GET_DATA;
- hdlc->crc = 0xffff;
- hdlc->shift_reg = 0;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = 0;
- hdlc->data_received = 0;
- }
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- break;
- case HDLC_GET_DATA:
- if (hdlc->cbin & 0x80) {
- hdlc->hdlc_bits1++;
- switch (hdlc->hdlc_bits1) {
- case 6:
- break;
- case 7:
- if (hdlc->data_received)
- /* bad frame */
- status = -HDLC_FRAMING_ERROR;
- if (!hdlc->do_adapt56) {
- if (hdlc->cbin == fast_abort
- [hdlc->bit_shift + 1]) {
- hdlc->state =
- HDLC_FAST_IDLE;
- hdlc->bit_shift = 1;
- break;
- }
- } else
- hdlc->state = HDLC_GET_FLAG_B0;
- break;
- default:
- hdlc->shift_reg >>= 1;
- hdlc->shift_reg |= 0x80;
- hdlc->data_bits++;
- break;
- }
- } else {
- switch (hdlc->hdlc_bits1) {
- case 5:
- break;
- case 6:
- if (hdlc->data_received)
- status = check_frame(hdlc);
- hdlc->crc = 0xffff;
- hdlc->shift_reg = 0;
- hdlc->data_bits = 0;
- if (!hdlc->do_adapt56)
- handle_fast_flag(hdlc);
- else {
- hdlc->state = HDLC_GET_DATA;
- hdlc->data_received = 0;
- }
- break;
- default:
- hdlc->shift_reg >>= 1;
- hdlc->data_bits++;
- break;
- }
- hdlc->hdlc_bits1 = 0;
- }
- if (status) {
- hdlc->dstpos = 0;
- *count -= slen;
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- return status;
- }
- if (hdlc->data_bits == 8) {
- hdlc->data_bits = 0;
- hdlc->data_received = 1;
- hdlc->crc = crc_ccitt_byte(hdlc->crc,
- hdlc->shift_reg);
-
- /* good byte received */
- if (hdlc->dstpos < dsize)
- dst[hdlc->dstpos++] = hdlc->shift_reg;
- else {
- /* frame too long */
- status = -HDLC_LENGTH_ERROR;
- hdlc->dstpos = 0;
- }
- }
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- break;
- case HDLC_FAST_FLAG:
- if (hdlc->cbin == hdlc->ffvalue) {
- hdlc->bit_shift = 0;
- break;
- } else {
- if (hdlc->cbin == 0xff) {
- hdlc->state = HDLC_FAST_IDLE;
- hdlc->bit_shift = 0;
- } else if (hdlc->ffbit_shift == 8) {
- hdlc->state = HDLC_GETFLAG_B7;
- break;
- } else
- handle_abort(hdlc);
- }
- break;
- default:
- break;
- }
- }
- *count -= slen;
- return 0;
-}
-EXPORT_SYMBOL(isdnhdlc_decode);
-/*
- isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
-
- The bit stream starts with a beginning flag (01111110). After
- that each byte is added to the bit stream with bit stuffing added
- (0 after 5 1's).
- When the last byte has been removed from the source buffer, the
- CRC (2 bytes is added) and the frame terminates with the ending flag.
- For the dchannel, the idle character (all 1's) is also added at the end.
- If this function is called with empty source buffer (slen=0), flags or
- idle character will be generated.
-
- src - source buffer
- slen - source buffer length
- count - number of bytes removed (encoded) from source buffer
- dst _ destination buffer
- dsize - destination buffer size
- returns - number of encoded bytes in the destination buffer
-*/
-int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen,
- int *count, u8 *dst, int dsize)
-{
- static const unsigned char xfast_flag_value[] = {
- 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e
- };
-
- int len = 0;
-
- *count = slen;
-
- /* special handling for one byte frames */
- if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG))
- hdlc->state = HDLC_SENDFLAG_ONE;
- while (dsize > 0) {
- if (hdlc->bit_shift == 0) {
- if (slen && !hdlc->do_closing) {
- hdlc->shift_reg = *src++;
- slen--;
- if (slen == 0)
- /* closing sequence, CRC + flag(s) */
- hdlc->do_closing = 1;
- hdlc->bit_shift = 8;
- } else {
- if (hdlc->state == HDLC_SEND_DATA) {
- if (hdlc->data_received) {
- hdlc->state = HDLC_SEND_CRC1;
- hdlc->crc ^= 0xffff;
- hdlc->bit_shift = 8;
- hdlc->shift_reg =
- hdlc->crc & 0xff;
- } else if (!hdlc->do_adapt56)
- hdlc->state =
- HDLC_SEND_FAST_FLAG;
- else
- hdlc->state =
- HDLC_SENDFLAG_B0;
- }
-
- }
- }
-
- switch (hdlc->state) {
- case STOPPED:
- while (dsize--)
- *dst++ = 0xff;
- return dsize;
- case HDLC_SEND_FAST_FLAG:
- hdlc->do_closing = 0;
- if (slen == 0) {
- /* the code is for bitreverse streams */
- if (hdlc->do_bitreverse == 0)
- *dst++ = bitrev8(hdlc->ffvalue);
- else
- *dst++ = hdlc->ffvalue;
- len++;
- dsize--;
- break;
- }
- fallthrough;
- case HDLC_SENDFLAG_ONE:
- if (hdlc->bit_shift == 8) {
- hdlc->cbin = hdlc->ffvalue >>
- (8 - hdlc->data_bits);
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_received = 1;
- }
- break;
- case HDLC_SENDFLAG_B0:
- hdlc->do_closing = 0;
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- hdlc->hdlc_bits1 = 0;
- hdlc->state = HDLC_SENDFLAG_B1A6;
- break;
- case HDLC_SENDFLAG_B1A6:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- hdlc->cbin++;
- if (++hdlc->hdlc_bits1 == 6)
- hdlc->state = HDLC_SENDFLAG_B7;
- break;
- case HDLC_SENDFLAG_B7:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (slen == 0) {
- hdlc->state = HDLC_SENDFLAG_B0;
- break;
- }
- if (hdlc->bit_shift == 8) {
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_received = 1;
- }
- break;
- case HDLC_SEND_FIRST_FLAG:
- hdlc->data_received = 1;
- if (hdlc->data_bits == 8) {
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- break;
- }
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (hdlc->shift_reg & 0x01)
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- if (hdlc->bit_shift == 0) {
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- }
- break;
- case HDLC_SEND_DATA:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (hdlc->hdlc_bits1 == 5) {
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if (hdlc->bit_shift == 8)
- hdlc->crc = crc_ccitt_byte(hdlc->crc,
- hdlc->shift_reg);
- if (hdlc->shift_reg & 0x01) {
- hdlc->hdlc_bits1++;
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- } else {
- hdlc->hdlc_bits1 = 0;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- }
- break;
- case HDLC_SEND_CRC1:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (hdlc->hdlc_bits1 == 5) {
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if (hdlc->shift_reg & 0x01) {
- hdlc->hdlc_bits1++;
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- } else {
- hdlc->hdlc_bits1 = 0;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- }
- if (hdlc->bit_shift == 0) {
- hdlc->shift_reg = (hdlc->crc >> 8);
- hdlc->state = HDLC_SEND_CRC2;
- hdlc->bit_shift = 8;
- }
- break;
- case HDLC_SEND_CRC2:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (hdlc->hdlc_bits1 == 5) {
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if (hdlc->shift_reg & 0x01) {
- hdlc->hdlc_bits1++;
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- } else {
- hdlc->hdlc_bits1 = 0;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- }
- if (hdlc->bit_shift == 0) {
- hdlc->shift_reg = 0x7e;
- hdlc->state = HDLC_SEND_CLOSING_FLAG;
- hdlc->bit_shift = 8;
- }
- break;
- case HDLC_SEND_CLOSING_FLAG:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (hdlc->hdlc_bits1 == 5) {
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if (hdlc->shift_reg & 0x01)
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- if (hdlc->bit_shift == 0) {
- hdlc->ffvalue =
- xfast_flag_value[hdlc->data_bits];
- if (hdlc->dchannel) {
- hdlc->ffvalue = 0x7e;
- hdlc->state = HDLC_SEND_IDLE1;
- hdlc->bit_shift = 8-hdlc->data_bits;
- if (hdlc->bit_shift == 0)
- hdlc->state =
- HDLC_SEND_FAST_IDLE;
- } else {
- if (!hdlc->do_adapt56) {
- hdlc->state =
- HDLC_SEND_FAST_FLAG;
- hdlc->data_received = 0;
- } else {
- hdlc->state = HDLC_SENDFLAG_B0;
- hdlc->data_received = 0;
- }
- /* Finished this frame, send flags */
- if (dsize > 1)
- dsize = 1;
- }
- }
- break;
- case HDLC_SEND_IDLE1:
- hdlc->do_closing = 0;
- hdlc->cbin <<= 1;
- hdlc->cbin++;
- hdlc->data_bits++;
- hdlc->bit_shift--;
- if (hdlc->bit_shift == 0) {
- hdlc->state = HDLC_SEND_FAST_IDLE;
- hdlc->bit_shift = 0;
- }
- break;
- case HDLC_SEND_FAST_IDLE:
- hdlc->do_closing = 0;
- hdlc->cbin = 0xff;
- hdlc->data_bits = 8;
- if (hdlc->bit_shift == 8) {
- hdlc->cbin = 0x7e;
- hdlc->state = HDLC_SEND_FIRST_FLAG;
- } else {
- /* the code is for bitreverse streams */
- if (hdlc->do_bitreverse == 0)
- *dst++ = bitrev8(hdlc->cbin);
- else
- *dst++ = hdlc->cbin;
- hdlc->bit_shift = 0;
- hdlc->data_bits = 0;
- len++;
- dsize = 0;
- }
- break;
- default:
- break;
- }
- if (hdlc->do_adapt56) {
- if (hdlc->data_bits == 7) {
- hdlc->cbin <<= 1;
- hdlc->cbin++;
- hdlc->data_bits++;
- }
- }
- if (hdlc->data_bits == 8) {
- /* the code is for bitreverse streams */
- if (hdlc->do_bitreverse == 0)
- *dst++ = bitrev8(hdlc->cbin);
- else
- *dst++ = hdlc->cbin;
- hdlc->data_bits = 0;
- len++;
- dsize--;
- }
- }
- *count -= slen;
-
- return len;
-}
-EXPORT_SYMBOL(isdnhdlc_encode);
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * hdlc.h -- General purpose ISDN HDLC decoder.
- *
- * Implementation of a HDLC decoder/encoder in software.
- * Necessary because some ISDN devices don't have HDLC
- * controllers.
- *
- * Copyright (C)
- * 2009 Karsten Keil <keil@b1-systems.de>
- * 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
- * 2001 Frode Isaksen <fisaksen@bewan.com>
- * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
- */
-
-#ifndef __ISDNHDLC_H__
-#define __ISDNHDLC_H__
-
-struct isdnhdlc_vars {
- int bit_shift;
- int hdlc_bits1;
- int data_bits;
- int ffbit_shift; /* encoding only */
- int state;
- int dstpos;
-
- u16 crc;
-
- u8 cbin;
- u8 shift_reg;
- u8 ffvalue;
-
- /* set if transferring data */
- u32 data_received:1;
- /* set if D channel (send idle instead of flags) */
- u32 dchannel:1;
- /* set if 56K adaptation */
- u32 do_adapt56:1;
- /* set if in closing phase (need to send CRC + flag) */
- u32 do_closing:1;
- /* set if data is bitreverse */
- u32 do_bitreverse:1;
-};
-
-/* Feature Flags */
-#define HDLC_56KBIT 0x01
-#define HDLC_DCHANNEL 0x02
-#define HDLC_BITREVERSE 0x04
-
-/*
- The return value from isdnhdlc_decode is
- the frame length, 0 if no complete frame was decoded,
- or a negative error number
-*/
-#define HDLC_FRAMING_ERROR 1
-#define HDLC_CRC_ERROR 2
-#define HDLC_LENGTH_ERROR 3
-
-extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features);
-
-extern int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src,
- int slen, int *count, u8 *dst, int dsize);
-
-extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features);
-
-extern int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src,
- u16 slen, int *count, u8 *dst, int dsize);
-
-#endif /* __ISDNHDLC_H__ */
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * mISDNinfineon.c
- * Support for cards based on following Infineon ISDN chipsets
- * - ISAC + HSCX
- * - IPAC and IPAC-X
- * - ISAC-SX + HSCX
- *
- * Supported cards:
- * - Dialogic Diva 2.0
- * - Dialogic Diva 2.0U
- * - Dialogic Diva 2.01
- * - Dialogic Diva 2.02
- * - Sedlbauer Speedwin
- * - HST Saphir3
- * - Develo (former ELSA) Microlink PCI (Quickstep 1000)
- * - Develo (former ELSA) Quickstep 3000
- * - Berkom Scitel BRIX Quadro
- * - Dr.Neuhaus (Sagem) Niccy
- *
- * Author Karsten Keil <keil@isdn4linux.de>
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/mISDNhw.h>
-#include <linux/slab.h>
-#include "ipac.h"
-
-#define INFINEON_REV "1.0"
-
-static int inf_cnt;
-static u32 debug;
-static u32 irqloops = 4;
-
-enum inf_types {
- INF_NONE,
- INF_DIVA20,
- INF_DIVA20U,
- INF_DIVA201,
- INF_DIVA202,
- INF_SPEEDWIN,
- INF_SAPHIR3,
- INF_QS1000,
- INF_QS3000,
- INF_NICCY,
- INF_SCT_1,
- INF_SCT_2,
- INF_SCT_3,
- INF_SCT_4,
- INF_GAZEL_R685,
- INF_GAZEL_R753
-};
-
-enum addr_mode {
- AM_NONE = 0,
- AM_IO,
- AM_MEMIO,
- AM_IND_IO,
-};
-
-struct inf_cinfo {
- enum inf_types typ;
- const char *full;
- const char *name;
- enum addr_mode cfg_mode;
- enum addr_mode addr_mode;
- u8 cfg_bar;
- u8 addr_bar;
- void *irqfunc;
-};
-
-struct _ioaddr {
- enum addr_mode mode;
- union {
- void __iomem *p;
- struct _ioport io;
- } a;
-};
-
-struct _iohandle {
- enum addr_mode mode;
- resource_size_t size;
- resource_size_t start;
- void __iomem *p;
-};
-
-struct inf_hw {
- struct list_head list;
- struct pci_dev *pdev;
- const struct inf_cinfo *ci;
- char name[MISDN_MAX_IDLEN];
- u32 irq;
- u32 irqcnt;
- struct _iohandle cfg;
- struct _iohandle addr;
- struct _ioaddr isac;
- struct _ioaddr hscx;
- spinlock_t lock; /* HW access lock */
- struct ipac_hw ipac;
- struct inf_hw *sc[3]; /* slave cards */
-};
-
-
-#define PCI_SUBVENDOR_HST_SAPHIR3 0x52
-#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53
-#define PCI_SUB_ID_SEDLBAUER 0x01
-
-static struct pci_device_id infineon_ids[] = {
- { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20), INF_DIVA20 },
- { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U), INF_DIVA20U },
- { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201), INF_DIVA201 },
- { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202), INF_DIVA202 },
- { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
- PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0,
- INF_SPEEDWIN },
- { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
- PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3 },
- { PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK), INF_QS1000 },
- { PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000), INF_QS3000 },
- { PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY), INF_NICCY },
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
- PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0,
- INF_SCT_1 },
- { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685), INF_GAZEL_R685 },
- { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753), INF_GAZEL_R753 },
- { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO), INF_GAZEL_R753 },
- { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC), INF_GAZEL_R753 },
- { }
-};
-MODULE_DEVICE_TABLE(pci, infineon_ids);
-
-/* PCI interface specific defines */
-/* Diva 2.0/2.0U */
-#define DIVA_HSCX_PORT 0x00
-#define DIVA_HSCX_ALE 0x04
-#define DIVA_ISAC_PORT 0x08
-#define DIVA_ISAC_ALE 0x0C
-#define DIVA_PCI_CTRL 0x10
-
-/* DIVA_PCI_CTRL bits */
-#define DIVA_IRQ_BIT 0x01
-#define DIVA_RESET_BIT 0x08
-#define DIVA_EEPROM_CLK 0x40
-#define DIVA_LED_A 0x10
-#define DIVA_LED_B 0x20
-#define DIVA_IRQ_CLR 0x80
-
-/* Diva 2.01/2.02 */
-/* Siemens PITA */
-#define PITA_ICR_REG 0x00
-#define PITA_INT0_STATUS 0x02
-
-#define PITA_MISC_REG 0x1c
-#define PITA_PARA_SOFTRESET 0x01000000
-#define PITA_SER_SOFTRESET 0x02000000
-#define PITA_PARA_MPX_MODE 0x04000000
-#define PITA_INT0_ENABLE 0x00020000
-
-/* TIGER 100 Registers */
-#define TIGER_RESET_ADDR 0x00
-#define TIGER_EXTERN_RESET 0x01
-#define TIGER_AUX_CTRL 0x02
-#define TIGER_AUX_DATA 0x03
-#define TIGER_AUX_IRQMASK 0x05
-#define TIGER_AUX_STATUS 0x07
-
-/* Tiger AUX BITs */
-#define TIGER_IOMASK 0xdd /* 1 and 5 are inputs */
-#define TIGER_IRQ_BIT 0x02
-
-#define TIGER_IPAC_ALE 0xC0
-#define TIGER_IPAC_PORT 0xC8
-
-/* ELSA (now Develo) PCI cards */
-#define ELSA_IRQ_ADDR 0x4c
-#define ELSA_IRQ_MASK 0x04
-#define QS1000_IRQ_OFF 0x01
-#define QS3000_IRQ_OFF 0x03
-#define QS1000_IRQ_ON 0x41
-#define QS3000_IRQ_ON 0x43
-
-/* Dr Neuhaus/Sagem Niccy */
-#define NICCY_ISAC_PORT 0x00
-#define NICCY_HSCX_PORT 0x01
-#define NICCY_ISAC_ALE 0x02
-#define NICCY_HSCX_ALE 0x03
-
-#define NICCY_IRQ_CTRL_REG 0x38
-#define NICCY_IRQ_ENABLE 0x001f00
-#define NICCY_IRQ_DISABLE 0xff0000
-#define NICCY_IRQ_BIT 0x800000
-
-
-/* Scitel PLX */
-#define SCT_PLX_IRQ_ADDR 0x4c
-#define SCT_PLX_RESET_ADDR 0x50
-#define SCT_PLX_IRQ_ENABLE 0x41
-#define SCT_PLX_RESET_BIT 0x04
-
-/* Gazel */
-#define GAZEL_IPAC_DATA_PORT 0x04
-/* Gazel PLX */
-#define GAZEL_CNTRL 0x50
-#define GAZEL_RESET 0x04
-#define GAZEL_RESET_9050 0x40000000
-#define GAZEL_INCSR 0x4C
-#define GAZEL_ISAC_EN 0x08
-#define GAZEL_INT_ISAC 0x20
-#define GAZEL_HSCX_EN 0x01
-#define GAZEL_INT_HSCX 0x04
-#define GAZEL_PCI_EN 0x40
-#define GAZEL_IPAC_EN 0x03
-
-
-static LIST_HEAD(Cards);
-static DEFINE_RWLOCK(card_lock); /* protect Cards */
-
-static void
-_set_debug(struct inf_hw *card)
-{
- card->ipac.isac.dch.debug = debug;
- card->ipac.hscx[0].bch.debug = debug;
- card->ipac.hscx[1].bch.debug = debug;
-}
-
-static int
-set_debug(const char *val, const struct kernel_param *kp)
-{
- int ret;
- struct inf_hw *card;
-
- ret = param_set_uint(val, kp);
- if (!ret) {
- read_lock(&card_lock);
- list_for_each_entry(card, &Cards, list)
- _set_debug(card);
- read_unlock(&card_lock);
- }
- return ret;
-}
-
-MODULE_AUTHOR("Karsten Keil");
-MODULE_DESCRIPTION("mISDN driver for cards based on Infineon ISDN chipsets");
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION(INFINEON_REV);
-module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "infineon debug mask");
-module_param(irqloops, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)");
-
-/* Interface functions */
-
-IOFUNC_IO(ISAC, inf_hw, isac.a.io)
-IOFUNC_IO(IPAC, inf_hw, hscx.a.io)
-IOFUNC_IND(ISAC, inf_hw, isac.a.io)
-IOFUNC_IND(IPAC, inf_hw, hscx.a.io)
-IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p)
-IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p)
-
-static irqreturn_t
-diva_irq(int intno, void *dev_id)
-{
- struct inf_hw *hw = dev_id;
- u8 val;
-
- spin_lock(&hw->lock);
- val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL);
- if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */
- spin_unlock(&hw->lock);
- return IRQ_NONE; /* shared */
- }
- hw->irqcnt++;
- mISDNipac_irq(&hw->ipac, irqloops);
- spin_unlock(&hw->lock);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-diva20x_irq(int intno, void *dev_id)
-{
- struct inf_hw *hw = dev_id;
- u8 val;
-
- spin_lock(&hw->lock);
- val = readb(hw->cfg.p);
- if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */
- spin_unlock(&hw->lock);
- return IRQ_NONE; /* shared */
- }
- hw->irqcnt++;
- mISDNipac_irq(&hw->ipac, irqloops);
- writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */
- spin_unlock(&hw->lock);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-tiger_irq(int intno, void *dev_id)
-{
- struct inf_hw *hw = dev_id;
- u8 val;
-
- spin_lock(&hw->lock);
- val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS);
- if (val & TIGER_IRQ_BIT) { /* for us or shared ? */
- spin_unlock(&hw->lock);
- return IRQ_NONE; /* shared */
- }
- hw->irqcnt++;
- mISDNipac_irq(&hw->ipac, irqloops);
- spin_unlock(&hw->lock);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-elsa_irq(int intno, void *dev_id)
-{
- struct inf_hw *hw = dev_id;
- u8 val;
-
- spin_lock(&hw->lock);
- val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR);
- if (!(val & ELSA_IRQ_MASK)) {
- spin_unlock(&hw->lock);
- return IRQ_NONE; /* shared */
- }
- hw->irqcnt++;
- mISDNipac_irq(&hw->ipac, irqloops);
- spin_unlock(&hw->lock);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-niccy_irq(int intno, void *dev_id)
-{
- struct inf_hw *hw = dev_id;
- u32 val;
-
- spin_lock(&hw->lock);
- val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
- if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */
- spin_unlock(&hw->lock);
- return IRQ_NONE; /* shared */
- }
- outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
- hw->irqcnt++;
- mISDNipac_irq(&hw->ipac, irqloops);
- spin_unlock(&hw->lock);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-gazel_irq(int intno, void *dev_id)
-{
- struct inf_hw *hw = dev_id;
- irqreturn_t ret;
-
- spin_lock(&hw->lock);
- ret = mISDNipac_irq(&hw->ipac, irqloops);
- spin_unlock(&hw->lock);
- return ret;
-}
-
-static irqreturn_t
-ipac_irq(int intno, void *dev_id)
-{
- struct inf_hw *hw = dev_id;
- u8 val;
-
- spin_lock(&hw->lock);
- val = hw->ipac.read_reg(hw, IPAC_ISTA);
- if (!(val & 0x3f)) {
- spin_unlock(&hw->lock);
- return IRQ_NONE; /* shared */
- }
- hw->irqcnt++;
- mISDNipac_irq(&hw->ipac, irqloops);
- spin_unlock(&hw->lock);
- return IRQ_HANDLED;
-}
-
-static void
-enable_hwirq(struct inf_hw *hw)
-{
- u16 w;
- u32 val;
-
- switch (hw->ci->typ) {
- case INF_DIVA201:
- case INF_DIVA202:
- writel(PITA_INT0_ENABLE, hw->cfg.p);
- break;
- case INF_SPEEDWIN:
- case INF_SAPHIR3:
- outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);
- break;
- case INF_QS1000:
- outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
- break;
- case INF_QS3000:
- outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
- break;
- case INF_NICCY:
- val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
- val |= NICCY_IRQ_ENABLE;
- outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
- break;
- case INF_SCT_1:
- w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
- w |= SCT_PLX_IRQ_ENABLE;
- outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
- break;
- case INF_GAZEL_R685:
- outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN,
- (u32)hw->cfg.start + GAZEL_INCSR);
- break;
- case INF_GAZEL_R753:
- outb(GAZEL_IPAC_EN + GAZEL_PCI_EN,
- (u32)hw->cfg.start + GAZEL_INCSR);
- break;
- default:
- break;
- }
-}
-
-static void
-disable_hwirq(struct inf_hw *hw)
-{
- u16 w;
- u32 val;
-
- switch (hw->ci->typ) {
- case INF_DIVA201:
- case INF_DIVA202:
- writel(0, hw->cfg.p);
- break;
- case INF_SPEEDWIN:
- case INF_SAPHIR3:
- outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);
- break;
- case INF_QS1000:
- outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
- break;
- case INF_QS3000:
- outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
- break;
- case INF_NICCY:
- val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
- val &= NICCY_IRQ_DISABLE;
- outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
- break;
- case INF_SCT_1:
- w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
- w &= (~SCT_PLX_IRQ_ENABLE);
- outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
- break;
- case INF_GAZEL_R685:
- case INF_GAZEL_R753:
- outb(0, (u32)hw->cfg.start + GAZEL_INCSR);
- break;
- default:
- break;
- }
-}
-
-static void
-ipac_chip_reset(struct inf_hw *hw)
-{
- hw->ipac.write_reg(hw, IPAC_POTA2, 0x20);
- mdelay(5);
- hw->ipac.write_reg(hw, IPAC_POTA2, 0x00);
- mdelay(5);
- hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf);
- hw->ipac.write_reg(hw, IPAC_MASK, 0xc0);
-}
-
-static void
-reset_inf(struct inf_hw *hw)
-{
- u16 w;
- u32 val;
-
- if (debug & DEBUG_HW)
- pr_notice("%s: resetting card\n", hw->name);
- switch (hw->ci->typ) {
- case INF_DIVA20:
- case INF_DIVA20U:
- outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL);
- mdelay(10);
- outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL);
- mdelay(10);
- /* Workaround PCI9060 */
- outb(9, (u32)hw->cfg.start + 0x69);
- outb(DIVA_RESET_BIT | DIVA_LED_A,
- (u32)hw->cfg.start + DIVA_PCI_CTRL);
- break;
- case INF_DIVA201:
- writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,
- hw->cfg.p + PITA_MISC_REG);
- mdelay(1);
- writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG);
- mdelay(10);
- break;
- case INF_DIVA202:
- writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,
- hw->cfg.p + PITA_MISC_REG);
- mdelay(1);
- writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET,
- hw->cfg.p + PITA_MISC_REG);
- mdelay(10);
- break;
- case INF_SPEEDWIN:
- case INF_SAPHIR3:
- ipac_chip_reset(hw);
- hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);
- hw->ipac.write_reg(hw, IPAC_AOE, 0x00);
- hw->ipac.write_reg(hw, IPAC_PCFG, 0x12);
- break;
- case INF_QS1000:
- case INF_QS3000:
- ipac_chip_reset(hw);
- hw->ipac.write_reg(hw, IPAC_ACFG, 0x00);
- hw->ipac.write_reg(hw, IPAC_AOE, 0x3c);
- hw->ipac.write_reg(hw, IPAC_ATX, 0xff);
- break;
- case INF_NICCY:
- break;
- case INF_SCT_1:
- w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
- w &= (~SCT_PLX_RESET_BIT);
- outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
- mdelay(10);
- w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
- w |= SCT_PLX_RESET_BIT;
- outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
- mdelay(10);
- break;
- case INF_GAZEL_R685:
- val = inl((u32)hw->cfg.start + GAZEL_CNTRL);
- val |= (GAZEL_RESET_9050 + GAZEL_RESET);
- outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
- val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);
- mdelay(4);
- outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
- mdelay(10);
- hw->ipac.isac.adf2 = 0x87;
- hw->ipac.hscx[0].slot = 0x1f;
- hw->ipac.hscx[1].slot = 0x23;
- break;
- case INF_GAZEL_R753:
- val = inl((u32)hw->cfg.start + GAZEL_CNTRL);
- val |= (GAZEL_RESET_9050 + GAZEL_RESET);
- outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
- val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);
- mdelay(4);
- outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
- mdelay(10);
- ipac_chip_reset(hw);
- hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);
- hw->ipac.write_reg(hw, IPAC_AOE, 0x00);
- hw->ipac.conf = 0x01; /* IOM off */
- break;
- default:
- return;
- }
- enable_hwirq(hw);
-}
-
-static int
-inf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg)
-{
- int ret = 0;
-
- switch (cmd) {
- case HW_RESET_REQ:
- reset_inf(hw);
- break;
- default:
- pr_info("%s: %s unknown command %x %lx\n",
- hw->name, __func__, cmd, arg);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int
-init_irq(struct inf_hw *hw)
-{
- int ret, cnt = 3;
- u_long flags;
-
- if (!hw->ci->irqfunc)
- return -EINVAL;
- ret = request_irq(hw->irq, hw->ci->irqfunc, IRQF_SHARED, hw->name, hw);
- if (ret) {
- pr_info("%s: couldn't get interrupt %d\n", hw->name, hw->irq);
- return ret;
- }
- while (cnt--) {
- spin_lock_irqsave(&hw->lock, flags);
- reset_inf(hw);
- ret = hw->ipac.init(&hw->ipac);
- if (ret) {
- spin_unlock_irqrestore(&hw->lock, flags);
- pr_info("%s: ISAC init failed with %d\n",
- hw->name, ret);
- break;
- }
- spin_unlock_irqrestore(&hw->lock, flags);
- msleep_interruptible(10);
- if (debug & DEBUG_HW)
- pr_notice("%s: IRQ %d count %d\n", hw->name,
- hw->irq, hw->irqcnt);
- if (!hw->irqcnt) {
- pr_info("%s: IRQ(%d) got no requests during init %d\n",
- hw->name, hw->irq, 3 - cnt);
- } else
- return 0;
- }
- free_irq(hw->irq, hw);
- return -EIO;
-}
-
-static void
-release_io(struct inf_hw *hw)
-{
- if (hw->cfg.mode) {
- if (hw->cfg.mode == AM_MEMIO) {
- release_mem_region(hw->cfg.start, hw->cfg.size);
- if (hw->cfg.p)
- iounmap(hw->cfg.p);
- } else
- release_region(hw->cfg.start, hw->cfg.size);
- hw->cfg.mode = AM_NONE;
- }
- if (hw->addr.mode) {
- if (hw->addr.mode == AM_MEMIO) {
- release_mem_region(hw->addr.start, hw->addr.size);
- if (hw->addr.p)
- iounmap(hw->addr.p);
- } else
- release_region(hw->addr.start, hw->addr.size);
- hw->addr.mode = AM_NONE;
- }
-}
-
-static int
-setup_io(struct inf_hw *hw)
-{
- int err = 0;
-
- if (hw->ci->cfg_mode) {
- hw->cfg.start = pci_resource_start(hw->pdev, hw->ci->cfg_bar);
- hw->cfg.size = pci_resource_len(hw->pdev, hw->ci->cfg_bar);
- if (hw->ci->cfg_mode == AM_MEMIO) {
- if (!request_mem_region(hw->cfg.start, hw->cfg.size,
- hw->name))
- err = -EBUSY;
- } else {
- if (!request_region(hw->cfg.start, hw->cfg.size,
- hw->name))
- err = -EBUSY;
- }
- if (err) {
- pr_info("mISDN: %s config port %lx (%lu bytes)"
- "already in use\n", hw->name,
- (ulong)hw->cfg.start, (ulong)hw->cfg.size);
- return err;
- }
- hw->cfg.mode = hw->ci->cfg_mode;
- if (hw->ci->cfg_mode == AM_MEMIO) {
- hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size);
- if (!hw->cfg.p)
- return -ENOMEM;
- }
- if (debug & DEBUG_HW)
- pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n",
- hw->name, (ulong)hw->cfg.start,
- (ulong)hw->cfg.size, hw->ci->cfg_mode);
-
- }
- if (hw->ci->addr_mode) {
- hw->addr.start = pci_resource_start(hw->pdev, hw->ci->addr_bar);
- hw->addr.size = pci_resource_len(hw->pdev, hw->ci->addr_bar);
- if (hw->ci->addr_mode == AM_MEMIO) {
- if (!request_mem_region(hw->addr.start, hw->addr.size,
- hw->name))
- err = -EBUSY;
- } else {
- if (!request_region(hw->addr.start, hw->addr.size,
- hw->name))
- err = -EBUSY;
- }
- if (err) {
- pr_info("mISDN: %s address port %lx (%lu bytes)"
- "already in use\n", hw->name,
- (ulong)hw->addr.start, (ulong)hw->addr.size);
- return err;
- }
- hw->addr.mode = hw->ci->addr_mode;
- if (hw->ci->addr_mode == AM_MEMIO) {
- hw->addr.p = ioremap(hw->addr.start, hw->addr.size);
- if (!hw->addr.p)
- return -ENOMEM;
- }
- if (debug & DEBUG_HW)
- pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n",
- hw->name, (ulong)hw->addr.start,
- (ulong)hw->addr.size, hw->ci->addr_mode);
-
- }
-
- switch (hw->ci->typ) {
- case INF_DIVA20:
- case INF_DIVA20U:
- hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
- hw->isac.mode = hw->cfg.mode;
- hw->isac.a.io.ale = (u32)hw->cfg.start + DIVA_ISAC_ALE;
- hw->isac.a.io.port = (u32)hw->cfg.start + DIVA_ISAC_PORT;
- hw->hscx.mode = hw->cfg.mode;
- hw->hscx.a.io.ale = (u32)hw->cfg.start + DIVA_HSCX_ALE;
- hw->hscx.a.io.port = (u32)hw->cfg.start + DIVA_HSCX_PORT;
- break;
- case INF_DIVA201:
- hw->ipac.type = IPAC_TYPE_IPAC;
- hw->ipac.isac.off = 0x80;
- hw->isac.mode = hw->addr.mode;
- hw->isac.a.p = hw->addr.p;
- hw->hscx.mode = hw->addr.mode;
- hw->hscx.a.p = hw->addr.p;
- break;
- case INF_DIVA202:
- hw->ipac.type = IPAC_TYPE_IPACX;
- hw->isac.mode = hw->addr.mode;
- hw->isac.a.p = hw->addr.p;
- hw->hscx.mode = hw->addr.mode;
- hw->hscx.a.p = hw->addr.p;
- break;
- case INF_SPEEDWIN:
- case INF_SAPHIR3:
- hw->ipac.type = IPAC_TYPE_IPAC;
- hw->ipac.isac.off = 0x80;
- hw->isac.mode = hw->cfg.mode;
- hw->isac.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;
- hw->isac.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;
- hw->hscx.mode = hw->cfg.mode;
- hw->hscx.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;
- hw->hscx.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;
- outb(0xff, (ulong)hw->cfg.start);
- mdelay(1);
- outb(0x00, (ulong)hw->cfg.start);
- mdelay(1);
- outb(TIGER_IOMASK, (ulong)hw->cfg.start + TIGER_AUX_CTRL);
- break;
- case INF_QS1000:
- case INF_QS3000:
- hw->ipac.type = IPAC_TYPE_IPAC;
- hw->ipac.isac.off = 0x80;
- hw->isac.a.io.ale = (u32)hw->addr.start;
- hw->isac.a.io.port = (u32)hw->addr.start + 1;
- hw->isac.mode = hw->addr.mode;
- hw->hscx.a.io.ale = (u32)hw->addr.start;
- hw->hscx.a.io.port = (u32)hw->addr.start + 1;
- hw->hscx.mode = hw->addr.mode;
- break;
- case INF_NICCY:
- hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
- hw->isac.mode = hw->addr.mode;
- hw->isac.a.io.ale = (u32)hw->addr.start + NICCY_ISAC_ALE;
- hw->isac.a.io.port = (u32)hw->addr.start + NICCY_ISAC_PORT;
- hw->hscx.mode = hw->addr.mode;
- hw->hscx.a.io.ale = (u32)hw->addr.start + NICCY_HSCX_ALE;
- hw->hscx.a.io.port = (u32)hw->addr.start + NICCY_HSCX_PORT;
- break;
- case INF_SCT_1:
- hw->ipac.type = IPAC_TYPE_IPAC;
- hw->ipac.isac.off = 0x80;
- hw->isac.a.io.ale = (u32)hw->addr.start;
- hw->isac.a.io.port = hw->isac.a.io.ale + 4;
- hw->isac.mode = hw->addr.mode;
- hw->hscx.a.io.ale = hw->isac.a.io.ale;
- hw->hscx.a.io.port = hw->isac.a.io.port;
- hw->hscx.mode = hw->addr.mode;
- break;
- case INF_SCT_2:
- hw->ipac.type = IPAC_TYPE_IPAC;
- hw->ipac.isac.off = 0x80;
- hw->isac.a.io.ale = (u32)hw->addr.start + 0x08;
- hw->isac.a.io.port = hw->isac.a.io.ale + 4;
- hw->isac.mode = hw->addr.mode;
- hw->hscx.a.io.ale = hw->isac.a.io.ale;
- hw->hscx.a.io.port = hw->isac.a.io.port;
- hw->hscx.mode = hw->addr.mode;
- break;
- case INF_SCT_3:
- hw->ipac.type = IPAC_TYPE_IPAC;
- hw->ipac.isac.off = 0x80;
- hw->isac.a.io.ale = (u32)hw->addr.start + 0x10;
- hw->isac.a.io.port = hw->isac.a.io.ale + 4;
- hw->isac.mode = hw->addr.mode;
- hw->hscx.a.io.ale = hw->isac.a.io.ale;
- hw->hscx.a.io.port = hw->isac.a.io.port;
- hw->hscx.mode = hw->addr.mode;
- break;
- case INF_SCT_4:
- hw->ipac.type = IPAC_TYPE_IPAC;
- hw->ipac.isac.off = 0x80;
- hw->isac.a.io.ale = (u32)hw->addr.start + 0x20;
- hw->isac.a.io.port = hw->isac.a.io.ale + 4;
- hw->isac.mode = hw->addr.mode;
- hw->hscx.a.io.ale = hw->isac.a.io.ale;
- hw->hscx.a.io.port = hw->isac.a.io.port;
- hw->hscx.mode = hw->addr.mode;
- break;
- case INF_GAZEL_R685:
- hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
- hw->ipac.isac.off = 0x80;
- hw->isac.mode = hw->addr.mode;
- hw->isac.a.io.port = (u32)hw->addr.start;
- hw->hscx.mode = hw->addr.mode;
- hw->hscx.a.io.port = hw->isac.a.io.port;
- break;
- case INF_GAZEL_R753:
- hw->ipac.type = IPAC_TYPE_IPAC;
- hw->ipac.isac.off = 0x80;
- hw->isac.mode = hw->addr.mode;
- hw->isac.a.io.ale = (u32)hw->addr.start;
- hw->isac.a.io.port = (u32)hw->addr.start + GAZEL_IPAC_DATA_PORT;
- hw->hscx.mode = hw->addr.mode;
- hw->hscx.a.io.ale = hw->isac.a.io.ale;
- hw->hscx.a.io.port = hw->isac.a.io.port;
- break;
- default:
- return -EINVAL;
- }
- switch (hw->isac.mode) {
- case AM_MEMIO:
- ASSIGN_FUNC_IPAC(MIO, hw->ipac);
- break;
- case AM_IND_IO:
- ASSIGN_FUNC_IPAC(IND, hw->ipac);
- break;
- case AM_IO:
- ASSIGN_FUNC_IPAC(IO, hw->ipac);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static void
-release_card(struct inf_hw *card) {
- ulong flags;
- int i;
-
- spin_lock_irqsave(&card->lock, flags);
- disable_hwirq(card);
- spin_unlock_irqrestore(&card->lock, flags);
- card->ipac.isac.release(&card->ipac.isac);
- free_irq(card->irq, card);
- mISDN_unregister_device(&card->ipac.isac.dch.dev);
- release_io(card);
- write_lock_irqsave(&card_lock, flags);
- list_del(&card->list);
- write_unlock_irqrestore(&card_lock, flags);
- switch (card->ci->typ) {
- case INF_SCT_2:
- case INF_SCT_3:
- case INF_SCT_4:
- break;
- case INF_SCT_1:
- for (i = 0; i < 3; i++) {
- if (card->sc[i])
- release_card(card->sc[i]);
- card->sc[i] = NULL;
- }
- fallthrough;
- default:
- pci_disable_device(card->pdev);
- pci_set_drvdata(card->pdev, NULL);
- break;
- }
- kfree(card);
- inf_cnt--;
-}
-
-static int
-setup_instance(struct inf_hw *card)
-{
- int err;
- ulong flags;
-
- snprintf(card->name, MISDN_MAX_IDLEN - 1, "%s.%d", card->ci->name,
- inf_cnt + 1);
- write_lock_irqsave(&card_lock, flags);
- list_add_tail(&card->list, &Cards);
- write_unlock_irqrestore(&card_lock, flags);
-
- _set_debug(card);
- card->ipac.isac.name = card->name;
- card->ipac.name = card->name;
- card->ipac.owner = THIS_MODULE;
- spin_lock_init(&card->lock);
- card->ipac.isac.hwlock = &card->lock;
- card->ipac.hwlock = &card->lock;
- card->ipac.ctrl = (void *)&inf_ctrl;
-
- err = setup_io(card);
- if (err)
- goto error_setup;
-
- card->ipac.isac.dch.dev.Bprotocols =
- mISDNipac_init(&card->ipac, card);
-
- if (card->ipac.isac.dch.dev.Bprotocols == 0)
- goto error_setup;
-
- err = mISDN_register_device(&card->ipac.isac.dch.dev,
- &card->pdev->dev, card->name);
- if (err)
- goto error;
-
- err = init_irq(card);
- if (!err) {
- inf_cnt++;
- pr_notice("Infineon %d cards installed\n", inf_cnt);
- return 0;
- }
- mISDN_unregister_device(&card->ipac.isac.dch.dev);
-error:
- card->ipac.release(&card->ipac);
-error_setup:
- release_io(card);
- write_lock_irqsave(&card_lock, flags);
- list_del(&card->list);
- write_unlock_irqrestore(&card_lock, flags);
- return err;
-}
-
-static const struct inf_cinfo inf_card_info[] = {
- {
- INF_DIVA20,
- "Dialogic Diva 2.0",
- "diva20",
- AM_IND_IO, AM_NONE, 2, 0,
- &diva_irq
- },
- {
- INF_DIVA20U,
- "Dialogic Diva 2.0U",
- "diva20U",
- AM_IND_IO, AM_NONE, 2, 0,
- &diva_irq
- },
- {
- INF_DIVA201,
- "Dialogic Diva 2.01",
- "diva201",
- AM_MEMIO, AM_MEMIO, 0, 1,
- &diva20x_irq
- },
- {
- INF_DIVA202,
- "Dialogic Diva 2.02",
- "diva202",
- AM_MEMIO, AM_MEMIO, 0, 1,
- &diva20x_irq
- },
- {
- INF_SPEEDWIN,
- "Sedlbauer SpeedWin PCI",
- "speedwin",
- AM_IND_IO, AM_NONE, 0, 0,
- &tiger_irq
- },
- {
- INF_SAPHIR3,
- "HST Saphir 3",
- "saphir",
- AM_IND_IO, AM_NONE, 0, 0,
- &tiger_irq
- },
- {
- INF_QS1000,
- "Develo Microlink PCI",
- "qs1000",
- AM_IO, AM_IND_IO, 1, 3,
- &elsa_irq
- },
- {
- INF_QS3000,
- "Develo QuickStep 3000",
- "qs3000",
- AM_IO, AM_IND_IO, 1, 3,
- &elsa_irq
- },
- {
- INF_NICCY,
- "Sagem NICCY",
- "niccy",
- AM_IO, AM_IND_IO, 0, 1,
- &niccy_irq
- },
- {
- INF_SCT_1,
- "SciTel Quadro",
- "p1_scitel",
- AM_IO, AM_IND_IO, 1, 5,
- &ipac_irq
- },
- {
- INF_SCT_2,
- "SciTel Quadro",
- "p2_scitel",
- AM_NONE, AM_IND_IO, 0, 4,
- &ipac_irq
- },
- {
- INF_SCT_3,
- "SciTel Quadro",
- "p3_scitel",
- AM_NONE, AM_IND_IO, 0, 3,
- &ipac_irq
- },
- {
- INF_SCT_4,
- "SciTel Quadro",
- "p4_scitel",
- AM_NONE, AM_IND_IO, 0, 2,
- &ipac_irq
- },
- {
- INF_GAZEL_R685,
- "Gazel R685",
- "gazel685",
- AM_IO, AM_IO, 1, 2,
- &gazel_irq
- },
- {
- INF_GAZEL_R753,
- "Gazel R753",
- "gazel753",
- AM_IO, AM_IND_IO, 1, 2,
- &ipac_irq
- },
- {
- INF_NONE,
- }
-};
-
-static const struct inf_cinfo *
-get_card_info(enum inf_types typ)
-{
- const struct inf_cinfo *ci = inf_card_info;
-
- while (ci->typ != INF_NONE) {
- if (ci->typ == typ)
- return ci;
- ci++;
- }
- return NULL;
-}
-
-static int
-inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int err = -ENOMEM;
- struct inf_hw *card;
-
- card = kzalloc_obj(struct inf_hw);
- if (!card) {
- pr_info("No memory for Infineon ISDN card\n");
- return err;
- }
- card->pdev = pdev;
- err = pci_enable_device(pdev);
- if (err) {
- kfree(card);
- return err;
- }
- card->ci = get_card_info(ent->driver_data);
- if (!card->ci) {
- pr_info("mISDN: do not have information about adapter at %s\n",
- pci_name(pdev));
- kfree(card);
- pci_disable_device(pdev);
- return -EINVAL;
- } else
- pr_notice("mISDN: found adapter %s at %s\n",
- card->ci->full, pci_name(pdev));
-
- card->irq = pdev->irq;
- pci_set_drvdata(pdev, card);
- err = setup_instance(card);
- if (err) {
- pci_disable_device(pdev);
- kfree(card);
- pci_set_drvdata(pdev, NULL);
- } else if (ent->driver_data == INF_SCT_1) {
- int i;
- struct inf_hw *sc;
-
- for (i = 1; i < 4; i++) {
- sc = kzalloc_obj(struct inf_hw);
- if (!sc) {
- release_card(card);
- pci_disable_device(pdev);
- return -ENOMEM;
- }
- sc->irq = card->irq;
- sc->pdev = card->pdev;
- sc->ci = card->ci + i;
- err = setup_instance(sc);
- if (err) {
- pci_disable_device(pdev);
- kfree(sc);
- release_card(card);
- break;
- } else
- card->sc[i - 1] = sc;
- }
- }
- return err;
-}
-
-static void
-inf_remove(struct pci_dev *pdev)
-{
- struct inf_hw *card = pci_get_drvdata(pdev);
-
- if (card)
- release_card(card);
- else
- pr_debug("%s: drvdata already removed\n", __func__);
-}
-
-static struct pci_driver infineon_driver = {
- .name = "ISDN Infineon pci",
- .probe = inf_probe,
- .remove = inf_remove,
- .id_table = infineon_ids,
-};
-
-static int __init
-infineon_init(void)
-{
- int err;
-
- pr_notice("Infineon ISDN Driver Rev. %s\n", INFINEON_REV);
- err = pci_register_driver(&infineon_driver);
- return err;
-}
-
-static void __exit
-infineon_cleanup(void)
-{
- pci_unregister_driver(&infineon_driver);
-}
-
-module_init(infineon_init);
-module_exit(infineon_cleanup);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * isac.c ISAC specific routines
- *
- * Author Karsten Keil <keil@isdn4linux.de>
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-
-#include <linux/irqreturn.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mISDNhw.h>
-#include "ipac.h"
-
-
-#define DBUSY_TIMER_VALUE 80
-#define ARCOFI_USE 1
-
-#define ISAC_REV "2.0"
-
-MODULE_AUTHOR("Karsten Keil");
-MODULE_VERSION(ISAC_REV);
-MODULE_DESCRIPTION("mISDN driver for ISAC specific functions");
-MODULE_LICENSE("GPL v2");
-
-#define ReadISAC(is, o) (is->read_reg(is->dch.hw, o + is->off))
-#define WriteISAC(is, o, v) (is->write_reg(is->dch.hw, o + is->off, v))
-#define ReadHSCX(h, o) (h->ip->read_reg(h->ip->hw, h->off + o))
-#define WriteHSCX(h, o, v) (h->ip->write_reg(h->ip->hw, h->off + o, v))
-#define ReadIPAC(ip, o) (ip->read_reg(ip->hw, o))
-#define WriteIPAC(ip, o, v) (ip->write_reg(ip->hw, o, v))
-
-static inline void
-ph_command(struct isac_hw *isac, u8 command)
-{
- pr_debug("%s: ph_command %x\n", isac->name, command);
- if (isac->type & IPAC_TYPE_ISACX)
- WriteISAC(isac, ISACX_CIX0, (command << 4) | 0xE);
- else
- WriteISAC(isac, ISAC_CIX0, (command << 2) | 3);
-}
-
-static void
-isac_ph_state_change(struct isac_hw *isac)
-{
- switch (isac->state) {
- case (ISAC_IND_RS):
- case (ISAC_IND_EI):
- ph_command(isac, ISAC_CMD_DUI);
- }
- schedule_event(&isac->dch, FLG_PHCHANGE);
-}
-
-static void
-isac_ph_state_bh(struct dchannel *dch)
-{
- struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
-
- switch (isac->state) {
- case ISAC_IND_RS:
- case ISAC_IND_EI:
- dch->state = 0;
- l1_event(dch->l1, HW_RESET_IND);
- break;
- case ISAC_IND_DID:
- dch->state = 3;
- l1_event(dch->l1, HW_DEACT_CNF);
- break;
- case ISAC_IND_DR:
- case ISAC_IND_DR6:
- dch->state = 3;
- l1_event(dch->l1, HW_DEACT_IND);
- break;
- case ISAC_IND_PU:
- dch->state = 4;
- l1_event(dch->l1, HW_POWERUP_IND);
- break;
- case ISAC_IND_RSY:
- if (dch->state <= 5) {
- dch->state = 5;
- l1_event(dch->l1, ANYSIGNAL);
- } else {
- dch->state = 8;
- l1_event(dch->l1, LOSTFRAMING);
- }
- break;
- case ISAC_IND_ARD:
- dch->state = 6;
- l1_event(dch->l1, INFO2);
- break;
- case ISAC_IND_AI8:
- dch->state = 7;
- l1_event(dch->l1, INFO4_P8);
- break;
- case ISAC_IND_AI10:
- dch->state = 7;
- l1_event(dch->l1, INFO4_P10);
- break;
- }
- pr_debug("%s: TE newstate %x\n", isac->name, dch->state);
-}
-
-static void
-isac_empty_fifo(struct isac_hw *isac, int count)
-{
- u8 *ptr;
-
- pr_debug("%s: %s %d\n", isac->name, __func__, count);
-
- if (!isac->dch.rx_skb) {
- isac->dch.rx_skb = mI_alloc_skb(isac->dch.maxlen, GFP_ATOMIC);
- if (!isac->dch.rx_skb) {
- pr_info("%s: D receive out of memory\n", isac->name);
- WriteISAC(isac, ISAC_CMDR, 0x80);
- return;
- }
- }
- if ((isac->dch.rx_skb->len + count) >= isac->dch.maxlen) {
- pr_debug("%s: %s overrun %d\n", isac->name, __func__,
- isac->dch.rx_skb->len + count);
- WriteISAC(isac, ISAC_CMDR, 0x80);
- return;
- }
- ptr = skb_put(isac->dch.rx_skb, count);
- isac->read_fifo(isac->dch.hw, isac->off, ptr, count);
- WriteISAC(isac, ISAC_CMDR, 0x80);
- if (isac->dch.debug & DEBUG_HW_DFIFO) {
- char pfx[MISDN_MAX_IDLEN + 16];
-
- snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-recv %s %d ",
- isac->name, count);
- print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);
- }
-}
-
-static void
-isac_fill_fifo(struct isac_hw *isac)
-{
- int count, more;
- u8 *ptr;
-
- if (!isac->dch.tx_skb)
- return;
- count = isac->dch.tx_skb->len - isac->dch.tx_idx;
- if (count <= 0)
- return;
-
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- pr_debug("%s: %s %d\n", isac->name, __func__, count);
- ptr = isac->dch.tx_skb->data + isac->dch.tx_idx;
- isac->dch.tx_idx += count;
- isac->write_fifo(isac->dch.hw, isac->off, ptr, count);
- WriteISAC(isac, ISAC_CMDR, more ? 0x8 : 0xa);
- if (test_and_set_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {
- pr_debug("%s: %s dbusytimer running\n", isac->name, __func__);
- timer_delete(&isac->dch.timer);
- }
- isac->dch.timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
- add_timer(&isac->dch.timer);
- if (isac->dch.debug & DEBUG_HW_DFIFO) {
- char pfx[MISDN_MAX_IDLEN + 16];
-
- snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-send %s %d ",
- isac->name, count);
- print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);
- }
-}
-
-static void
-isac_rme_irq(struct isac_hw *isac)
-{
- u8 val, count;
-
- val = ReadISAC(isac, ISAC_RSTA);
- if ((val & 0x70) != 0x20) {
- if (val & 0x40) {
- pr_debug("%s: ISAC RDO\n", isac->name);
-#ifdef ERROR_STATISTIC
- isac->dch.err_rx++;
-#endif
- }
- if (!(val & 0x20)) {
- pr_debug("%s: ISAC CRC error\n", isac->name);
-#ifdef ERROR_STATISTIC
- isac->dch.err_crc++;
-#endif
- }
- WriteISAC(isac, ISAC_CMDR, 0x80);
- dev_kfree_skb(isac->dch.rx_skb);
- isac->dch.rx_skb = NULL;
- } else {
- count = ReadISAC(isac, ISAC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- isac_empty_fifo(isac, count);
- recv_Dchannel(&isac->dch);
- }
-}
-
-static void
-isac_xpr_irq(struct isac_hw *isac)
-{
- if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))
- timer_delete(&isac->dch.timer);
- if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) {
- isac_fill_fifo(isac);
- } else {
- dev_kfree_skb(isac->dch.tx_skb);
- if (get_next_dframe(&isac->dch))
- isac_fill_fifo(isac);
- }
-}
-
-static void
-isac_retransmit(struct isac_hw *isac)
-{
- if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))
- timer_delete(&isac->dch.timer);
- if (test_bit(FLG_TX_BUSY, &isac->dch.Flags)) {
- /* Restart frame */
- isac->dch.tx_idx = 0;
- isac_fill_fifo(isac);
- } else if (isac->dch.tx_skb) { /* should not happen */
- pr_info("%s: tx_skb exist but not busy\n", isac->name);
- test_and_set_bit(FLG_TX_BUSY, &isac->dch.Flags);
- isac->dch.tx_idx = 0;
- isac_fill_fifo(isac);
- } else {
- pr_info("%s: ISAC XDU no TX_BUSY\n", isac->name);
- if (get_next_dframe(&isac->dch))
- isac_fill_fifo(isac);
- }
-}
-
-static void
-isac_mos_irq(struct isac_hw *isac)
-{
- u8 val;
- int ret;
-
- val = ReadISAC(isac, ISAC_MOSR);
- pr_debug("%s: ISAC MOSR %02x\n", isac->name, val);
-#if ARCOFI_USE
- if (val & 0x08) {
- if (!isac->mon_rx) {
- isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
- if (!isac->mon_rx) {
- pr_info("%s: ISAC MON RX out of memory!\n",
- isac->name);
- isac->mocr &= 0xf0;
- isac->mocr |= 0x0a;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- goto afterMONR0;
- } else
- isac->mon_rxp = 0;
- }
- if (isac->mon_rxp >= MAX_MON_FRAME) {
- isac->mocr &= 0xf0;
- isac->mocr |= 0x0a;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- isac->mon_rxp = 0;
- pr_debug("%s: ISAC MON RX overflow!\n", isac->name);
- goto afterMONR0;
- }
- isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR0);
- pr_debug("%s: ISAC MOR0 %02x\n", isac->name,
- isac->mon_rx[isac->mon_rxp - 1]);
- if (isac->mon_rxp == 1) {
- isac->mocr |= 0x04;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- }
- }
-afterMONR0:
- if (val & 0x80) {
- if (!isac->mon_rx) {
- isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
- if (!isac->mon_rx) {
- pr_info("%s: ISAC MON RX out of memory!\n",
- isac->name);
- isac->mocr &= 0x0f;
- isac->mocr |= 0xa0;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- goto afterMONR1;
- } else
- isac->mon_rxp = 0;
- }
- if (isac->mon_rxp >= MAX_MON_FRAME) {
- isac->mocr &= 0x0f;
- isac->mocr |= 0xa0;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- isac->mon_rxp = 0;
- pr_debug("%s: ISAC MON RX overflow!\n", isac->name);
- goto afterMONR1;
- }
- isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR1);
- pr_debug("%s: ISAC MOR1 %02x\n", isac->name,
- isac->mon_rx[isac->mon_rxp - 1]);
- isac->mocr |= 0x40;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- }
-afterMONR1:
- if (val & 0x04) {
- isac->mocr &= 0xf0;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- isac->mocr |= 0x0a;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- if (isac->monitor) {
- ret = isac->monitor(isac->dch.hw, MONITOR_RX_0,
- isac->mon_rx, isac->mon_rxp);
- if (ret)
- kfree(isac->mon_rx);
- } else {
- pr_info("%s: MONITOR 0 received %d but no user\n",
- isac->name, isac->mon_rxp);
- kfree(isac->mon_rx);
- }
- isac->mon_rx = NULL;
- isac->mon_rxp = 0;
- }
- if (val & 0x40) {
- isac->mocr &= 0x0f;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- isac->mocr |= 0xa0;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- if (isac->monitor) {
- ret = isac->monitor(isac->dch.hw, MONITOR_RX_1,
- isac->mon_rx, isac->mon_rxp);
- if (ret)
- kfree(isac->mon_rx);
- } else {
- pr_info("%s: MONITOR 1 received %d but no user\n",
- isac->name, isac->mon_rxp);
- kfree(isac->mon_rx);
- }
- isac->mon_rx = NULL;
- isac->mon_rxp = 0;
- }
- if (val & 0x02) {
- if ((!isac->mon_tx) || (isac->mon_txc &&
- (isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) {
- isac->mocr &= 0xf0;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- isac->mocr |= 0x0a;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
- if (isac->monitor)
- isac->monitor(isac->dch.hw,
- MONITOR_TX_0, NULL, 0);
- }
- kfree(isac->mon_tx);
- isac->mon_tx = NULL;
- isac->mon_txc = 0;
- isac->mon_txp = 0;
- goto AfterMOX0;
- }
- if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
- if (isac->monitor)
- isac->monitor(isac->dch.hw,
- MONITOR_TX_0, NULL, 0);
- kfree(isac->mon_tx);
- isac->mon_tx = NULL;
- isac->mon_txc = 0;
- isac->mon_txp = 0;
- goto AfterMOX0;
- }
- WriteISAC(isac, ISAC_MOX0, isac->mon_tx[isac->mon_txp++]);
- pr_debug("%s: ISAC %02x -> MOX0\n", isac->name,
- isac->mon_tx[isac->mon_txp - 1]);
- }
-AfterMOX0:
- if (val & 0x20) {
- if ((!isac->mon_tx) || (isac->mon_txc &&
- (isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) {
- isac->mocr &= 0x0f;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- isac->mocr |= 0xa0;
- WriteISAC(isac, ISAC_MOCR, isac->mocr);
- if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
- if (isac->monitor)
- isac->monitor(isac->dch.hw,
- MONITOR_TX_1, NULL, 0);
- }
- kfree(isac->mon_tx);
- isac->mon_tx = NULL;
- isac->mon_txc = 0;
- isac->mon_txp = 0;
- goto AfterMOX1;
- }
- if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
- if (isac->monitor)
- isac->monitor(isac->dch.hw,
- MONITOR_TX_1, NULL, 0);
- kfree(isac->mon_tx);
- isac->mon_tx = NULL;
- isac->mon_txc = 0;
- isac->mon_txp = 0;
- goto AfterMOX1;
- }
- WriteISAC(isac, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
- pr_debug("%s: ISAC %02x -> MOX1\n", isac->name,
- isac->mon_tx[isac->mon_txp - 1]);
- }
-AfterMOX1:
- val = 0; /* dummy to avoid warning */
-#endif
-}
-
-static void
-isac_cisq_irq(struct isac_hw *isac) {
- u8 val;
-
- val = ReadISAC(isac, ISAC_CIR0);
- pr_debug("%s: ISAC CIR0 %02X\n", isac->name, val);
- if (val & 2) {
- pr_debug("%s: ph_state change %x->%x\n", isac->name,
- isac->state, (val >> 2) & 0xf);
- isac->state = (val >> 2) & 0xf;
- isac_ph_state_change(isac);
- }
- if (val & 1) {
- val = ReadISAC(isac, ISAC_CIR1);
- pr_debug("%s: ISAC CIR1 %02X\n", isac->name, val);
- }
-}
-
-static void
-isacsx_cic_irq(struct isac_hw *isac)
-{
- u8 val;
-
- val = ReadISAC(isac, ISACX_CIR0);
- pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);
- if (val & ISACX_CIR0_CIC0) {
- pr_debug("%s: ph_state change %x->%x\n", isac->name,
- isac->state, val >> 4);
- isac->state = val >> 4;
- isac_ph_state_change(isac);
- }
-}
-
-static void
-isacsx_rme_irq(struct isac_hw *isac)
-{
- int count;
- u8 val;
-
- val = ReadISAC(isac, ISACX_RSTAD);
- if ((val & (ISACX_RSTAD_VFR |
- ISACX_RSTAD_RDO |
- ISACX_RSTAD_CRC |
- ISACX_RSTAD_RAB))
- != (ISACX_RSTAD_VFR | ISACX_RSTAD_CRC)) {
- pr_debug("%s: RSTAD %#x, dropped\n", isac->name, val);
-#ifdef ERROR_STATISTIC
- if (val & ISACX_RSTAD_CRC)
- isac->dch.err_rx++;
- else
- isac->dch.err_crc++;
-#endif
- WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);
- dev_kfree_skb(isac->dch.rx_skb);
- isac->dch.rx_skb = NULL;
- } else {
- count = ReadISAC(isac, ISACX_RBCLD) & 0x1f;
- if (count == 0)
- count = 32;
- isac_empty_fifo(isac, count);
- if (isac->dch.rx_skb) {
- skb_trim(isac->dch.rx_skb, isac->dch.rx_skb->len - 1);
- pr_debug("%s: dchannel received %d\n", isac->name,
- isac->dch.rx_skb->len);
- recv_Dchannel(&isac->dch);
- }
- }
-}
-
-irqreturn_t
-mISDNisac_irq(struct isac_hw *isac, u8 val)
-{
- if (unlikely(!val))
- return IRQ_NONE;
- pr_debug("%s: ISAC interrupt %02x\n", isac->name, val);
- if (isac->type & IPAC_TYPE_ISACX) {
- if (val & ISACX__CIC)
- isacsx_cic_irq(isac);
- if (val & ISACX__ICD) {
- val = ReadISAC(isac, ISACX_ISTAD);
- pr_debug("%s: ISTAD %02x\n", isac->name, val);
- if (val & ISACX_D_XDU) {
- pr_debug("%s: ISAC XDU\n", isac->name);
-#ifdef ERROR_STATISTIC
- isac->dch.err_tx++;
-#endif
- isac_retransmit(isac);
- }
- if (val & ISACX_D_XMR) {
- pr_debug("%s: ISAC XMR\n", isac->name);
-#ifdef ERROR_STATISTIC
- isac->dch.err_tx++;
-#endif
- isac_retransmit(isac);
- }
- if (val & ISACX_D_XPR)
- isac_xpr_irq(isac);
- if (val & ISACX_D_RFO) {
- pr_debug("%s: ISAC RFO\n", isac->name);
- WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);
- }
- if (val & ISACX_D_RME)
- isacsx_rme_irq(isac);
- if (val & ISACX_D_RPF)
- isac_empty_fifo(isac, 0x20);
- }
- } else {
- if (val & 0x80) /* RME */
- isac_rme_irq(isac);
- if (val & 0x40) /* RPF */
- isac_empty_fifo(isac, 32);
- if (val & 0x10) /* XPR */
- isac_xpr_irq(isac);
- if (val & 0x04) /* CISQ */
- isac_cisq_irq(isac);
- if (val & 0x20) /* RSC - never */
- pr_debug("%s: ISAC RSC interrupt\n", isac->name);
- if (val & 0x02) /* SIN - never */
- pr_debug("%s: ISAC SIN interrupt\n", isac->name);
- if (val & 0x01) { /* EXI */
- val = ReadISAC(isac, ISAC_EXIR);
- pr_debug("%s: ISAC EXIR %02x\n", isac->name, val);
- if (val & 0x80) /* XMR */
- pr_debug("%s: ISAC XMR\n", isac->name);
- if (val & 0x40) { /* XDU */
- pr_debug("%s: ISAC XDU\n", isac->name);
-#ifdef ERROR_STATISTIC
- isac->dch.err_tx++;
-#endif
- isac_retransmit(isac);
- }
- if (val & 0x04) /* MOS */
- isac_mos_irq(isac);
- }
- }
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(mISDNisac_irq);
-
-static int
-isac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
- int ret = -EINVAL;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- u32 id;
- u_long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- spin_lock_irqsave(isac->hwlock, flags);
- ret = dchannel_senddata(dch, skb);
- if (ret > 0) { /* direct TX */
- id = hh->id; /* skb can be freed */
- isac_fill_fifo(isac);
- ret = 0;
- spin_unlock_irqrestore(isac->hwlock, flags);
- queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
- } else
- spin_unlock_irqrestore(isac->hwlock, flags);
- return ret;
- case PH_ACTIVATE_REQ:
- ret = l1_event(dch->l1, hh->prim);
- break;
- case PH_DEACTIVATE_REQ:
- test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
- ret = l1_event(dch->l1, hh->prim);
- break;
- }
-
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static int
-isac_ctrl(struct isac_hw *isac, u32 cmd, unsigned long para)
-{
- u8 tl = 0;
- unsigned long flags;
- int ret = 0;
-
- switch (cmd) {
- case HW_TESTLOOP:
- spin_lock_irqsave(isac->hwlock, flags);
- if (!(isac->type & IPAC_TYPE_ISACX)) {
- /* TODO: implement for IPAC_TYPE_ISACX */
- if (para & 1) /* B1 */
- tl |= 0x0c;
- else if (para & 2) /* B2 */
- tl |= 0x3;
- /* we only support IOM2 mode */
- WriteISAC(isac, ISAC_SPCR, tl);
- if (tl)
- WriteISAC(isac, ISAC_ADF1, 0x8);
- else
- WriteISAC(isac, ISAC_ADF1, 0x0);
- }
- spin_unlock_irqrestore(isac->hwlock, flags);
- break;
- case HW_TIMER3_VALUE:
- ret = l1_event(isac->dch.l1, HW_TIMER3_VALUE | (para & 0xff));
- break;
- default:
- pr_debug("%s: %s unknown command %x %lx\n", isac->name,
- __func__, cmd, para);
- ret = -1;
- }
- return ret;
-}
-
-static int
-isac_l1cmd(struct dchannel *dch, u32 cmd)
-{
- struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
- u_long flags;
-
- pr_debug("%s: cmd(%x) state(%02x)\n", isac->name, cmd, isac->state);
- switch (cmd) {
- case INFO3_P8:
- spin_lock_irqsave(isac->hwlock, flags);
- ph_command(isac, ISAC_CMD_AR8);
- spin_unlock_irqrestore(isac->hwlock, flags);
- break;
- case INFO3_P10:
- spin_lock_irqsave(isac->hwlock, flags);
- ph_command(isac, ISAC_CMD_AR10);
- spin_unlock_irqrestore(isac->hwlock, flags);
- break;
- case HW_RESET_REQ:
- spin_lock_irqsave(isac->hwlock, flags);
- if ((isac->state == ISAC_IND_EI) ||
- (isac->state == ISAC_IND_DR) ||
- (isac->state == ISAC_IND_DR6) ||
- (isac->state == ISAC_IND_RS))
- ph_command(isac, ISAC_CMD_TIM);
- else
- ph_command(isac, ISAC_CMD_RS);
- spin_unlock_irqrestore(isac->hwlock, flags);
- break;
- case HW_DEACT_REQ:
- skb_queue_purge(&dch->squeue);
- if (dch->tx_skb) {
- dev_kfree_skb(dch->tx_skb);
- dch->tx_skb = NULL;
- }
- dch->tx_idx = 0;
- if (dch->rx_skb) {
- dev_kfree_skb(dch->rx_skb);
- dch->rx_skb = NULL;
- }
- test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
- if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
- timer_delete(&dch->timer);
- break;
- case HW_POWERUP_REQ:
- spin_lock_irqsave(isac->hwlock, flags);
- ph_command(isac, ISAC_CMD_TIM);
- spin_unlock_irqrestore(isac->hwlock, flags);
- break;
- case PH_ACTIVATE_IND:
- test_and_set_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
- GFP_ATOMIC);
- break;
- case PH_DEACTIVATE_IND:
- test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
- GFP_ATOMIC);
- break;
- default:
- pr_debug("%s: %s unknown command %x\n", isac->name,
- __func__, cmd);
- return -1;
- }
- return 0;
-}
-
-static void
-isac_release(struct isac_hw *isac)
-{
- if (isac->type & IPAC_TYPE_ISACX)
- WriteISAC(isac, ISACX_MASK, 0xff);
- else if (isac->type != 0)
- WriteISAC(isac, ISAC_MASK, 0xff);
- if (isac->dch.timer.function != NULL) {
- timer_delete(&isac->dch.timer);
- isac->dch.timer.function = NULL;
- }
- kfree(isac->mon_rx);
- isac->mon_rx = NULL;
- kfree(isac->mon_tx);
- isac->mon_tx = NULL;
- if (isac->dch.l1)
- l1_event(isac->dch.l1, CLOSE_CHANNEL);
- mISDN_freedchannel(&isac->dch);
-}
-
-static void
-dbusy_timer_handler(struct timer_list *t)
-{
- struct isac_hw *isac = timer_container_of(isac, t, dch.timer);
- int rbch, star;
- u_long flags;
-
- if (test_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {
- spin_lock_irqsave(isac->hwlock, flags);
- rbch = ReadISAC(isac, ISAC_RBCH);
- star = ReadISAC(isac, ISAC_STAR);
- pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n",
- isac->name, rbch, star);
- if (rbch & ISAC_RBCH_XAC) /* D-Channel Busy */
- test_and_set_bit(FLG_L1_BUSY, &isac->dch.Flags);
- else {
- /* discard frame; reset transceiver */
- test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags);
- if (isac->dch.tx_idx)
- isac->dch.tx_idx = 0;
- else
- pr_info("%s: ISAC D-Channel Busy no tx_idx\n",
- isac->name);
- /* Transmitter reset */
- WriteISAC(isac, ISAC_CMDR, 0x01);
- }
- spin_unlock_irqrestore(isac->hwlock, flags);
- }
-}
-
-static int
-open_dchannel_caller(struct isac_hw *isac, struct channel_req *rq, void *caller)
-{
- pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__,
- isac->dch.dev.id, caller);
- if (rq->protocol != ISDN_P_TE_S0)
- return -EINVAL;
- if (rq->adr.channel == 1)
- /* E-Channel not supported */
- return -EINVAL;
- rq->ch = &isac->dch.dev.D;
- rq->ch->protocol = rq->protocol;
- if (isac->dch.state == 7)
- _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
- 0, NULL, GFP_KERNEL);
- return 0;
-}
-
-static int
-open_dchannel(struct isac_hw *isac, struct channel_req *rq)
-{
- return open_dchannel_caller(isac, rq, __builtin_return_address(0));
-}
-
-static const char *ISACVer[] =
-{"2086/2186 V1.1", "2085 B1", "2085 B2",
- "2085 V2.3"};
-
-static int
-isac_init(struct isac_hw *isac)
-{
- u8 val;
- int err = 0;
-
- if (!isac->dch.l1) {
- err = create_l1(&isac->dch, isac_l1cmd);
- if (err)
- return err;
- }
- isac->mon_tx = NULL;
- isac->mon_rx = NULL;
- timer_setup(&isac->dch.timer, dbusy_timer_handler, 0);
- isac->mocr = 0xaa;
- if (isac->type & IPAC_TYPE_ISACX) {
- /* Disable all IRQ */
- WriteISAC(isac, ISACX_MASK, 0xff);
- val = ReadISAC(isac, ISACX_STARD);
- pr_debug("%s: ISACX STARD %x\n", isac->name, val);
- val = ReadISAC(isac, ISACX_ISTAD);
- pr_debug("%s: ISACX ISTAD %x\n", isac->name, val);
- val = ReadISAC(isac, ISACX_ISTA);
- pr_debug("%s: ISACX ISTA %x\n", isac->name, val);
- /* clear LDD */
- WriteISAC(isac, ISACX_TR_CONF0, 0x00);
- /* enable transmitter */
- WriteISAC(isac, ISACX_TR_CONF2, 0x00);
- /* transparent mode 0, RAC, stop/go */
- WriteISAC(isac, ISACX_MODED, 0xc9);
- /* all HDLC IRQ unmasked */
- val = ReadISAC(isac, ISACX_ID);
- if (isac->dch.debug & DEBUG_HW)
- pr_notice("%s: ISACX Design ID %x\n",
- isac->name, val & 0x3f);
- val = ReadISAC(isac, ISACX_CIR0);
- pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);
- isac->state = val >> 4;
- isac_ph_state_change(isac);
- ph_command(isac, ISAC_CMD_RS);
- WriteISAC(isac, ISACX_MASK, IPACX__ON);
- WriteISAC(isac, ISACX_MASKD, 0x00);
- } else { /* old isac */
- WriteISAC(isac, ISAC_MASK, 0xff);
- val = ReadISAC(isac, ISAC_STAR);
- pr_debug("%s: ISAC STAR %x\n", isac->name, val);
- val = ReadISAC(isac, ISAC_MODE);
- pr_debug("%s: ISAC MODE %x\n", isac->name, val);
- val = ReadISAC(isac, ISAC_ADF2);
- pr_debug("%s: ISAC ADF2 %x\n", isac->name, val);
- val = ReadISAC(isac, ISAC_ISTA);
- pr_debug("%s: ISAC ISTA %x\n", isac->name, val);
- if (val & 0x01) {
- val = ReadISAC(isac, ISAC_EXIR);
- pr_debug("%s: ISAC EXIR %x\n", isac->name, val);
- }
- val = ReadISAC(isac, ISAC_RBCH);
- if (isac->dch.debug & DEBUG_HW)
- pr_notice("%s: ISAC version (%x): %s\n", isac->name,
- val, ISACVer[(val >> 5) & 3]);
- isac->type |= ((val >> 5) & 3);
- if (!isac->adf2)
- isac->adf2 = 0x80;
- if (!(isac->adf2 & 0x80)) { /* only IOM 2 Mode */
- pr_info("%s: only support IOM2 mode but adf2=%02x\n",
- isac->name, isac->adf2);
- isac_release(isac);
- return -EINVAL;
- }
- WriteISAC(isac, ISAC_ADF2, isac->adf2);
- WriteISAC(isac, ISAC_SQXR, 0x2f);
- WriteISAC(isac, ISAC_SPCR, 0x00);
- WriteISAC(isac, ISAC_STCR, 0x70);
- WriteISAC(isac, ISAC_MODE, 0xc9);
- WriteISAC(isac, ISAC_TIMR, 0x00);
- WriteISAC(isac, ISAC_ADF1, 0x00);
- val = ReadISAC(isac, ISAC_CIR0);
- pr_debug("%s: ISAC CIR0 %x\n", isac->name, val);
- isac->state = (val >> 2) & 0xf;
- isac_ph_state_change(isac);
- ph_command(isac, ISAC_CMD_RS);
- WriteISAC(isac, ISAC_MASK, 0);
- }
- return err;
-}
-
-int
-mISDNisac_init(struct isac_hw *isac, void *hw)
-{
- mISDN_initdchannel(&isac->dch, MAX_DFRAME_LEN_L1, isac_ph_state_bh);
- isac->dch.hw = hw;
- isac->dch.dev.D.send = isac_l1hw;
- isac->init = isac_init;
- isac->release = isac_release;
- isac->ctrl = isac_ctrl;
- isac->open = open_dchannel;
- isac->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0);
- isac->dch.dev.nrbchan = 2;
- return 0;
-}
-EXPORT_SYMBOL(mISDNisac_init);
-
-static void
-waitforCEC(struct hscx_hw *hx)
-{
- u8 starb, to = 50;
-
- while (to) {
- starb = ReadHSCX(hx, IPAC_STARB);
- if (!(starb & 0x04))
- break;
- udelay(1);
- to--;
- }
- if (to < 50)
- pr_debug("%s: B%1d CEC %d us\n", hx->ip->name, hx->bch.nr,
- 50 - to);
- if (!to)
- pr_info("%s: B%1d CEC timeout\n", hx->ip->name, hx->bch.nr);
-}
-
-
-static void
-waitforXFW(struct hscx_hw *hx)
-{
- u8 starb, to = 50;
-
- while (to) {
- starb = ReadHSCX(hx, IPAC_STARB);
- if ((starb & 0x44) == 0x40)
- break;
- udelay(1);
- to--;
- }
- if (to < 50)
- pr_debug("%s: B%1d XFW %d us\n", hx->ip->name, hx->bch.nr,
- 50 - to);
- if (!to)
- pr_info("%s: B%1d XFW timeout\n", hx->ip->name, hx->bch.nr);
-}
-
-static void
-hscx_cmdr(struct hscx_hw *hx, u8 cmd)
-{
- if (hx->ip->type & IPAC_TYPE_IPACX)
- WriteHSCX(hx, IPACX_CMDRB, cmd);
- else {
- waitforCEC(hx);
- WriteHSCX(hx, IPAC_CMDRB, cmd);
- }
-}
-
-static void
-hscx_empty_fifo(struct hscx_hw *hscx, u8 count)
-{
- u8 *p;
- int maxlen;
-
- pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);
- if (test_bit(FLG_RX_OFF, &hscx->bch.Flags)) {
- hscx->bch.dropcnt += count;
- hscx_cmdr(hscx, 0x80); /* RMC */
- return;
- }
- maxlen = bchannel_get_rxbuf(&hscx->bch, count);
- if (maxlen < 0) {
- hscx_cmdr(hscx, 0x80); /* RMC */
- if (hscx->bch.rx_skb)
- skb_trim(hscx->bch.rx_skb, 0);
- pr_warn("%s.B%d: No bufferspace for %d bytes\n",
- hscx->ip->name, hscx->bch.nr, count);
- return;
- }
- p = skb_put(hscx->bch.rx_skb, count);
-
- if (hscx->ip->type & IPAC_TYPE_IPACX)
- hscx->ip->read_fifo(hscx->ip->hw,
- hscx->off + IPACX_RFIFOB, p, count);
- else
- hscx->ip->read_fifo(hscx->ip->hw,
- hscx->off, p, count);
-
- hscx_cmdr(hscx, 0x80); /* RMC */
-
- if (hscx->bch.debug & DEBUG_HW_BFIFO) {
- snprintf(hscx->log, 64, "B%1d-recv %s %d ",
- hscx->bch.nr, hscx->ip->name, count);
- print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);
- }
-}
-
-static void
-hscx_fill_fifo(struct hscx_hw *hscx)
-{
- int count, more;
- u8 *p;
-
- if (!hscx->bch.tx_skb) {
- if (!test_bit(FLG_TX_EMPTY, &hscx->bch.Flags))
- return;
- count = hscx->fifo_size;
- more = 1;
- p = hscx->log;
- memset(p, hscx->bch.fill[0], count);
- } else {
- count = hscx->bch.tx_skb->len - hscx->bch.tx_idx;
- if (count <= 0)
- return;
- p = hscx->bch.tx_skb->data + hscx->bch.tx_idx;
-
- more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0;
- if (count > hscx->fifo_size) {
- count = hscx->fifo_size;
- more = 1;
- }
- pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr,
- count, hscx->bch.tx_idx, hscx->bch.tx_skb->len);
- hscx->bch.tx_idx += count;
- }
- if (hscx->ip->type & IPAC_TYPE_IPACX)
- hscx->ip->write_fifo(hscx->ip->hw,
- hscx->off + IPACX_XFIFOB, p, count);
- else {
- waitforXFW(hscx);
- hscx->ip->write_fifo(hscx->ip->hw,
- hscx->off, p, count);
- }
- hscx_cmdr(hscx, more ? 0x08 : 0x0a);
-
- if (hscx->bch.tx_skb && (hscx->bch.debug & DEBUG_HW_BFIFO)) {
- snprintf(hscx->log, 64, "B%1d-send %s %d ",
- hscx->bch.nr, hscx->ip->name, count);
- print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);
- }
-}
-
-static void
-hscx_xpr(struct hscx_hw *hx)
-{
- if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) {
- hscx_fill_fifo(hx);
- } else {
- dev_kfree_skb(hx->bch.tx_skb);
- if (get_next_bframe(&hx->bch)) {
- hscx_fill_fifo(hx);
- test_and_clear_bit(FLG_TX_EMPTY, &hx->bch.Flags);
- } else if (test_bit(FLG_TX_EMPTY, &hx->bch.Flags)) {
- hscx_fill_fifo(hx);
- }
- }
-}
-
-static void
-ipac_rme(struct hscx_hw *hx)
-{
- int count;
- u8 rstab;
-
- if (hx->ip->type & IPAC_TYPE_IPACX)
- rstab = ReadHSCX(hx, IPACX_RSTAB);
- else
- rstab = ReadHSCX(hx, IPAC_RSTAB);
- pr_debug("%s: B%1d RSTAB %02x\n", hx->ip->name, hx->bch.nr, rstab);
- if ((rstab & 0xf0) != 0xa0) {
- /* !(VFR && !RDO && CRC && !RAB) */
- if (!(rstab & 0x80)) {
- if (hx->bch.debug & DEBUG_HW_BCHANNEL)
- pr_notice("%s: B%1d invalid frame\n",
- hx->ip->name, hx->bch.nr);
- }
- if (rstab & 0x40) {
- if (hx->bch.debug & DEBUG_HW_BCHANNEL)
- pr_notice("%s: B%1d RDO proto=%x\n",
- hx->ip->name, hx->bch.nr,
- hx->bch.state);
- }
- if (!(rstab & 0x20)) {
- if (hx->bch.debug & DEBUG_HW_BCHANNEL)
- pr_notice("%s: B%1d CRC error\n",
- hx->ip->name, hx->bch.nr);
- }
- hscx_cmdr(hx, 0x80); /* Do RMC */
- return;
- }
- if (hx->ip->type & IPAC_TYPE_IPACX)
- count = ReadHSCX(hx, IPACX_RBCLB);
- else
- count = ReadHSCX(hx, IPAC_RBCLB);
- count &= (hx->fifo_size - 1);
- if (count == 0)
- count = hx->fifo_size;
- hscx_empty_fifo(hx, count);
- if (!hx->bch.rx_skb)
- return;
- if (hx->bch.rx_skb->len < 2) {
- pr_debug("%s: B%1d frame too short %d\n",
- hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len);
- skb_trim(hx->bch.rx_skb, 0);
- } else {
- skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1);
- recv_Bchannel(&hx->bch, 0, false);
- }
-}
-
-static void
-ipac_irq(struct hscx_hw *hx, u8 ista)
-{
- u8 istab, m, exirb = 0;
-
- if (hx->ip->type & IPAC_TYPE_IPACX)
- istab = ReadHSCX(hx, IPACX_ISTAB);
- else if (hx->ip->type & IPAC_TYPE_IPAC) {
- istab = ReadHSCX(hx, IPAC_ISTAB);
- m = (hx->bch.nr & 1) ? IPAC__EXA : IPAC__EXB;
- if (m & ista) {
- exirb = ReadHSCX(hx, IPAC_EXIRB);
- pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
- hx->bch.nr, exirb);
- }
- } else if (hx->bch.nr & 2) { /* HSCX B */
- if (ista & (HSCX__EXA | HSCX__ICA))
- ipac_irq(&hx->ip->hscx[0], ista);
- if (ista & HSCX__EXB) {
- exirb = ReadHSCX(hx, IPAC_EXIRB);
- pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
- hx->bch.nr, exirb);
- }
- istab = ista & 0xF8;
- } else { /* HSCX A */
- istab = ReadHSCX(hx, IPAC_ISTAB);
- if (ista & HSCX__EXA) {
- exirb = ReadHSCX(hx, IPAC_EXIRB);
- pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
- hx->bch.nr, exirb);
- }
- istab = istab & 0xF8;
- }
- if (exirb & IPAC_B_XDU)
- istab |= IPACX_B_XDU;
- if (exirb & IPAC_B_RFO)
- istab |= IPACX_B_RFO;
- pr_debug("%s: B%1d ISTAB %02x\n", hx->ip->name, hx->bch.nr, istab);
-
- if (!test_bit(FLG_ACTIVE, &hx->bch.Flags))
- return;
-
- if (istab & IPACX_B_RME)
- ipac_rme(hx);
-
- if (istab & IPACX_B_RPF) {
- hscx_empty_fifo(hx, hx->fifo_size);
- if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags))
- recv_Bchannel(&hx->bch, 0, false);
- }
-
- if (istab & IPACX_B_RFO) {
- pr_debug("%s: B%1d RFO error\n", hx->ip->name, hx->bch.nr);
- hscx_cmdr(hx, 0x40); /* RRES */
- }
-
- if (istab & IPACX_B_XPR)
- hscx_xpr(hx);
-
- if (istab & IPACX_B_XDU) {
- if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {
- if (test_bit(FLG_FILLEMPTY, &hx->bch.Flags))
- test_and_set_bit(FLG_TX_EMPTY, &hx->bch.Flags);
- hscx_xpr(hx);
- return;
- }
- pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name,
- hx->bch.nr, hx->bch.tx_idx);
- hx->bch.tx_idx = 0;
- hscx_cmdr(hx, 0x01); /* XRES */
- }
-}
-
-irqreturn_t
-mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
-{
- int cnt = maxloop + 1;
- u8 ista, istad;
- struct isac_hw *isac = &ipac->isac;
-
- if (ipac->type & IPAC_TYPE_IPACX) {
- ista = ReadIPAC(ipac, ISACX_ISTA);
- while (ista && --cnt) {
- pr_debug("%s: ISTA %02x\n", ipac->name, ista);
- if (ista & IPACX__ICA)
- ipac_irq(&ipac->hscx[0], ista);
- if (ista & IPACX__ICB)
- ipac_irq(&ipac->hscx[1], ista);
- if (ista & (ISACX__ICD | ISACX__CIC))
- mISDNisac_irq(&ipac->isac, ista);
- ista = ReadIPAC(ipac, ISACX_ISTA);
- }
- } else if (ipac->type & IPAC_TYPE_IPAC) {
- ista = ReadIPAC(ipac, IPAC_ISTA);
- while (ista && --cnt) {
- pr_debug("%s: ISTA %02x\n", ipac->name, ista);
- if (ista & (IPAC__ICD | IPAC__EXD)) {
- istad = ReadISAC(isac, ISAC_ISTA);
- pr_debug("%s: ISTAD %02x\n", ipac->name, istad);
- if (istad & IPAC_D_TIN2)
- pr_debug("%s TIN2 irq\n", ipac->name);
- if (ista & IPAC__EXD)
- istad |= 1; /* ISAC EXI */
- mISDNisac_irq(isac, istad);
- }
- if (ista & (IPAC__ICA | IPAC__EXA))
- ipac_irq(&ipac->hscx[0], ista);
- if (ista & (IPAC__ICB | IPAC__EXB))
- ipac_irq(&ipac->hscx[1], ista);
- ista = ReadIPAC(ipac, IPAC_ISTA);
- }
- } else if (ipac->type & IPAC_TYPE_HSCX) {
- while (--cnt) {
- ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off);
- pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista);
- if (ista)
- ipac_irq(&ipac->hscx[1], ista);
- istad = ReadISAC(isac, ISAC_ISTA);
- pr_debug("%s: ISTAD %02x\n", ipac->name, istad);
- if (istad)
- mISDNisac_irq(isac, istad);
- if (0 == (ista | istad))
- break;
- }
- }
- if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */
- return IRQ_NONE;
- if (cnt < maxloop)
- pr_debug("%s: %d irqloops cpu%d\n", ipac->name,
- maxloop - cnt, smp_processor_id());
- if (maxloop && !cnt)
- pr_notice("%s: %d IRQ LOOP cpu%d\n", ipac->name,
- maxloop, smp_processor_id());
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(mISDNipac_irq);
-
-static int
-hscx_mode(struct hscx_hw *hscx, u32 bprotocol)
-{
- pr_debug("%s: HSCX %c protocol %x-->%x ch %d\n", hscx->ip->name,
- '@' + hscx->bch.nr, hscx->bch.state, bprotocol, hscx->bch.nr);
- if (hscx->ip->type & IPAC_TYPE_IPACX) {
- if (hscx->bch.nr & 1) { /* B1 and ICA */
- WriteIPAC(hscx->ip, ISACX_BCHA_TSDP_BC1, 0x80);
- WriteIPAC(hscx->ip, ISACX_BCHA_CR, 0x88);
- } else { /* B2 and ICB */
- WriteIPAC(hscx->ip, ISACX_BCHB_TSDP_BC1, 0x81);
- WriteIPAC(hscx->ip, ISACX_BCHB_CR, 0x88);
- }
- switch (bprotocol) {
- case ISDN_P_NONE: /* init */
- WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* rec off */
- WriteHSCX(hscx, IPACX_EXMB, 0x30); /* std adj. */
- WriteHSCX(hscx, IPACX_MASKB, 0xFF); /* ints off */
- hscx_cmdr(hscx, 0x41);
- test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
- test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
- break;
- case ISDN_P_B_RAW:
- WriteHSCX(hscx, IPACX_MODEB, 0x88); /* ex trans */
- WriteHSCX(hscx, IPACX_EXMB, 0x00); /* trans */
- hscx_cmdr(hscx, 0x41);
- WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);
- test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
- break;
- case ISDN_P_B_HDLC:
- WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* trans */
- WriteHSCX(hscx, IPACX_EXMB, 0x00); /* hdlc,crc */
- hscx_cmdr(hscx, 0x41);
- WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);
- test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
- break;
- default:
- pr_info("%s: protocol not known %x\n", hscx->ip->name,
- bprotocol);
- return -ENOPROTOOPT;
- }
- } else if (hscx->ip->type & IPAC_TYPE_IPAC) { /* IPAC */
- WriteHSCX(hscx, IPAC_CCR1, 0x82);
- WriteHSCX(hscx, IPAC_CCR2, 0x30);
- WriteHSCX(hscx, IPAC_XCCR, 0x07);
- WriteHSCX(hscx, IPAC_RCCR, 0x07);
- WriteHSCX(hscx, IPAC_TSAX, hscx->slot);
- WriteHSCX(hscx, IPAC_TSAR, hscx->slot);
- switch (bprotocol) {
- case ISDN_P_NONE:
- WriteHSCX(hscx, IPAC_TSAX, 0x1F);
- WriteHSCX(hscx, IPAC_TSAR, 0x1F);
- WriteHSCX(hscx, IPAC_MODEB, 0x84);
- WriteHSCX(hscx, IPAC_CCR1, 0x82);
- WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */
- test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
- test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
- break;
- case ISDN_P_B_RAW:
- WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */
- WriteHSCX(hscx, IPAC_CCR1, 0x82);
- hscx_cmdr(hscx, 0x41);
- WriteHSCX(hscx, IPAC_MASKB, 0);
- test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
- break;
- case ISDN_P_B_HDLC:
- WriteHSCX(hscx, IPAC_MODEB, 0x8c);
- WriteHSCX(hscx, IPAC_CCR1, 0x8a);
- hscx_cmdr(hscx, 0x41);
- WriteHSCX(hscx, IPAC_MASKB, 0);
- test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
- break;
- default:
- pr_info("%s: protocol not known %x\n", hscx->ip->name,
- bprotocol);
- return -ENOPROTOOPT;
- }
- } else if (hscx->ip->type & IPAC_TYPE_HSCX) { /* HSCX */
- WriteHSCX(hscx, IPAC_CCR1, 0x85);
- WriteHSCX(hscx, IPAC_CCR2, 0x30);
- WriteHSCX(hscx, IPAC_XCCR, 0x07);
- WriteHSCX(hscx, IPAC_RCCR, 0x07);
- WriteHSCX(hscx, IPAC_TSAX, hscx->slot);
- WriteHSCX(hscx, IPAC_TSAR, hscx->slot);
- switch (bprotocol) {
- case ISDN_P_NONE:
- WriteHSCX(hscx, IPAC_TSAX, 0x1F);
- WriteHSCX(hscx, IPAC_TSAR, 0x1F);
- WriteHSCX(hscx, IPAC_MODEB, 0x84);
- WriteHSCX(hscx, IPAC_CCR1, 0x85);
- WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */
- test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
- test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
- break;
- case ISDN_P_B_RAW:
- WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */
- WriteHSCX(hscx, IPAC_CCR1, 0x85);
- hscx_cmdr(hscx, 0x41);
- WriteHSCX(hscx, IPAC_MASKB, 0);
- test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
- break;
- case ISDN_P_B_HDLC:
- WriteHSCX(hscx, IPAC_MODEB, 0x8c);
- WriteHSCX(hscx, IPAC_CCR1, 0x8d);
- hscx_cmdr(hscx, 0x41);
- WriteHSCX(hscx, IPAC_MASKB, 0);
- test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
- break;
- default:
- pr_info("%s: protocol not known %x\n", hscx->ip->name,
- bprotocol);
- return -ENOPROTOOPT;
- }
- } else
- return -EINVAL;
- hscx->bch.state = bprotocol;
- return 0;
-}
-
-static int
-hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch);
- int ret = -EINVAL;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- unsigned long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- spin_lock_irqsave(hx->ip->hwlock, flags);
- ret = bchannel_senddata(bch, skb);
- if (ret > 0) { /* direct TX */
- ret = 0;
- hscx_fill_fifo(hx);
- }
- spin_unlock_irqrestore(hx->ip->hwlock, flags);
- return ret;
- case PH_ACTIVATE_REQ:
- spin_lock_irqsave(hx->ip->hwlock, flags);
- if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
- ret = hscx_mode(hx, ch->protocol);
- else
- ret = 0;
- spin_unlock_irqrestore(hx->ip->hwlock, flags);
- if (!ret)
- _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- break;
- case PH_DEACTIVATE_REQ:
- spin_lock_irqsave(hx->ip->hwlock, flags);
- mISDN_clear_bchannel(bch);
- hscx_mode(hx, ISDN_P_NONE);
- spin_unlock_irqrestore(hx->ip->hwlock, flags);
- _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- ret = 0;
- break;
- default:
- pr_info("%s: %s unknown prim(%x,%x)\n",
- hx->ip->name, __func__, hh->prim, hh->id);
- ret = -EINVAL;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static int
-channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
-{
- return mISDN_ctrl_bchannel(bch, cq);
-}
-
-static int
-hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch);
- int ret = -EINVAL;
- u_long flags;
-
- pr_debug("%s: %s cmd:%x %p\n", hx->ip->name, __func__, cmd, arg);
- switch (cmd) {
- case CLOSE_CHANNEL:
- test_and_clear_bit(FLG_OPEN, &bch->Flags);
- cancel_work_sync(&bch->workq);
- spin_lock_irqsave(hx->ip->hwlock, flags);
- mISDN_clear_bchannel(bch);
- hscx_mode(hx, ISDN_P_NONE);
- spin_unlock_irqrestore(hx->ip->hwlock, flags);
- ch->protocol = ISDN_P_NONE;
- ch->peer = NULL;
- module_put(hx->ip->owner);
- ret = 0;
- break;
- case CONTROL_CHANNEL:
- ret = channel_bctrl(bch, arg);
- break;
- default:
- pr_info("%s: %s unknown prim(%x)\n",
- hx->ip->name, __func__, cmd);
- }
- return ret;
-}
-
-static void
-free_ipac(struct ipac_hw *ipac)
-{
- isac_release(&ipac->isac);
-}
-
-static const char *HSCXVer[] =
-{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
- "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
-
-
-
-static void
-hscx_init(struct hscx_hw *hx)
-{
- u8 val;
-
- WriteHSCX(hx, IPAC_RAH2, 0xFF);
- WriteHSCX(hx, IPAC_XBCH, 0x00);
- WriteHSCX(hx, IPAC_RLCR, 0x00);
-
- if (hx->ip->type & IPAC_TYPE_HSCX) {
- WriteHSCX(hx, IPAC_CCR1, 0x85);
- val = ReadHSCX(hx, HSCX_VSTR);
- pr_debug("%s: HSCX VSTR %02x\n", hx->ip->name, val);
- if (hx->bch.debug & DEBUG_HW)
- pr_notice("%s: HSCX version %s\n", hx->ip->name,
- HSCXVer[val & 0x0f]);
- } else
- WriteHSCX(hx, IPAC_CCR1, 0x82);
- WriteHSCX(hx, IPAC_CCR2, 0x30);
- WriteHSCX(hx, IPAC_XCCR, 0x07);
- WriteHSCX(hx, IPAC_RCCR, 0x07);
-}
-
-static int
-ipac_init(struct ipac_hw *ipac)
-{
- u8 val;
-
- if (ipac->type & IPAC_TYPE_HSCX) {
- hscx_init(&ipac->hscx[0]);
- hscx_init(&ipac->hscx[1]);
- val = ReadIPAC(ipac, IPAC_ID);
- } else if (ipac->type & IPAC_TYPE_IPAC) {
- hscx_init(&ipac->hscx[0]);
- hscx_init(&ipac->hscx[1]);
- WriteIPAC(ipac, IPAC_MASK, IPAC__ON);
- val = ReadIPAC(ipac, IPAC_CONF);
- /* conf is default 0, but can be overwritten by card setup */
- pr_debug("%s: IPAC CONF %02x/%02x\n", ipac->name,
- val, ipac->conf);
- WriteIPAC(ipac, IPAC_CONF, ipac->conf);
- val = ReadIPAC(ipac, IPAC_ID);
- if (ipac->hscx[0].bch.debug & DEBUG_HW)
- pr_notice("%s: IPAC Design ID %02x\n", ipac->name, val);
- }
- /* nothing special for IPACX to do here */
- return isac_init(&ipac->isac);
-}
-
-static int
-open_bchannel(struct ipac_hw *ipac, struct channel_req *rq)
-{
- struct bchannel *bch;
-
- if (rq->adr.channel == 0 || rq->adr.channel > 2)
- return -EINVAL;
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
- bch = &ipac->hscx[rq->adr.channel - 1].bch;
- if (test_and_set_bit(FLG_OPEN, &bch->Flags))
- return -EBUSY; /* b-channel can be only open once */
- test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
- bch->ch.protocol = rq->protocol;
- rq->ch = &bch->ch;
- return 0;
-}
-
-static int
-channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq)
-{
- int ret = 0;
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3;
- break;
- case MISDN_CTRL_LOOP:
- /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
- if (cq->channel < 0 || cq->channel > 3) {
- ret = -EINVAL;
- break;
- }
- ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel);
- break;
- case MISDN_CTRL_L1_TIMER3:
- ret = ipac->isac.ctrl(&ipac->isac, HW_TIMER3_VALUE, cq->p1);
- break;
- default:
- pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int
-ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
- struct ipac_hw *ipac = container_of(isac, struct ipac_hw, isac);
- struct channel_req *rq;
- int err = 0;
-
- pr_debug("%s: DCTRL: %x %p\n", ipac->name, cmd, arg);
- switch (cmd) {
- case OPEN_CHANNEL:
- rq = arg;
- if (rq->protocol == ISDN_P_TE_S0)
- err = open_dchannel_caller(isac, rq, __builtin_return_address(0));
- else
- err = open_bchannel(ipac, rq);
- if (err)
- break;
- if (!try_module_get(ipac->owner))
- pr_info("%s: cannot get module\n", ipac->name);
- break;
- case CLOSE_CHANNEL:
- pr_debug("%s: dev(%d) close from %p\n", ipac->name,
- dch->dev.id, __builtin_return_address(0));
- module_put(ipac->owner);
- break;
- case CONTROL_CHANNEL:
- err = channel_ctrl(ipac, arg);
- break;
- default:
- pr_debug("%s: unknown DCTRL command %x\n", ipac->name, cmd);
- return -EINVAL;
- }
- return err;
-}
-
-u32
-mISDNipac_init(struct ipac_hw *ipac, void *hw)
-{
- u32 ret;
- u8 i;
-
- ipac->hw = hw;
- if (ipac->isac.dch.debug & DEBUG_HW)
- pr_notice("%s: ipac type %x\n", ipac->name, ipac->type);
- if (ipac->type & IPAC_TYPE_HSCX) {
- ipac->isac.type = IPAC_TYPE_ISAC;
- ipac->hscx[0].off = 0;
- ipac->hscx[1].off = 0x40;
- ipac->hscx[0].fifo_size = 32;
- ipac->hscx[1].fifo_size = 32;
- } else if (ipac->type & IPAC_TYPE_IPAC) {
- ipac->isac.type = IPAC_TYPE_IPAC | IPAC_TYPE_ISAC;
- ipac->hscx[0].off = 0;
- ipac->hscx[1].off = 0x40;
- ipac->hscx[0].fifo_size = 64;
- ipac->hscx[1].fifo_size = 64;
- } else if (ipac->type & IPAC_TYPE_IPACX) {
- ipac->isac.type = IPAC_TYPE_IPACX | IPAC_TYPE_ISACX;
- ipac->hscx[0].off = IPACX_OFF_ICA;
- ipac->hscx[1].off = IPACX_OFF_ICB;
- ipac->hscx[0].fifo_size = 64;
- ipac->hscx[1].fifo_size = 64;
- } else
- return 0;
-
- mISDNisac_init(&ipac->isac, hw);
-
- ipac->isac.dch.dev.D.ctrl = ipac_dctrl;
-
- for (i = 0; i < 2; i++) {
- ipac->hscx[i].bch.nr = i + 1;
- set_channelmap(i + 1, ipac->isac.dch.dev.channelmap);
- list_add(&ipac->hscx[i].bch.ch.list,
- &ipac->isac.dch.dev.bchannels);
- mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM,
- ipac->hscx[i].fifo_size);
- ipac->hscx[i].bch.ch.nr = i + 1;
- ipac->hscx[i].bch.ch.send = &hscx_l2l1;
- ipac->hscx[i].bch.ch.ctrl = hscx_bctrl;
- ipac->hscx[i].bch.hw = hw;
- ipac->hscx[i].ip = ipac;
- /* default values for IOM time slots
- * can be overwritten by card */
- ipac->hscx[i].slot = (i == 0) ? 0x2f : 0x03;
- }
-
- ipac->init = ipac_init;
- ipac->release = free_ipac;
-
- ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
- return ret;
-}
-EXPORT_SYMBOL(mISDNipac_init);
-
-static int __init
-isac_mod_init(void)
-{
- pr_notice("mISDNipac module version %s\n", ISAC_REV);
- return 0;
-}
-
-static void __exit
-isac_mod_cleanup(void)
-{
- pr_notice("mISDNipac module unloaded\n");
-}
-module_init(isac_mod_init);
-module_exit(isac_mod_cleanup);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * mISDNisar.c ISAR (Siemens PSB 7110) specific functions
- *
- * Author Karsten Keil (keil@isdn4linux.de)
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-
-/* define this to enable static debug messages, if you kernel supports
- * dynamic debugging, you should use debugfs for this
- */
-/* #define DEBUG */
-
-#include <linux/gfp.h>
-#include <linux/delay.h>
-#include <linux/vmalloc.h>
-#include <linux/mISDNhw.h>
-#include <linux/module.h>
-#include "isar.h"
-
-#define ISAR_REV "2.1"
-
-MODULE_AUTHOR("Karsten Keil");
-MODULE_DESCRIPTION("mISDN driver for ISAR (Siemens PSB 7110) specific functions");
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION(ISAR_REV);
-
-#define DEBUG_HW_FIRMWARE_FIFO 0x10000
-
-static const u8 faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121,
- 122, 145, 146};
-#define FAXMODCNT 13
-
-static void isar_setup(struct isar_hw *);
-
-static inline int
-waitforHIA(struct isar_hw *isar, int timeout)
-{
- int t = timeout;
- u8 val = isar->read_reg(isar->hw, ISAR_HIA);
-
- while ((val & 1) && t) {
- udelay(1);
- t--;
- val = isar->read_reg(isar->hw, ISAR_HIA);
- }
- pr_debug("%s: HIA after %dus\n", isar->name, timeout - t);
- return timeout;
-}
-
-/*
- * send msg to ISAR mailbox
- * if msg is NULL use isar->buf
- */
-static int
-send_mbox(struct isar_hw *isar, u8 his, u8 creg, u8 len, u8 *msg)
-{
- if (!waitforHIA(isar, 1000))
- return 0;
- pr_debug("send_mbox(%02x,%02x,%d)\n", his, creg, len);
- isar->write_reg(isar->hw, ISAR_CTRL_H, creg);
- isar->write_reg(isar->hw, ISAR_CTRL_L, len);
- isar->write_reg(isar->hw, ISAR_WADR, 0);
- if (!msg)
- msg = isar->buf;
- if (msg && len) {
- isar->write_fifo(isar->hw, ISAR_MBOX, msg, len);
- if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) {
- int l = 0;
-
- while (l < (int)len) {
- hex_dump_to_buffer(msg + l, len - l, 32, 1,
- isar->log, 256, 1);
- pr_debug("%s: %s %02x: %s\n", isar->name,
- __func__, l, isar->log);
- l += 32;
- }
- }
- }
- isar->write_reg(isar->hw, ISAR_HIS, his);
- waitforHIA(isar, 1000);
- return 1;
-}
-
-/*
- * receive message from ISAR mailbox
- * if msg is NULL use isar->buf
- */
-static void
-rcv_mbox(struct isar_hw *isar, u8 *msg)
-{
- if (!msg)
- msg = isar->buf;
- isar->write_reg(isar->hw, ISAR_RADR, 0);
- if (msg && isar->clsb) {
- isar->read_fifo(isar->hw, ISAR_MBOX, msg, isar->clsb);
- if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) {
- int l = 0;
-
- while (l < (int)isar->clsb) {
- hex_dump_to_buffer(msg + l, isar->clsb - l, 32,
- 1, isar->log, 256, 1);
- pr_debug("%s: %s %02x: %s\n", isar->name,
- __func__, l, isar->log);
- l += 32;
- }
- }
- }
- isar->write_reg(isar->hw, ISAR_IIA, 0);
-}
-
-static inline void
-get_irq_infos(struct isar_hw *isar)
-{
- isar->iis = isar->read_reg(isar->hw, ISAR_IIS);
- isar->cmsb = isar->read_reg(isar->hw, ISAR_CTRL_H);
- isar->clsb = isar->read_reg(isar->hw, ISAR_CTRL_L);
- pr_debug("%s: rcv_mbox(%02x,%02x,%d)\n", isar->name,
- isar->iis, isar->cmsb, isar->clsb);
-}
-
-/*
- * poll answer message from ISAR mailbox
- * should be used only with ISAR IRQs disabled before DSP was started
- *
- */
-static int
-poll_mbox(struct isar_hw *isar, int maxdelay)
-{
- int t = maxdelay;
- u8 irq;
-
- irq = isar->read_reg(isar->hw, ISAR_IRQBIT);
- while (t && !(irq & ISAR_IRQSTA)) {
- udelay(1);
- t--;
- }
- if (t) {
- get_irq_infos(isar);
- rcv_mbox(isar, NULL);
- }
- pr_debug("%s: pulled %d bytes after %d us\n",
- isar->name, isar->clsb, maxdelay - t);
- return t;
-}
-
-static int
-ISARVersion(struct isar_hw *isar)
-{
- int ver;
-
- /* disable ISAR IRQ */
- isar->write_reg(isar->hw, ISAR_IRQBIT, 0);
- isar->buf[0] = ISAR_MSG_HWVER;
- isar->buf[1] = 0;
- isar->buf[2] = 1;
- if (!send_mbox(isar, ISAR_HIS_VNR, 0, 3, NULL))
- return -1;
- if (!poll_mbox(isar, 1000))
- return -2;
- if (isar->iis == ISAR_IIS_VNR) {
- if (isar->clsb == 1) {
- ver = isar->buf[0] & 0xf;
- return ver;
- }
- return -3;
- }
- return -4;
-}
-
-static int
-load_firmware(struct isar_hw *isar, const u8 *buf, int size)
-{
- u32 saved_debug = isar->ch[0].bch.debug;
- int ret, cnt;
- u8 nom, noc;
- u16 left, val, *sp = (u16 *)buf;
- u8 *mp;
- u_long flags;
-
- struct {
- u16 sadr;
- u16 len;
- u16 d_key;
- } blk_head;
-
- if (1 != isar->version) {
- pr_err("%s: ISAR wrong version %d firmware download aborted\n",
- isar->name, isar->version);
- return -EINVAL;
- }
- if (!(saved_debug & DEBUG_HW_FIRMWARE_FIFO))
- isar->ch[0].bch.debug &= ~DEBUG_HW_BFIFO;
- pr_debug("%s: load firmware %d words (%d bytes)\n",
- isar->name, size / 2, size);
- cnt = 0;
- size /= 2;
- /* disable ISAR IRQ */
- spin_lock_irqsave(isar->hwlock, flags);
- isar->write_reg(isar->hw, ISAR_IRQBIT, 0);
- spin_unlock_irqrestore(isar->hwlock, flags);
- while (cnt < size) {
- blk_head.sadr = le16_to_cpu(*sp++);
- blk_head.len = le16_to_cpu(*sp++);
- blk_head.d_key = le16_to_cpu(*sp++);
- cnt += 3;
- pr_debug("ISAR firmware block (%#x,%d,%#x)\n",
- blk_head.sadr, blk_head.len, blk_head.d_key & 0xff);
- left = blk_head.len;
- if (cnt + left > size) {
- pr_info("%s: firmware error have %d need %d words\n",
- isar->name, size, cnt + left);
- ret = -EINVAL;
- goto reterrflg;
- }
- spin_lock_irqsave(isar->hwlock, flags);
- if (!send_mbox(isar, ISAR_HIS_DKEY, blk_head.d_key & 0xff,
- 0, NULL)) {
- pr_info("ISAR send_mbox dkey failed\n");
- ret = -ETIME;
- goto reterror;
- }
- if (!poll_mbox(isar, 1000)) {
- pr_warn("ISAR poll_mbox dkey failed\n");
- ret = -ETIME;
- goto reterror;
- }
- spin_unlock_irqrestore(isar->hwlock, flags);
- if ((isar->iis != ISAR_IIS_DKEY) || isar->cmsb || isar->clsb) {
- pr_info("ISAR wrong dkey response (%x,%x,%x)\n",
- isar->iis, isar->cmsb, isar->clsb);
- ret = 1;
- goto reterrflg;
- }
- while (left > 0) {
- if (left > 126)
- noc = 126;
- else
- noc = left;
- nom = (2 * noc) + 3;
- mp = isar->buf;
- /* the ISAR is big endian */
- *mp++ = blk_head.sadr >> 8;
- *mp++ = blk_head.sadr & 0xFF;
- left -= noc;
- cnt += noc;
- *mp++ = noc;
- pr_debug("%s: load %3d words at %04x\n", isar->name,
- noc, blk_head.sadr);
- blk_head.sadr += noc;
- while (noc) {
- val = le16_to_cpu(*sp++);
- *mp++ = val >> 8;
- *mp++ = val & 0xFF;
- noc--;
- }
- spin_lock_irqsave(isar->hwlock, flags);
- if (!send_mbox(isar, ISAR_HIS_FIRM, 0, nom, NULL)) {
- pr_info("ISAR send_mbox prog failed\n");
- ret = -ETIME;
- goto reterror;
- }
- if (!poll_mbox(isar, 1000)) {
- pr_info("ISAR poll_mbox prog failed\n");
- ret = -ETIME;
- goto reterror;
- }
- spin_unlock_irqrestore(isar->hwlock, flags);
- if ((isar->iis != ISAR_IIS_FIRM) ||
- isar->cmsb || isar->clsb) {
- pr_info("ISAR wrong prog response (%x,%x,%x)\n",
- isar->iis, isar->cmsb, isar->clsb);
- ret = -EIO;
- goto reterrflg;
- }
- }
- pr_debug("%s: ISAR firmware block %d words loaded\n",
- isar->name, blk_head.len);
- }
- isar->ch[0].bch.debug = saved_debug;
- /* 10ms delay */
- cnt = 10;
- while (cnt--)
- mdelay(1);
- isar->buf[0] = 0xff;
- isar->buf[1] = 0xfe;
- isar->bstat = 0;
- spin_lock_irqsave(isar->hwlock, flags);
- if (!send_mbox(isar, ISAR_HIS_STDSP, 0, 2, NULL)) {
- pr_info("ISAR send_mbox start dsp failed\n");
- ret = -ETIME;
- goto reterror;
- }
- if (!poll_mbox(isar, 1000)) {
- pr_info("ISAR poll_mbox start dsp failed\n");
- ret = -ETIME;
- goto reterror;
- }
- if ((isar->iis != ISAR_IIS_STDSP) || isar->cmsb || isar->clsb) {
- pr_info("ISAR wrong start dsp response (%x,%x,%x)\n",
- isar->iis, isar->cmsb, isar->clsb);
- ret = -EIO;
- goto reterror;
- } else
- pr_debug("%s: ISAR start dsp success\n", isar->name);
-
- /* NORMAL mode entered */
- /* Enable IRQs of ISAR */
- isar->write_reg(isar->hw, ISAR_IRQBIT, ISAR_IRQSTA);
- spin_unlock_irqrestore(isar->hwlock, flags);
- cnt = 1000; /* max 1s */
- while ((!isar->bstat) && cnt) {
- mdelay(1);
- cnt--;
- }
- if (!cnt) {
- pr_info("ISAR no general status event received\n");
- ret = -ETIME;
- goto reterrflg;
- } else
- pr_debug("%s: ISAR general status event %x\n",
- isar->name, isar->bstat);
- /* 10ms delay */
- cnt = 10;
- while (cnt--)
- mdelay(1);
- isar->iis = 0;
- spin_lock_irqsave(isar->hwlock, flags);
- if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) {
- pr_info("ISAR send_mbox self tst failed\n");
- ret = -ETIME;
- goto reterror;
- }
- spin_unlock_irqrestore(isar->hwlock, flags);
- cnt = 10000; /* max 100 ms */
- while ((isar->iis != ISAR_IIS_DIAG) && cnt) {
- udelay(10);
- cnt--;
- }
- mdelay(1);
- if (!cnt) {
- pr_info("ISAR no self tst response\n");
- ret = -ETIME;
- goto reterrflg;
- }
- if ((isar->cmsb == ISAR_CTRL_STST) && (isar->clsb == 1)
- && (isar->buf[0] == 0))
- pr_debug("%s: ISAR selftest OK\n", isar->name);
- else {
- pr_info("ISAR selftest not OK %x/%x/%x\n",
- isar->cmsb, isar->clsb, isar->buf[0]);
- ret = -EIO;
- goto reterrflg;
- }
- spin_lock_irqsave(isar->hwlock, flags);
- isar->iis = 0;
- if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) {
- pr_info("ISAR RQST SVN failed\n");
- ret = -ETIME;
- goto reterror;
- }
- spin_unlock_irqrestore(isar->hwlock, flags);
- cnt = 30000; /* max 300 ms */
- while ((isar->iis != ISAR_IIS_DIAG) && cnt) {
- udelay(10);
- cnt--;
- }
- mdelay(1);
- if (!cnt) {
- pr_info("ISAR no SVN response\n");
- ret = -ETIME;
- goto reterrflg;
- } else {
- if ((isar->cmsb == ISAR_CTRL_SWVER) && (isar->clsb == 1)) {
- pr_notice("%s: ISAR software version %#x\n",
- isar->name, isar->buf[0]);
- } else {
- pr_info("%s: ISAR wrong swver response (%x,%x)"
- " cnt(%d)\n", isar->name, isar->cmsb,
- isar->clsb, cnt);
- ret = -EIO;
- goto reterrflg;
- }
- }
- spin_lock_irqsave(isar->hwlock, flags);
- isar_setup(isar);
- spin_unlock_irqrestore(isar->hwlock, flags);
- ret = 0;
-reterrflg:
- spin_lock_irqsave(isar->hwlock, flags);
-reterror:
- isar->ch[0].bch.debug = saved_debug;
- if (ret)
- /* disable ISAR IRQ */
- isar->write_reg(isar->hw, ISAR_IRQBIT, 0);
- spin_unlock_irqrestore(isar->hwlock, flags);
- return ret;
-}
-
-static inline void
-deliver_status(struct isar_ch *ch, int status)
-{
- pr_debug("%s: HL->LL FAXIND %x\n", ch->is->name, status);
- _queue_data(&ch->bch.ch, PH_CONTROL_IND, status, 0, NULL, GFP_ATOMIC);
-}
-
-static inline void
-isar_rcv_frame(struct isar_ch *ch)
-{
- u8 *ptr;
- int maxlen;
-
- if (!ch->is->clsb) {
- pr_debug("%s; ISAR zero len frame\n", ch->is->name);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- return;
- }
- if (test_bit(FLG_RX_OFF, &ch->bch.Flags)) {
- ch->bch.dropcnt += ch->is->clsb;
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- return;
- }
- switch (ch->bch.state) {
- case ISDN_P_NONE:
- pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n",
- ch->is->name, ch->is->iis, ch->is->cmsb, ch->is->clsb);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- break;
- case ISDN_P_B_RAW:
- case ISDN_P_B_L2DTMF:
- case ISDN_P_B_MODEM_ASYNC:
- maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb);
- if (maxlen < 0) {
- pr_warn("%s.B%d: No bufferspace for %d bytes\n",
- ch->is->name, ch->bch.nr, ch->is->clsb);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- break;
- }
- rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb));
- recv_Bchannel(&ch->bch, 0, false);
- break;
- case ISDN_P_B_HDLC:
- maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb);
- if (maxlen < 0) {
- pr_warn("%s.B%d: No bufferspace for %d bytes\n",
- ch->is->name, ch->bch.nr, ch->is->clsb);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- break;
- }
- if (ch->is->cmsb & HDLC_ERROR) {
- pr_debug("%s: ISAR frame error %x len %d\n",
- ch->is->name, ch->is->cmsb, ch->is->clsb);
-#ifdef ERROR_STATISTIC
- if (ch->is->cmsb & HDLC_ERR_RER)
- ch->bch.err_inv++;
- if (ch->is->cmsb & HDLC_ERR_CER)
- ch->bch.err_crc++;
-#endif
- skb_trim(ch->bch.rx_skb, 0);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- break;
- }
- if (ch->is->cmsb & HDLC_FSD)
- skb_trim(ch->bch.rx_skb, 0);
- ptr = skb_put(ch->bch.rx_skb, ch->is->clsb);
- rcv_mbox(ch->is, ptr);
- if (ch->is->cmsb & HDLC_FED) {
- if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */
- pr_debug("%s: ISAR frame too short %d\n",
- ch->is->name, ch->bch.rx_skb->len);
- skb_trim(ch->bch.rx_skb, 0);
- break;
- }
- skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2);
- recv_Bchannel(&ch->bch, 0, false);
- }
- break;
- case ISDN_P_B_T30_FAX:
- if (ch->state != STFAX_ACTIV) {
- pr_debug("%s: isar_rcv_frame: not ACTIV\n",
- ch->is->name);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- if (ch->bch.rx_skb)
- skb_trim(ch->bch.rx_skb, 0);
- break;
- }
- if (!ch->bch.rx_skb) {
- ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen,
- GFP_ATOMIC);
- if (unlikely(!ch->bch.rx_skb)) {
- pr_info("%s: B receive out of memory\n",
- __func__);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- break;
- }
- }
- if (ch->cmd == PCTRL_CMD_FRM) {
- rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb));
- pr_debug("%s: isar_rcv_frame: %d\n",
- ch->is->name, ch->bch.rx_skb->len);
- if (ch->is->cmsb & SART_NMD) { /* ABORT */
- pr_debug("%s: isar_rcv_frame: no more data\n",
- ch->is->name);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- send_mbox(ch->is, SET_DPS(ch->dpath) |
- ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
- 0, NULL);
- ch->state = STFAX_ESCAPE;
- /* set_skb_flag(skb, DF_NOMOREDATA); */
- }
- recv_Bchannel(&ch->bch, 0, false);
- if (ch->is->cmsb & SART_NMD)
- deliver_status(ch, HW_MOD_NOCARR);
- break;
- }
- if (ch->cmd != PCTRL_CMD_FRH) {
- pr_debug("%s: isar_rcv_frame: unknown fax mode %x\n",
- ch->is->name, ch->cmd);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- if (ch->bch.rx_skb)
- skb_trim(ch->bch.rx_skb, 0);
- break;
- }
- /* PCTRL_CMD_FRH */
- if ((ch->bch.rx_skb->len + ch->is->clsb) >
- (ch->bch.maxlen + 2)) {
- pr_info("%s: %s incoming packet too large\n",
- ch->is->name, __func__);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- skb_trim(ch->bch.rx_skb, 0);
- break;
- } else if (ch->is->cmsb & HDLC_ERROR) {
- pr_info("%s: ISAR frame error %x len %d\n",
- ch->is->name, ch->is->cmsb, ch->is->clsb);
- skb_trim(ch->bch.rx_skb, 0);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- break;
- }
- if (ch->is->cmsb & HDLC_FSD)
- skb_trim(ch->bch.rx_skb, 0);
- ptr = skb_put(ch->bch.rx_skb, ch->is->clsb);
- rcv_mbox(ch->is, ptr);
- if (ch->is->cmsb & HDLC_FED) {
- if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */
- pr_info("%s: ISAR frame too short %d\n",
- ch->is->name, ch->bch.rx_skb->len);
- skb_trim(ch->bch.rx_skb, 0);
- break;
- }
- skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2);
- recv_Bchannel(&ch->bch, 0, false);
- }
- if (ch->is->cmsb & SART_NMD) { /* ABORT */
- pr_debug("%s: isar_rcv_frame: no more data\n",
- ch->is->name);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- if (ch->bch.rx_skb)
- skb_trim(ch->bch.rx_skb, 0);
- send_mbox(ch->is, SET_DPS(ch->dpath) |
- ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
- ch->state = STFAX_ESCAPE;
- deliver_status(ch, HW_MOD_NOCARR);
- }
- break;
- default:
- pr_info("isar_rcv_frame protocol (%x)error\n", ch->bch.state);
- ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
- break;
- }
-}
-
-static void
-isar_fill_fifo(struct isar_ch *ch)
-{
- int count;
- u8 msb;
- u8 *ptr;
-
- pr_debug("%s: ch%d tx_skb %d tx_idx %d\n", ch->is->name, ch->bch.nr,
- ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, ch->bch.tx_idx);
- if (!(ch->is->bstat &
- (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2)))
- return;
- if (!ch->bch.tx_skb) {
- if (!test_bit(FLG_TX_EMPTY, &ch->bch.Flags) ||
- (ch->bch.state != ISDN_P_B_RAW))
- return;
- count = ch->mml;
- /* use the card buffer */
- memset(ch->is->buf, ch->bch.fill[0], count);
- send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
- 0, count, ch->is->buf);
- return;
- }
- count = ch->bch.tx_skb->len - ch->bch.tx_idx;
- if (count <= 0)
- return;
- if (count > ch->mml) {
- msb = 0;
- count = ch->mml;
- } else {
- msb = HDLC_FED;
- }
- ptr = ch->bch.tx_skb->data + ch->bch.tx_idx;
- if (!ch->bch.tx_idx) {
- pr_debug("%s: frame start\n", ch->is->name);
- if ((ch->bch.state == ISDN_P_B_T30_FAX) &&
- (ch->cmd == PCTRL_CMD_FTH)) {
- if (count > 1) {
- if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) {
- /* last frame */
- test_and_set_bit(FLG_LASTDATA,
- &ch->bch.Flags);
- pr_debug("%s: set LASTDATA\n",
- ch->is->name);
- if (msb == HDLC_FED)
- test_and_set_bit(FLG_DLEETX,
- &ch->bch.Flags);
- }
- }
- }
- msb |= HDLC_FST;
- }
- ch->bch.tx_idx += count;
- switch (ch->bch.state) {
- case ISDN_P_NONE:
- pr_info("%s: wrong protocol 0\n", __func__);
- break;
- case ISDN_P_B_RAW:
- case ISDN_P_B_L2DTMF:
- case ISDN_P_B_MODEM_ASYNC:
- send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
- 0, count, ptr);
- break;
- case ISDN_P_B_HDLC:
- send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
- msb, count, ptr);
- break;
- case ISDN_P_B_T30_FAX:
- if (ch->state != STFAX_ACTIV)
- pr_debug("%s: not ACTIV\n", ch->is->name);
- else if (ch->cmd == PCTRL_CMD_FTH)
- send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
- msb, count, ptr);
- else if (ch->cmd == PCTRL_CMD_FTM)
- send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
- 0, count, ptr);
- else
- pr_debug("%s: not FTH/FTM\n", ch->is->name);
- break;
- default:
- pr_info("%s: protocol(%x) error\n",
- __func__, ch->bch.state);
- break;
- }
-}
-
-static inline struct isar_ch *
-sel_bch_isar(struct isar_hw *isar, u8 dpath)
-{
- struct isar_ch *base = &isar->ch[0];
-
- if ((!dpath) || (dpath > 2))
- return NULL;
- if (base->dpath == dpath)
- return base;
- base++;
- if (base->dpath == dpath)
- return base;
- return NULL;
-}
-
-static void
-send_next(struct isar_ch *ch)
-{
- pr_debug("%s: %s ch%d tx_skb %d tx_idx %d\n", ch->is->name, __func__,
- ch->bch.nr, ch->bch.tx_skb ? ch->bch.tx_skb->len : -1,
- ch->bch.tx_idx);
- if (ch->bch.state == ISDN_P_B_T30_FAX) {
- if (ch->cmd == PCTRL_CMD_FTH) {
- if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) {
- pr_debug("set NMD_DATA\n");
- test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags);
- }
- } else if (ch->cmd == PCTRL_CMD_FTM) {
- if (test_bit(FLG_DLEETX, &ch->bch.Flags)) {
- test_and_set_bit(FLG_LASTDATA, &ch->bch.Flags);
- test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags);
- }
- }
- }
- dev_kfree_skb(ch->bch.tx_skb);
- if (get_next_bframe(&ch->bch)) {
- isar_fill_fifo(ch);
- test_and_clear_bit(FLG_TX_EMPTY, &ch->bch.Flags);
- } else if (test_bit(FLG_TX_EMPTY, &ch->bch.Flags)) {
- isar_fill_fifo(ch);
- } else {
- if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) {
- if (test_and_clear_bit(FLG_LASTDATA,
- &ch->bch.Flags)) {
- if (test_and_clear_bit(FLG_NMD_DATA,
- &ch->bch.Flags)) {
- u8 zd = 0;
- send_mbox(ch->is, SET_DPS(ch->dpath) |
- ISAR_HIS_SDATA, 0x01, 1, &zd);
- }
- test_and_set_bit(FLG_LL_OK, &ch->bch.Flags);
- } else {
- deliver_status(ch, HW_MOD_CONNECT);
- }
- } else if (test_bit(FLG_FILLEMPTY, &ch->bch.Flags)) {
- test_and_set_bit(FLG_TX_EMPTY, &ch->bch.Flags);
- }
- }
-}
-
-static void
-check_send(struct isar_hw *isar, u8 rdm)
-{
- struct isar_ch *ch;
-
- pr_debug("%s: rdm %x\n", isar->name, rdm);
- if (rdm & BSTAT_RDM1) {
- ch = sel_bch_isar(isar, 1);
- if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) {
- if (ch->bch.tx_skb && (ch->bch.tx_skb->len >
- ch->bch.tx_idx))
- isar_fill_fifo(ch);
- else
- send_next(ch);
- }
- }
- if (rdm & BSTAT_RDM2) {
- ch = sel_bch_isar(isar, 2);
- if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) {
- if (ch->bch.tx_skb && (ch->bch.tx_skb->len >
- ch->bch.tx_idx))
- isar_fill_fifo(ch);
- else
- send_next(ch);
- }
- }
-}
-
-static const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4",
- "300", "600", "1200", "2400", "4800", "7200",
- "9600nt", "9600t", "12000", "14400", "WRONG"};
-static const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21",
- "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"};
-
-static void
-isar_pump_status_rsp(struct isar_ch *ch) {
- u8 ril = ch->is->buf[0];
- u8 rim;
-
- if (!test_and_clear_bit(ISAR_RATE_REQ, &ch->is->Flags))
- return;
- if (ril > 14) {
- pr_info("%s: wrong pstrsp ril=%d\n", ch->is->name, ril);
- ril = 15;
- }
- switch (ch->is->buf[1]) {
- case 0:
- rim = 0;
- break;
- case 0x20:
- rim = 2;
- break;
- case 0x40:
- rim = 3;
- break;
- case 0x41:
- rim = 4;
- break;
- case 0x51:
- rim = 5;
- break;
- case 0x61:
- rim = 6;
- break;
- case 0x71:
- rim = 7;
- break;
- case 0x82:
- rim = 8;
- break;
- case 0x92:
- rim = 9;
- break;
- case 0xa2:
- rim = 10;
- break;
- default:
- rim = 1;
- break;
- }
- sprintf(ch->conmsg, "%s %s", dmril[ril], dmrim[rim]);
- pr_debug("%s: pump strsp %s\n", ch->is->name, ch->conmsg);
-}
-
-static void
-isar_pump_statev_modem(struct isar_ch *ch, u8 devt) {
- u8 dps = SET_DPS(ch->dpath);
-
- switch (devt) {
- case PSEV_10MS_TIMER:
- pr_debug("%s: pump stev TIMER\n", ch->is->name);
- break;
- case PSEV_CON_ON:
- pr_debug("%s: pump stev CONNECT\n", ch->is->name);
- deliver_status(ch, HW_MOD_CONNECT);
- break;
- case PSEV_CON_OFF:
- pr_debug("%s: pump stev NO CONNECT\n", ch->is->name);
- send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
- deliver_status(ch, HW_MOD_NOCARR);
- break;
- case PSEV_V24_OFF:
- pr_debug("%s: pump stev V24 OFF\n", ch->is->name);
- break;
- case PSEV_CTS_ON:
- pr_debug("%s: pump stev CTS ON\n", ch->is->name);
- break;
- case PSEV_CTS_OFF:
- pr_debug("%s pump stev CTS OFF\n", ch->is->name);
- break;
- case PSEV_DCD_ON:
- pr_debug("%s: pump stev CARRIER ON\n", ch->is->name);
- test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags);
- send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
- break;
- case PSEV_DCD_OFF:
- pr_debug("%s: pump stev CARRIER OFF\n", ch->is->name);
- break;
- case PSEV_DSR_ON:
- pr_debug("%s: pump stev DSR ON\n", ch->is->name);
- break;
- case PSEV_DSR_OFF:
- pr_debug("%s: pump stev DSR_OFF\n", ch->is->name);
- break;
- case PSEV_REM_RET:
- pr_debug("%s: pump stev REMOTE RETRAIN\n", ch->is->name);
- break;
- case PSEV_REM_REN:
- pr_debug("%s: pump stev REMOTE RENEGOTIATE\n", ch->is->name);
- break;
- case PSEV_GSTN_CLR:
- pr_debug("%s: pump stev GSTN CLEAR\n", ch->is->name);
- break;
- default:
- pr_info("u%s: unknown pump stev %x\n", ch->is->name, devt);
- break;
- }
-}
-
-static void
-isar_pump_statev_fax(struct isar_ch *ch, u8 devt) {
- u8 dps = SET_DPS(ch->dpath);
- u8 p1;
-
- switch (devt) {
- case PSEV_10MS_TIMER:
- pr_debug("%s: pump stev TIMER\n", ch->is->name);
- break;
- case PSEV_RSP_READY:
- pr_debug("%s: pump stev RSP_READY\n", ch->is->name);
- ch->state = STFAX_READY;
- deliver_status(ch, HW_MOD_READY);
-#ifdef AUTOCON
- if (test_bit(BC_FLG_ORIG, &ch->bch.Flags))
- isar_pump_cmd(bch, HW_MOD_FRH, 3);
- else
- isar_pump_cmd(bch, HW_MOD_FTH, 3);
-#endif
- break;
- case PSEV_LINE_TX_H:
- if (ch->state == STFAX_LINE) {
- pr_debug("%s: pump stev LINE_TX_H\n", ch->is->name);
- ch->state = STFAX_CONT;
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
- PCTRL_CMD_CONT, 0, NULL);
- } else {
- pr_debug("%s: pump stev LINE_TX_H wrong st %x\n",
- ch->is->name, ch->state);
- }
- break;
- case PSEV_LINE_RX_H:
- if (ch->state == STFAX_LINE) {
- pr_debug("%s: pump stev LINE_RX_H\n", ch->is->name);
- ch->state = STFAX_CONT;
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
- PCTRL_CMD_CONT, 0, NULL);
- } else {
- pr_debug("%s: pump stev LINE_RX_H wrong st %x\n",
- ch->is->name, ch->state);
- }
- break;
- case PSEV_LINE_TX_B:
- if (ch->state == STFAX_LINE) {
- pr_debug("%s: pump stev LINE_TX_B\n", ch->is->name);
- ch->state = STFAX_CONT;
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
- PCTRL_CMD_CONT, 0, NULL);
- } else {
- pr_debug("%s: pump stev LINE_TX_B wrong st %x\n",
- ch->is->name, ch->state);
- }
- break;
- case PSEV_LINE_RX_B:
- if (ch->state == STFAX_LINE) {
- pr_debug("%s: pump stev LINE_RX_B\n", ch->is->name);
- ch->state = STFAX_CONT;
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
- PCTRL_CMD_CONT, 0, NULL);
- } else {
- pr_debug("%s: pump stev LINE_RX_B wrong st %x\n",
- ch->is->name, ch->state);
- }
- break;
- case PSEV_RSP_CONN:
- if (ch->state == STFAX_CONT) {
- pr_debug("%s: pump stev RSP_CONN\n", ch->is->name);
- ch->state = STFAX_ACTIV;
- test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags);
- send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
- if (ch->cmd == PCTRL_CMD_FTH) {
- int delay = (ch->mod == 3) ? 1000 : 200;
- /* 1s (200 ms) Flags before data */
- if (test_and_set_bit(FLG_FTI_RUN,
- &ch->bch.Flags))
- timer_delete(&ch->ftimer);
- ch->ftimer.expires =
- jiffies + ((delay * HZ) / 1000);
- test_and_set_bit(FLG_LL_CONN,
- &ch->bch.Flags);
- add_timer(&ch->ftimer);
- } else {
- deliver_status(ch, HW_MOD_CONNECT);
- }
- } else {
- pr_debug("%s: pump stev RSP_CONN wrong st %x\n",
- ch->is->name, ch->state);
- }
- break;
- case PSEV_FLAGS_DET:
- pr_debug("%s: pump stev FLAGS_DET\n", ch->is->name);
- break;
- case PSEV_RSP_DISC:
- pr_debug("%s: pump stev RSP_DISC state(%d)\n",
- ch->is->name, ch->state);
- if (ch->state == STFAX_ESCAPE) {
- p1 = 5;
- switch (ch->newcmd) {
- case 0:
- ch->state = STFAX_READY;
- break;
- case PCTRL_CMD_FTM:
- p1 = 2;
- fallthrough;
- case PCTRL_CMD_FTH:
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
- PCTRL_CMD_SILON, 1, &p1);
- ch->state = STFAX_SILDET;
- break;
- case PCTRL_CMD_FRH:
- case PCTRL_CMD_FRM:
- ch->mod = ch->newmod;
- p1 = ch->newmod;
- ch->newmod = 0;
- ch->cmd = ch->newcmd;
- ch->newcmd = 0;
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
- ch->cmd, 1, &p1);
- ch->state = STFAX_LINE;
- ch->try_mod = 3;
- break;
- default:
- pr_debug("%s: RSP_DISC unknown newcmd %x\n",
- ch->is->name, ch->newcmd);
- break;
- }
- } else if (ch->state == STFAX_ACTIV) {
- if (test_and_clear_bit(FLG_LL_OK, &ch->bch.Flags))
- deliver_status(ch, HW_MOD_OK);
- else if (ch->cmd == PCTRL_CMD_FRM)
- deliver_status(ch, HW_MOD_NOCARR);
- else
- deliver_status(ch, HW_MOD_FCERROR);
- ch->state = STFAX_READY;
- } else if (ch->state != STFAX_SILDET) {
- /* ignore in STFAX_SILDET */
- ch->state = STFAX_READY;
- deliver_status(ch, HW_MOD_FCERROR);
- }
- break;
- case PSEV_RSP_SILDET:
- pr_debug("%s: pump stev RSP_SILDET\n", ch->is->name);
- if (ch->state == STFAX_SILDET) {
- ch->mod = ch->newmod;
- p1 = ch->newmod;
- ch->newmod = 0;
- ch->cmd = ch->newcmd;
- ch->newcmd = 0;
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
- ch->cmd, 1, &p1);
- ch->state = STFAX_LINE;
- ch->try_mod = 3;
- }
- break;
- case PSEV_RSP_SILOFF:
- pr_debug("%s: pump stev RSP_SILOFF\n", ch->is->name);
- break;
- case PSEV_RSP_FCERR:
- if (ch->state == STFAX_LINE) {
- pr_debug("%s: pump stev RSP_FCERR try %d\n",
- ch->is->name, ch->try_mod);
- if (ch->try_mod--) {
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
- ch->cmd, 1, &ch->mod);
- break;
- }
- }
- pr_debug("%s: pump stev RSP_FCERR\n", ch->is->name);
- ch->state = STFAX_ESCAPE;
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
- 0, NULL);
- deliver_status(ch, HW_MOD_FCERROR);
- break;
- default:
- break;
- }
-}
-
-void
-mISDNisar_irq(struct isar_hw *isar)
-{
- struct isar_ch *ch;
-
- get_irq_infos(isar);
- switch (isar->iis & ISAR_IIS_MSCMSD) {
- case ISAR_IIS_RDATA:
- ch = sel_bch_isar(isar, isar->iis >> 6);
- if (ch)
- isar_rcv_frame(ch);
- else {
- pr_debug("%s: ISAR spurious IIS_RDATA %x/%x/%x\n",
- isar->name, isar->iis, isar->cmsb,
- isar->clsb);
- isar->write_reg(isar->hw, ISAR_IIA, 0);
- }
- break;
- case ISAR_IIS_GSTEV:
- isar->write_reg(isar->hw, ISAR_IIA, 0);
- isar->bstat |= isar->cmsb;
- check_send(isar, isar->cmsb);
- break;
- case ISAR_IIS_BSTEV:
-#ifdef ERROR_STATISTIC
- ch = sel_bch_isar(isar, isar->iis >> 6);
- if (ch) {
- if (isar->cmsb == BSTEV_TBO)
- ch->bch.err_tx++;
- if (isar->cmsb == BSTEV_RBO)
- ch->bch.err_rdo++;
- }
-#endif
- pr_debug("%s: Buffer STEV dpath%d msb(%x)\n",
- isar->name, isar->iis >> 6, isar->cmsb);
- isar->write_reg(isar->hw, ISAR_IIA, 0);
- break;
- case ISAR_IIS_PSTEV:
- ch = sel_bch_isar(isar, isar->iis >> 6);
- if (ch) {
- rcv_mbox(isar, NULL);
- if (ch->bch.state == ISDN_P_B_MODEM_ASYNC)
- isar_pump_statev_modem(ch, isar->cmsb);
- else if (ch->bch.state == ISDN_P_B_T30_FAX)
- isar_pump_statev_fax(ch, isar->cmsb);
- else if (ch->bch.state == ISDN_P_B_RAW) {
- int tt;
- tt = isar->cmsb | 0x30;
- if (tt == 0x3e)
- tt = '*';
- else if (tt == 0x3f)
- tt = '#';
- else if (tt > '9')
- tt += 7;
- tt |= DTMF_TONE_VAL;
- _queue_data(&ch->bch.ch, PH_CONTROL_IND,
- MISDN_ID_ANY, sizeof(tt), &tt,
- GFP_ATOMIC);
- } else
- pr_debug("%s: ISAR IIS_PSTEV pm %d sta %x\n",
- isar->name, ch->bch.state,
- isar->cmsb);
- } else {
- pr_debug("%s: ISAR spurious IIS_PSTEV %x/%x/%x\n",
- isar->name, isar->iis, isar->cmsb,
- isar->clsb);
- isar->write_reg(isar->hw, ISAR_IIA, 0);
- }
- break;
- case ISAR_IIS_PSTRSP:
- ch = sel_bch_isar(isar, isar->iis >> 6);
- if (ch) {
- rcv_mbox(isar, NULL);
- isar_pump_status_rsp(ch);
- } else {
- pr_debug("%s: ISAR spurious IIS_PSTRSP %x/%x/%x\n",
- isar->name, isar->iis, isar->cmsb,
- isar->clsb);
- isar->write_reg(isar->hw, ISAR_IIA, 0);
- }
- break;
- case ISAR_IIS_DIAG:
- case ISAR_IIS_BSTRSP:
- case ISAR_IIS_IOM2RSP:
- rcv_mbox(isar, NULL);
- break;
- case ISAR_IIS_INVMSG:
- rcv_mbox(isar, NULL);
- pr_debug("%s: invalid msg his:%x\n", isar->name, isar->cmsb);
- break;
- default:
- rcv_mbox(isar, NULL);
- pr_debug("%s: unhandled msg iis(%x) ctrl(%x/%x)\n",
- isar->name, isar->iis, isar->cmsb, isar->clsb);
- break;
- }
-}
-EXPORT_SYMBOL(mISDNisar_irq);
-
-static void
-ftimer_handler(struct timer_list *t)
-{
- struct isar_ch *ch = timer_container_of(ch, t, ftimer);
-
- pr_debug("%s: ftimer flags %lx\n", ch->is->name, ch->bch.Flags);
- test_and_clear_bit(FLG_FTI_RUN, &ch->bch.Flags);
- if (test_and_clear_bit(FLG_LL_CONN, &ch->bch.Flags))
- deliver_status(ch, HW_MOD_CONNECT);
-}
-
-static void
-setup_pump(struct isar_ch *ch) {
- u8 dps = SET_DPS(ch->dpath);
- u8 ctrl, param[6];
-
- switch (ch->bch.state) {
- case ISDN_P_NONE:
- case ISDN_P_B_RAW:
- case ISDN_P_B_HDLC:
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL);
- break;
- case ISDN_P_B_L2DTMF:
- if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) {
- param[0] = 5; /* TOA 5 db */
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG,
- PMOD_DTMF_TRANS, 1, param);
- } else {
- param[0] = 40; /* REL -46 dbm */
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG,
- PMOD_DTMF, 1, param);
- }
- fallthrough;
- case ISDN_P_B_MODEM_ASYNC:
- ctrl = PMOD_DATAMODEM;
- if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) {
- ctrl |= PCTRL_ORIG;
- param[5] = PV32P6_CTN;
- } else {
- param[5] = PV32P6_ATN;
- }
- param[0] = 6; /* 6 db */
- param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
- PV32P2_V22C | PV32P2_V21 | PV32P2_BEL;
- param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
- param[3] = PV32P4_UT144;
- param[4] = PV32P5_UT144;
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param);
- break;
- case ISDN_P_B_T30_FAX:
- ctrl = PMOD_FAX;
- if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) {
- ctrl |= PCTRL_ORIG;
- param[1] = PFAXP2_CTN;
- } else {
- param[1] = PFAXP2_ATN;
- }
- param[0] = 6; /* 6 db */
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
- ch->state = STFAX_NULL;
- ch->newcmd = 0;
- ch->newmod = 0;
- test_and_set_bit(FLG_FTI_RUN, &ch->bch.Flags);
- break;
- }
- udelay(1000);
- send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
- udelay(1000);
-}
-
-static void
-setup_sart(struct isar_ch *ch) {
- u8 dps = SET_DPS(ch->dpath);
- u8 ctrl, param[2] = {0, 0};
-
- switch (ch->bch.state) {
- case ISDN_P_NONE:
- send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE,
- 0, NULL);
- break;
- case ISDN_P_B_RAW:
- case ISDN_P_B_L2DTMF:
- send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_BINARY,
- 2, param);
- break;
- case ISDN_P_B_HDLC:
- case ISDN_P_B_T30_FAX:
- send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_HDLC,
- 1, param);
- break;
- case ISDN_P_B_MODEM_ASYNC:
- ctrl = SMODE_V14 | SCTRL_HDMC_BOTH;
- param[0] = S_P1_CHS_8;
- param[1] = S_P2_BFT_DEF;
- send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, ctrl, 2, param);
- break;
- }
- udelay(1000);
- send_mbox(ch->is, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
- udelay(1000);
-}
-
-static void
-setup_iom2(struct isar_ch *ch) {
- u8 dps = SET_DPS(ch->dpath);
- u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0};
-
- if (ch->bch.nr == 2) {
- msg[1] = 1;
- msg[3] = 1;
- }
- switch (ch->bch.state) {
- case ISDN_P_NONE:
- cmsb = 0;
- /* dummy slot */
- msg[1] = ch->dpath + 2;
- msg[3] = ch->dpath + 2;
- break;
- case ISDN_P_B_RAW:
- case ISDN_P_B_HDLC:
- break;
- case ISDN_P_B_MODEM_ASYNC:
- case ISDN_P_B_T30_FAX:
- cmsb |= IOM_CTRL_RCV;
- fallthrough;
- case ISDN_P_B_L2DTMF:
- if (test_bit(FLG_DTMFSEND, &ch->bch.Flags))
- cmsb |= IOM_CTRL_RCV;
- cmsb |= IOM_CTRL_ALAW;
- break;
- }
- send_mbox(ch->is, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg);
- udelay(1000);
- send_mbox(ch->is, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL);
- udelay(1000);
-}
-
-static int
-modeisar(struct isar_ch *ch, u32 bprotocol)
-{
- /* Here we are selecting the best datapath for requested protocol */
- if (ch->bch.state == ISDN_P_NONE) { /* New Setup */
- switch (bprotocol) {
- case ISDN_P_NONE: /* init */
- if (!ch->dpath)
- /* no init for dpath 0 */
- return 0;
- test_and_clear_bit(FLG_HDLC, &ch->bch.Flags);
- test_and_clear_bit(FLG_TRANSPARENT, &ch->bch.Flags);
- break;
- case ISDN_P_B_RAW:
- case ISDN_P_B_HDLC:
- /* best is datapath 2 */
- if (!test_and_set_bit(ISAR_DP2_USE, &ch->is->Flags))
- ch->dpath = 2;
- else if (!test_and_set_bit(ISAR_DP1_USE,
- &ch->is->Flags))
- ch->dpath = 1;
- else {
- pr_info("modeisar both paths in use\n");
- return -EBUSY;
- }
- if (bprotocol == ISDN_P_B_HDLC)
- test_and_set_bit(FLG_HDLC, &ch->bch.Flags);
- else
- test_and_set_bit(FLG_TRANSPARENT,
- &ch->bch.Flags);
- break;
- case ISDN_P_B_MODEM_ASYNC:
- case ISDN_P_B_T30_FAX:
- case ISDN_P_B_L2DTMF:
- /* only datapath 1 */
- if (!test_and_set_bit(ISAR_DP1_USE, &ch->is->Flags))
- ch->dpath = 1;
- else {
- pr_info("%s: ISAR modeisar analog functions"
- "only with DP1\n", ch->is->name);
- return -EBUSY;
- }
- break;
- default:
- pr_info("%s: protocol not known %x\n", ch->is->name,
- bprotocol);
- return -ENOPROTOOPT;
- }
- }
- pr_debug("%s: ISAR ch%d dp%d protocol %x->%x\n", ch->is->name,
- ch->bch.nr, ch->dpath, ch->bch.state, bprotocol);
- ch->bch.state = bprotocol;
- setup_pump(ch);
- setup_iom2(ch);
- setup_sart(ch);
- if (ch->bch.state == ISDN_P_NONE) {
- /* Clear resources */
- if (ch->dpath == 1)
- test_and_clear_bit(ISAR_DP1_USE, &ch->is->Flags);
- else if (ch->dpath == 2)
- test_and_clear_bit(ISAR_DP2_USE, &ch->is->Flags);
- ch->dpath = 0;
- ch->is->ctrl(ch->is->hw, HW_DEACT_IND, ch->bch.nr);
- } else
- ch->is->ctrl(ch->is->hw, HW_ACTIVATE_IND, ch->bch.nr);
- return 0;
-}
-
-static void
-isar_pump_cmd(struct isar_ch *ch, u32 cmd, u8 para)
-{
- u8 dps = SET_DPS(ch->dpath);
- u8 ctrl = 0, nom = 0, p1 = 0;
-
- pr_debug("%s: isar_pump_cmd %x/%x state(%x)\n",
- ch->is->name, cmd, para, ch->bch.state);
- switch (cmd) {
- case HW_MOD_FTM:
- if (ch->state == STFAX_READY) {
- p1 = para;
- ctrl = PCTRL_CMD_FTM;
- nom = 1;
- ch->state = STFAX_LINE;
- ch->cmd = ctrl;
- ch->mod = para;
- ch->newmod = 0;
- ch->newcmd = 0;
- ch->try_mod = 3;
- } else if ((ch->state == STFAX_ACTIV) &&
- (ch->cmd == PCTRL_CMD_FTM) && (ch->mod == para))
- deliver_status(ch, HW_MOD_CONNECT);
- else {
- ch->newmod = para;
- ch->newcmd = PCTRL_CMD_FTM;
- nom = 0;
- ctrl = PCTRL_CMD_ESC;
- ch->state = STFAX_ESCAPE;
- }
- break;
- case HW_MOD_FTH:
- if (ch->state == STFAX_READY) {
- p1 = para;
- ctrl = PCTRL_CMD_FTH;
- nom = 1;
- ch->state = STFAX_LINE;
- ch->cmd = ctrl;
- ch->mod = para;
- ch->newmod = 0;
- ch->newcmd = 0;
- ch->try_mod = 3;
- } else if ((ch->state == STFAX_ACTIV) &&
- (ch->cmd == PCTRL_CMD_FTH) && (ch->mod == para))
- deliver_status(ch, HW_MOD_CONNECT);
- else {
- ch->newmod = para;
- ch->newcmd = PCTRL_CMD_FTH;
- nom = 0;
- ctrl = PCTRL_CMD_ESC;
- ch->state = STFAX_ESCAPE;
- }
- break;
- case HW_MOD_FRM:
- if (ch->state == STFAX_READY) {
- p1 = para;
- ctrl = PCTRL_CMD_FRM;
- nom = 1;
- ch->state = STFAX_LINE;
- ch->cmd = ctrl;
- ch->mod = para;
- ch->newmod = 0;
- ch->newcmd = 0;
- ch->try_mod = 3;
- } else if ((ch->state == STFAX_ACTIV) &&
- (ch->cmd == PCTRL_CMD_FRM) && (ch->mod == para))
- deliver_status(ch, HW_MOD_CONNECT);
- else {
- ch->newmod = para;
- ch->newcmd = PCTRL_CMD_FRM;
- nom = 0;
- ctrl = PCTRL_CMD_ESC;
- ch->state = STFAX_ESCAPE;
- }
- break;
- case HW_MOD_FRH:
- if (ch->state == STFAX_READY) {
- p1 = para;
- ctrl = PCTRL_CMD_FRH;
- nom = 1;
- ch->state = STFAX_LINE;
- ch->cmd = ctrl;
- ch->mod = para;
- ch->newmod = 0;
- ch->newcmd = 0;
- ch->try_mod = 3;
- } else if ((ch->state == STFAX_ACTIV) &&
- (ch->cmd == PCTRL_CMD_FRH) && (ch->mod == para))
- deliver_status(ch, HW_MOD_CONNECT);
- else {
- ch->newmod = para;
- ch->newcmd = PCTRL_CMD_FRH;
- nom = 0;
- ctrl = PCTRL_CMD_ESC;
- ch->state = STFAX_ESCAPE;
- }
- break;
- case PCTRL_CMD_TDTMF:
- p1 = para;
- nom = 1;
- ctrl = PCTRL_CMD_TDTMF;
- break;
- }
- if (ctrl)
- send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
-}
-
-static void
-isar_setup(struct isar_hw *isar)
-{
- u8 msg;
- int i;
-
- /* Dpath 1, 2 */
- msg = 61;
- for (i = 0; i < 2; i++) {
- /* Buffer Config */
- send_mbox(isar, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
- ISAR_HIS_P12CFG, 4, 1, &msg);
- isar->ch[i].mml = msg;
- isar->ch[i].bch.state = 0;
- isar->ch[i].dpath = i + 1;
- modeisar(&isar->ch[i], ISDN_P_NONE);
- }
-}
-
-static int
-isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct isar_ch *ich = container_of(bch, struct isar_ch, bch);
- int ret = -EINVAL;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- u32 id, *val;
- u_long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- spin_lock_irqsave(ich->is->hwlock, flags);
- ret = bchannel_senddata(bch, skb);
- if (ret > 0) { /* direct TX */
- ret = 0;
- isar_fill_fifo(ich);
- }
- spin_unlock_irqrestore(ich->is->hwlock, flags);
- return ret;
- case PH_ACTIVATE_REQ:
- spin_lock_irqsave(ich->is->hwlock, flags);
- if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
- ret = modeisar(ich, ch->protocol);
- else
- ret = 0;
- spin_unlock_irqrestore(ich->is->hwlock, flags);
- if (!ret)
- _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- break;
- case PH_DEACTIVATE_REQ:
- spin_lock_irqsave(ich->is->hwlock, flags);
- mISDN_clear_bchannel(bch);
- modeisar(ich, ISDN_P_NONE);
- spin_unlock_irqrestore(ich->is->hwlock, flags);
- _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- ret = 0;
- break;
- case PH_CONTROL_REQ:
- val = (u32 *)skb->data;
- pr_debug("%s: PH_CONTROL | REQUEST %x/%x\n", ich->is->name,
- hh->id, *val);
- if ((hh->id == 0) && ((*val & ~DTMF_TONE_MASK) ==
- DTMF_TONE_VAL)) {
- if (bch->state == ISDN_P_B_L2DTMF) {
- char tt = *val & DTMF_TONE_MASK;
-
- if (tt == '*')
- tt = 0x1e;
- else if (tt == '#')
- tt = 0x1f;
- else if (tt > '9')
- tt -= 7;
- tt &= 0x1f;
- spin_lock_irqsave(ich->is->hwlock, flags);
- isar_pump_cmd(ich, PCTRL_CMD_TDTMF, tt);
- spin_unlock_irqrestore(ich->is->hwlock, flags);
- } else {
- pr_info("%s: DTMF send wrong protocol %x\n",
- __func__, bch->state);
- return -EINVAL;
- }
- } else if ((hh->id == HW_MOD_FRM) || (hh->id == HW_MOD_FRH) ||
- (hh->id == HW_MOD_FTM) || (hh->id == HW_MOD_FTH)) {
- for (id = 0; id < FAXMODCNT; id++)
- if (faxmodulation[id] == *val)
- break;
- if ((FAXMODCNT > id) &&
- test_bit(FLG_INITIALIZED, &bch->Flags)) {
- pr_debug("%s: isar: new mod\n", ich->is->name);
- isar_pump_cmd(ich, hh->id, *val);
- ret = 0;
- } else {
- pr_info("%s: wrong modulation\n",
- ich->is->name);
- ret = -EINVAL;
- }
- } else if (hh->id == HW_MOD_LASTDATA)
- test_and_set_bit(FLG_DLEETX, &bch->Flags);
- else {
- pr_info("%s: unknown PH_CONTROL_REQ %x\n",
- ich->is->name, hh->id);
- ret = -EINVAL;
- }
- fallthrough;
- default:
- pr_info("%s: %s unknown prim(%x,%x)\n",
- ich->is->name, __func__, hh->prim, hh->id);
- ret = -EINVAL;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static int
-channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
-{
- return mISDN_ctrl_bchannel(bch, cq);
-}
-
-static int
-isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct isar_ch *ich = container_of(bch, struct isar_ch, bch);
- int ret = -EINVAL;
- u_long flags;
-
- pr_debug("%s: %s cmd:%x %p\n", ich->is->name, __func__, cmd, arg);
- switch (cmd) {
- case CLOSE_CHANNEL:
- test_and_clear_bit(FLG_OPEN, &bch->Flags);
- cancel_work_sync(&bch->workq);
- spin_lock_irqsave(ich->is->hwlock, flags);
- mISDN_clear_bchannel(bch);
- modeisar(ich, ISDN_P_NONE);
- spin_unlock_irqrestore(ich->is->hwlock, flags);
- ch->protocol = ISDN_P_NONE;
- ch->peer = NULL;
- module_put(ich->is->owner);
- ret = 0;
- break;
- case CONTROL_CHANNEL:
- ret = channel_bctrl(bch, arg);
- break;
- default:
- pr_info("%s: %s unknown prim(%x)\n",
- ich->is->name, __func__, cmd);
- }
- return ret;
-}
-
-static void
-free_isar(struct isar_hw *isar)
-{
- modeisar(&isar->ch[0], ISDN_P_NONE);
- modeisar(&isar->ch[1], ISDN_P_NONE);
- timer_delete(&isar->ch[0].ftimer);
- timer_delete(&isar->ch[1].ftimer);
- test_and_clear_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags);
- test_and_clear_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags);
-}
-
-static int
-init_isar(struct isar_hw *isar)
-{
- int cnt = 3;
-
- while (cnt--) {
- isar->version = ISARVersion(isar);
- if (isar->ch[0].bch.debug & DEBUG_HW)
- pr_notice("%s: Testing version %d (%d time)\n",
- isar->name, isar->version, 3 - cnt);
- if (isar->version == 1)
- break;
- isar->ctrl(isar->hw, HW_RESET_REQ, 0);
- }
- if (isar->version != 1)
- return -EINVAL;
- timer_setup(&isar->ch[0].ftimer, ftimer_handler, 0);
- test_and_set_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags);
- timer_setup(&isar->ch[1].ftimer, ftimer_handler, 0);
- test_and_set_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags);
- return 0;
-}
-
-static int
-isar_open(struct isar_hw *isar, struct channel_req *rq)
-{
- struct bchannel *bch;
-
- if (rq->adr.channel == 0 || rq->adr.channel > 2)
- return -EINVAL;
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
- bch = &isar->ch[rq->adr.channel - 1].bch;
- if (test_and_set_bit(FLG_OPEN, &bch->Flags))
- return -EBUSY; /* b-channel can be only open once */
- bch->ch.protocol = rq->protocol;
- rq->ch = &bch->ch;
- return 0;
-}
-
-u32
-mISDNisar_init(struct isar_hw *isar, void *hw)
-{
- u32 ret, i;
-
- isar->hw = hw;
- for (i = 0; i < 2; i++) {
- isar->ch[i].bch.nr = i + 1;
- mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM, 32);
- isar->ch[i].bch.ch.nr = i + 1;
- isar->ch[i].bch.ch.send = &isar_l2l1;
- isar->ch[i].bch.ch.ctrl = isar_bctrl;
- isar->ch[i].bch.hw = hw;
- isar->ch[i].is = isar;
- }
-
- isar->init = &init_isar;
- isar->release = &free_isar;
- isar->firmware = &load_firmware;
- isar->open = &isar_open;
-
- ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_L2DTMF & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_MODEM_ASYNC & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_T30_FAX & ISDN_P_B_MASK));
-
- return ret;
-}
-EXPORT_SYMBOL(mISDNisar_init);
-
-static int __init isar_mod_init(void)
-{
- pr_notice("mISDN: ISAR driver Rev. %s\n", ISAR_REV);
- return 0;
-}
-
-static void __exit isar_mod_cleanup(void)
-{
- pr_notice("mISDN: ISAR module unloaded\n");
-}
-module_init(isar_mod_init);
-module_exit(isar_mod_cleanup);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * NETJet mISDN driver
- *
- * Author Karsten Keil <keil@isdn4linux.de>
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/mISDNhw.h>
-#include <linux/slab.h>
-#include "ipac.h"
-#include "iohelper.h"
-#include "netjet.h"
-#include "isdnhdlc.h"
-
-#define NETJET_REV "2.0"
-
-enum nj_types {
- NETJET_S_TJ300,
- NETJET_S_TJ320,
- ENTERNOW__TJ320,
-};
-
-struct tiger_dma {
- size_t size;
- u32 *start;
- int idx;
- u32 dmastart;
- u32 dmairq;
- u32 dmaend;
- u32 dmacur;
-};
-
-struct tiger_hw;
-
-struct tiger_ch {
- struct bchannel bch;
- struct tiger_hw *nj;
- int idx;
- int free;
- int lastrx;
- u16 rxstate;
- u16 txstate;
- struct isdnhdlc_vars hsend;
- struct isdnhdlc_vars hrecv;
- u8 *hsbuf;
- u8 *hrbuf;
-};
-
-#define TX_INIT 0x0001
-#define TX_IDLE 0x0002
-#define TX_RUN 0x0004
-#define TX_UNDERRUN 0x0100
-#define RX_OVERRUN 0x0100
-
-#define LOG_SIZE 64
-
-struct tiger_hw {
- struct list_head list;
- struct pci_dev *pdev;
- char name[MISDN_MAX_IDLEN];
- enum nj_types typ;
- int irq;
- u32 irqcnt;
- u32 base;
- size_t base_s;
- dma_addr_t dma;
- void *dma_p;
- spinlock_t lock; /* lock HW */
- struct isac_hw isac;
- struct tiger_dma send;
- struct tiger_dma recv;
- struct tiger_ch bc[2];
- u8 ctrlreg;
- u8 dmactrl;
- u8 auxd;
- u8 last_is0;
- u8 irqmask0;
- char log[LOG_SIZE];
-};
-
-static LIST_HEAD(Cards);
-static DEFINE_RWLOCK(card_lock); /* protect Cards */
-static u32 debug;
-static int nj_cnt;
-
-static void
-_set_debug(struct tiger_hw *card)
-{
- card->isac.dch.debug = debug;
- card->bc[0].bch.debug = debug;
- card->bc[1].bch.debug = debug;
-}
-
-static int
-set_debug(const char *val, const struct kernel_param *kp)
-{
- int ret;
- struct tiger_hw *card;
-
- ret = param_set_uint(val, kp);
- if (!ret) {
- read_lock(&card_lock);
- list_for_each_entry(card, &Cards, list)
- _set_debug(card);
- read_unlock(&card_lock);
- }
- return ret;
-}
-
-MODULE_AUTHOR("Karsten Keil");
-MODULE_DESCRIPTION("mISDN driver for NETJet cards");
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION(NETJET_REV);
-module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Netjet debug mask");
-
-static void
-nj_disable_hwirq(struct tiger_hw *card)
-{
- outb(0, card->base + NJ_IRQMASK0);
- outb(0, card->base + NJ_IRQMASK1);
-}
-
-
-static u8
-ReadISAC_nj(void *p, u8 offset)
-{
- struct tiger_hw *card = p;
- u8 ret;
-
- card->auxd &= 0xfc;
- card->auxd |= (offset >> 4) & 3;
- outb(card->auxd, card->base + NJ_AUXDATA);
- ret = inb(card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));
- return ret;
-}
-
-static void
-WriteISAC_nj(void *p, u8 offset, u8 value)
-{
- struct tiger_hw *card = p;
-
- card->auxd &= 0xfc;
- card->auxd |= (offset >> 4) & 3;
- outb(card->auxd, card->base + NJ_AUXDATA);
- outb(value, card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));
-}
-
-static void
-ReadFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)
-{
- struct tiger_hw *card = p;
-
- card->auxd &= 0xfc;
- outb(card->auxd, card->base + NJ_AUXDATA);
- insb(card->base + NJ_ISAC_OFF, data, size);
-}
-
-static void
-WriteFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)
-{
- struct tiger_hw *card = p;
-
- card->auxd &= 0xfc;
- outb(card->auxd, card->base + NJ_AUXDATA);
- outsb(card->base + NJ_ISAC_OFF, data, size);
-}
-
-static void
-fill_mem(struct tiger_ch *bc, u32 idx, u32 cnt, u32 fill)
-{
- struct tiger_hw *card = bc->bch.hw;
- u32 mask = 0xff, val;
-
- pr_debug("%s: B%1d fill %02x len %d idx %d/%d\n", card->name,
- bc->bch.nr, fill, cnt, idx, card->send.idx);
- if (bc->bch.nr & 2) {
- fill <<= 8;
- mask <<= 8;
- }
- mask ^= 0xffffffff;
- while (cnt--) {
- val = card->send.start[idx];
- val &= mask;
- val |= fill;
- card->send.start[idx++] = val;
- if (idx >= card->send.size)
- idx = 0;
- }
-}
-
-static int
-mode_tiger(struct tiger_ch *bc, u32 protocol)
-{
- struct tiger_hw *card = bc->bch.hw;
-
- pr_debug("%s: B%1d protocol %x-->%x\n", card->name,
- bc->bch.nr, bc->bch.state, protocol);
- switch (protocol) {
- case ISDN_P_NONE:
- if (bc->bch.state == ISDN_P_NONE)
- break;
- fill_mem(bc, 0, card->send.size, 0xff);
- bc->bch.state = protocol;
- /* only stop dma and interrupts if both channels NULL */
- if ((card->bc[0].bch.state == ISDN_P_NONE) &&
- (card->bc[1].bch.state == ISDN_P_NONE)) {
- card->dmactrl = 0;
- outb(card->dmactrl, card->base + NJ_DMACTRL);
- outb(0, card->base + NJ_IRQMASK0);
- }
- test_and_clear_bit(FLG_HDLC, &bc->bch.Flags);
- test_and_clear_bit(FLG_TRANSPARENT, &bc->bch.Flags);
- bc->txstate = 0;
- bc->rxstate = 0;
- bc->lastrx = -1;
- break;
- case ISDN_P_B_RAW:
- test_and_set_bit(FLG_TRANSPARENT, &bc->bch.Flags);
- bc->bch.state = protocol;
- bc->idx = 0;
- bc->free = card->send.size / 2;
- bc->rxstate = 0;
- bc->txstate = TX_INIT | TX_IDLE;
- bc->lastrx = -1;
- if (!card->dmactrl) {
- card->dmactrl = 1;
- outb(card->dmactrl, card->base + NJ_DMACTRL);
- outb(0x0f, card->base + NJ_IRQMASK0);
- }
- break;
- case ISDN_P_B_HDLC:
- test_and_set_bit(FLG_HDLC, &bc->bch.Flags);
- bc->bch.state = protocol;
- bc->idx = 0;
- bc->free = card->send.size / 2;
- bc->rxstate = 0;
- bc->txstate = TX_INIT | TX_IDLE;
- isdnhdlc_rcv_init(&bc->hrecv, 0);
- isdnhdlc_out_init(&bc->hsend, 0);
- bc->lastrx = -1;
- if (!card->dmactrl) {
- card->dmactrl = 1;
- outb(card->dmactrl, card->base + NJ_DMACTRL);
- outb(0x0f, card->base + NJ_IRQMASK0);
- }
- break;
- default:
- pr_info("%s: %s protocol %x not handled\n", card->name,
- __func__, protocol);
- return -ENOPROTOOPT;
- }
- card->send.dmacur = inl(card->base + NJ_DMA_READ_ADR);
- card->recv.dmacur = inl(card->base + NJ_DMA_WRITE_ADR);
- card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
- card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;
- pr_debug("%s: %s ctrl %x irq %02x/%02x idx %d/%d\n",
- card->name, __func__,
- inb(card->base + NJ_DMACTRL),
- inb(card->base + NJ_IRQMASK0),
- inb(card->base + NJ_IRQSTAT0),
- card->send.idx,
- card->recv.idx);
- return 0;
-}
-
-static void
-nj_reset(struct tiger_hw *card)
-{
- outb(0xff, card->base + NJ_CTRL); /* Reset On */
- mdelay(1);
-
- /* now edge triggered for TJ320 GE 13/07/00 */
- /* see comment in IRQ function */
- if (card->typ == NETJET_S_TJ320) /* TJ320 */
- card->ctrlreg = 0x40; /* Reset Off and status read clear */
- else
- card->ctrlreg = 0x00; /* Reset Off and status read clear */
- outb(card->ctrlreg, card->base + NJ_CTRL);
- mdelay(10);
-
- /* configure AUX pins (all output except ISAC IRQ pin) */
- card->auxd = 0;
- card->dmactrl = 0;
- outb(~NJ_ISACIRQ, card->base + NJ_AUXCTRL);
- outb(NJ_ISACIRQ, card->base + NJ_IRQMASK1);
- outb(card->auxd, card->base + NJ_AUXDATA);
-}
-
-static int
-inittiger(struct tiger_hw *card)
-{
- int i;
-
- card->dma_p = dma_alloc_coherent(&card->pdev->dev, NJ_DMA_SIZE,
- &card->dma, GFP_ATOMIC);
- if (!card->dma_p) {
- pr_info("%s: No DMA memory\n", card->name);
- return -ENOMEM;
- }
- if ((u64)card->dma > 0xffffffff) {
- pr_info("%s: DMA outside 32 bit\n", card->name);
- return -ENOMEM;
- }
- for (i = 0; i < 2; i++) {
- card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_ATOMIC);
- if (!card->bc[i].hsbuf) {
- pr_info("%s: no B%d send buffer\n", card->name, i + 1);
- return -ENOMEM;
- }
- card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_ATOMIC);
- if (!card->bc[i].hrbuf) {
- pr_info("%s: no B%d recv buffer\n", card->name, i + 1);
- return -ENOMEM;
- }
- }
- memset(card->dma_p, 0xff, NJ_DMA_SIZE);
-
- card->send.start = card->dma_p;
- card->send.dmastart = (u32)card->dma;
- card->send.dmaend = card->send.dmastart +
- (4 * (NJ_DMA_TXSIZE - 1));
- card->send.dmairq = card->send.dmastart +
- (4 * ((NJ_DMA_TXSIZE / 2) - 1));
- card->send.size = NJ_DMA_TXSIZE;
-
- if (debug & DEBUG_HW)
- pr_notice("%s: send buffer phy %#x - %#x - %#x virt %p"
- " size %zu u32\n", card->name,
- card->send.dmastart, card->send.dmairq,
- card->send.dmaend, card->send.start, card->send.size);
-
- outl(card->send.dmastart, card->base + NJ_DMA_READ_START);
- outl(card->send.dmairq, card->base + NJ_DMA_READ_IRQ);
- outl(card->send.dmaend, card->base + NJ_DMA_READ_END);
-
- card->recv.start = card->dma_p + (NJ_DMA_SIZE / 2);
- card->recv.dmastart = (u32)card->dma + (NJ_DMA_SIZE / 2);
- card->recv.dmaend = card->recv.dmastart +
- (4 * (NJ_DMA_RXSIZE - 1));
- card->recv.dmairq = card->recv.dmastart +
- (4 * ((NJ_DMA_RXSIZE / 2) - 1));
- card->recv.size = NJ_DMA_RXSIZE;
-
- if (debug & DEBUG_HW)
- pr_notice("%s: recv buffer phy %#x - %#x - %#x virt %p"
- " size %zu u32\n", card->name,
- card->recv.dmastart, card->recv.dmairq,
- card->recv.dmaend, card->recv.start, card->recv.size);
-
- outl(card->recv.dmastart, card->base + NJ_DMA_WRITE_START);
- outl(card->recv.dmairq, card->base + NJ_DMA_WRITE_IRQ);
- outl(card->recv.dmaend, card->base + NJ_DMA_WRITE_END);
- return 0;
-}
-
-static void
-read_dma(struct tiger_ch *bc, u32 idx, int cnt)
-{
- struct tiger_hw *card = bc->bch.hw;
- int i, stat;
- u32 val;
- u8 *p, *pn;
-
- if (bc->lastrx == idx) {
- bc->rxstate |= RX_OVERRUN;
- pr_info("%s: B%1d overrun at idx %d\n", card->name,
- bc->bch.nr, idx);
- }
- bc->lastrx = idx;
- if (test_bit(FLG_RX_OFF, &bc->bch.Flags)) {
- bc->bch.dropcnt += cnt;
- return;
- }
- stat = bchannel_get_rxbuf(&bc->bch, cnt);
- /* only transparent use the count here, HDLC overun is detected later */
- if (stat == -ENOMEM) {
- pr_warn("%s.B%d: No memory for %d bytes\n",
- card->name, bc->bch.nr, cnt);
- return;
- }
- if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags))
- p = skb_put(bc->bch.rx_skb, cnt);
- else
- p = bc->hrbuf;
-
- for (i = 0; i < cnt; i++) {
- val = card->recv.start[idx++];
- if (bc->bch.nr & 2)
- val >>= 8;
- if (idx >= card->recv.size)
- idx = 0;
- p[i] = val & 0xff;
- }
-
- if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) {
- recv_Bchannel(&bc->bch, 0, false);
- return;
- }
-
- pn = bc->hrbuf;
- while (cnt > 0) {
- stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i,
- bc->bch.rx_skb->data, bc->bch.maxlen);
- if (stat > 0) { /* valid frame received */
- p = skb_put(bc->bch.rx_skb, stat);
- if (debug & DEBUG_HW_BFIFO) {
- snprintf(card->log, LOG_SIZE,
- "B%1d-recv %s %d ", bc->bch.nr,
- card->name, stat);
- print_hex_dump_bytes(card->log,
- DUMP_PREFIX_OFFSET, p,
- stat);
- }
- recv_Bchannel(&bc->bch, 0, false);
- stat = bchannel_get_rxbuf(&bc->bch, bc->bch.maxlen);
- if (stat < 0) {
- pr_warn("%s.B%d: No memory for %d bytes\n",
- card->name, bc->bch.nr, cnt);
- return;
- }
- } else if (stat == -HDLC_CRC_ERROR) {
- pr_info("%s: B%1d receive frame CRC error\n",
- card->name, bc->bch.nr);
- } else if (stat == -HDLC_FRAMING_ERROR) {
- pr_info("%s: B%1d receive framing error\n",
- card->name, bc->bch.nr);
- } else if (stat == -HDLC_LENGTH_ERROR) {
- pr_info("%s: B%1d receive frame too long (> %d)\n",
- card->name, bc->bch.nr, bc->bch.maxlen);
- }
- pn += i;
- cnt -= i;
- }
-}
-
-static void
-recv_tiger(struct tiger_hw *card, u8 irq_stat)
-{
- u32 idx;
- int cnt = card->recv.size / 2;
-
- /* Note receive is via the WRITE DMA channel */
- card->last_is0 &= ~NJ_IRQM0_WR_MASK;
- card->last_is0 |= (irq_stat & NJ_IRQM0_WR_MASK);
-
- if (irq_stat & NJ_IRQM0_WR_END)
- idx = cnt - 1;
- else
- idx = card->recv.size - 1;
-
- if (test_bit(FLG_ACTIVE, &card->bc[0].bch.Flags))
- read_dma(&card->bc[0], idx, cnt);
- if (test_bit(FLG_ACTIVE, &card->bc[1].bch.Flags))
- read_dma(&card->bc[1], idx, cnt);
-}
-
-/* sync with current DMA address at start or after exception */
-static void
-resync(struct tiger_ch *bc, struct tiger_hw *card)
-{
- card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);
- card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
- if (bc->free > card->send.size / 2)
- bc->free = card->send.size / 2;
- /* currently we simple sync to the next complete free area
- * this hast the advantage that we have always maximum time to
- * handle TX irq
- */
- if (card->send.idx < ((card->send.size / 2) - 1))
- bc->idx = (card->recv.size / 2) - 1;
- else
- bc->idx = card->recv.size - 1;
- bc->txstate = TX_RUN;
- pr_debug("%s: %s B%1d free %d idx %d/%d\n", card->name,
- __func__, bc->bch.nr, bc->free, bc->idx, card->send.idx);
-}
-
-static int bc_next_frame(struct tiger_ch *);
-
-static void
-fill_hdlc_flag(struct tiger_ch *bc)
-{
- struct tiger_hw *card = bc->bch.hw;
- int count, i;
- u32 m, v;
- u8 *p;
-
- if (bc->free == 0)
- return;
- pr_debug("%s: %s B%1d %d state %x idx %d/%d\n", card->name,
- __func__, bc->bch.nr, bc->free, bc->txstate,
- bc->idx, card->send.idx);
- if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))
- resync(bc, card);
- count = isdnhdlc_encode(&bc->hsend, NULL, 0, &i,
- bc->hsbuf, bc->free);
- pr_debug("%s: B%1d hdlc encoded %d flags\n", card->name,
- bc->bch.nr, count);
- bc->free -= count;
- p = bc->hsbuf;
- m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
- for (i = 0; i < count; i++) {
- if (bc->idx >= card->send.size)
- bc->idx = 0;
- v = card->send.start[bc->idx];
- v &= m;
- v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;
- card->send.start[bc->idx++] = v;
- }
- if (debug & DEBUG_HW_BFIFO) {
- snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",
- bc->bch.nr, card->name, count);
- print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);
- }
-}
-
-static void
-fill_dma(struct tiger_ch *bc)
-{
- struct tiger_hw *card = bc->bch.hw;
- int count, i, fillempty = 0;
- u32 m, v, n = 0;
- u8 *p;
-
- if (bc->free == 0)
- return;
- if (!bc->bch.tx_skb) {
- if (!test_bit(FLG_TX_EMPTY, &bc->bch.Flags))
- return;
- fillempty = 1;
- count = card->send.size >> 1;
- p = bc->bch.fill;
- } else {
- count = bc->bch.tx_skb->len - bc->bch.tx_idx;
- if (count <= 0)
- return;
- pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n",
- card->name, __func__, bc->bch.nr, count, bc->free,
- bc->bch.tx_idx, bc->bch.tx_skb->len, bc->txstate,
- bc->idx, card->send.idx);
- p = bc->bch.tx_skb->data + bc->bch.tx_idx;
- }
- if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))
- resync(bc, card);
- if (test_bit(FLG_HDLC, &bc->bch.Flags) && !fillempty) {
- count = isdnhdlc_encode(&bc->hsend, p, count, &i,
- bc->hsbuf, bc->free);
- pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name,
- bc->bch.nr, i, count);
- bc->bch.tx_idx += i;
- bc->free -= count;
- p = bc->hsbuf;
- } else {
- if (count > bc->free)
- count = bc->free;
- if (!fillempty)
- bc->bch.tx_idx += count;
- bc->free -= count;
- }
- m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
- if (fillempty) {
- n = p[0];
- if (!(bc->bch.nr & 1))
- n <<= 8;
- for (i = 0; i < count; i++) {
- if (bc->idx >= card->send.size)
- bc->idx = 0;
- v = card->send.start[bc->idx];
- v &= m;
- v |= n;
- card->send.start[bc->idx++] = v;
- }
- } else {
- for (i = 0; i < count; i++) {
- if (bc->idx >= card->send.size)
- bc->idx = 0;
- v = card->send.start[bc->idx];
- v &= m;
- n = p[i];
- v |= (bc->bch.nr & 1) ? n : n << 8;
- card->send.start[bc->idx++] = v;
- }
- }
- if (debug & DEBUG_HW_BFIFO) {
- snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",
- bc->bch.nr, card->name, count);
- print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);
- }
- if (bc->free)
- bc_next_frame(bc);
-}
-
-
-static int
-bc_next_frame(struct tiger_ch *bc)
-{
- int ret = 1;
-
- if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len) {
- fill_dma(bc);
- } else {
- dev_kfree_skb(bc->bch.tx_skb);
- if (get_next_bframe(&bc->bch)) {
- fill_dma(bc);
- test_and_clear_bit(FLG_TX_EMPTY, &bc->bch.Flags);
- } else if (test_bit(FLG_TX_EMPTY, &bc->bch.Flags)) {
- fill_dma(bc);
- } else if (test_bit(FLG_FILLEMPTY, &bc->bch.Flags)) {
- test_and_set_bit(FLG_TX_EMPTY, &bc->bch.Flags);
- ret = 0;
- } else {
- ret = 0;
- }
- }
- return ret;
-}
-
-static void
-send_tiger_bc(struct tiger_hw *card, struct tiger_ch *bc)
-{
- int ret;
-
- bc->free += card->send.size / 2;
- if (bc->free >= card->send.size) {
- if (!(bc->txstate & (TX_UNDERRUN | TX_INIT))) {
- pr_info("%s: B%1d TX underrun state %x\n", card->name,
- bc->bch.nr, bc->txstate);
- bc->txstate |= TX_UNDERRUN;
- }
- bc->free = card->send.size;
- }
- ret = bc_next_frame(bc);
- if (!ret) {
- if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
- fill_hdlc_flag(bc);
- return;
- }
- pr_debug("%s: B%1d TX no data free %d idx %d/%d\n", card->name,
- bc->bch.nr, bc->free, bc->idx, card->send.idx);
- if (!(bc->txstate & (TX_IDLE | TX_INIT))) {
- fill_mem(bc, bc->idx, bc->free, 0xff);
- if (bc->free == card->send.size)
- bc->txstate |= TX_IDLE;
- }
- }
-}
-
-static void
-send_tiger(struct tiger_hw *card, u8 irq_stat)
-{
- int i;
-
- /* Note send is via the READ DMA channel */
- if ((irq_stat & card->last_is0) & NJ_IRQM0_RD_MASK) {
- pr_info("%s: tiger warn write double dma %x/%x\n",
- card->name, irq_stat, card->last_is0);
- return;
- } else {
- card->last_is0 &= ~NJ_IRQM0_RD_MASK;
- card->last_is0 |= (irq_stat & NJ_IRQM0_RD_MASK);
- }
- for (i = 0; i < 2; i++) {
- if (test_bit(FLG_ACTIVE, &card->bc[i].bch.Flags))
- send_tiger_bc(card, &card->bc[i]);
- }
-}
-
-static irqreturn_t
-nj_irq(int intno, void *dev_id)
-{
- struct tiger_hw *card = dev_id;
- u8 val, s1val, s0val;
-
- spin_lock(&card->lock);
- s0val = inb(card->base | NJ_IRQSTAT0);
- s1val = inb(card->base | NJ_IRQSTAT1);
- if ((s1val & NJ_ISACIRQ) && (s0val == 0)) {
- /* shared IRQ */
- spin_unlock(&card->lock);
- return IRQ_NONE;
- }
- pr_debug("%s: IRQSTAT0 %02x IRQSTAT1 %02x\n", card->name, s0val, s1val);
- card->irqcnt++;
- if (!(s1val & NJ_ISACIRQ)) {
- val = ReadISAC_nj(card, ISAC_ISTA);
- if (val)
- mISDNisac_irq(&card->isac, val);
- }
-
- if (s0val)
- /* write to clear */
- outb(s0val, card->base | NJ_IRQSTAT0);
- else
- goto end;
- s1val = s0val;
- /* set bits in sval to indicate which page is free */
- card->recv.dmacur = inl(card->base | NJ_DMA_WRITE_ADR);
- card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;
- if (card->recv.dmacur < card->recv.dmairq)
- s0val = 0x08; /* the 2nd write area is free */
- else
- s0val = 0x04; /* the 1st write area is free */
-
- card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);
- card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
- if (card->send.dmacur < card->send.dmairq)
- s0val |= 0x02; /* the 2nd read area is free */
- else
- s0val |= 0x01; /* the 1st read area is free */
-
- pr_debug("%s: DMA Status %02x/%02x/%02x %d/%d\n", card->name,
- s1val, s0val, card->last_is0,
- card->recv.idx, card->send.idx);
- /* test if we have a DMA interrupt */
- if (s0val != card->last_is0) {
- if ((s0val & NJ_IRQM0_RD_MASK) !=
- (card->last_is0 & NJ_IRQM0_RD_MASK))
- /* got a write dma int */
- send_tiger(card, s0val);
- if ((s0val & NJ_IRQM0_WR_MASK) !=
- (card->last_is0 & NJ_IRQM0_WR_MASK))
- /* got a read dma int */
- recv_tiger(card, s0val);
- }
-end:
- spin_unlock(&card->lock);
- return IRQ_HANDLED;
-}
-
-static int
-nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- int ret = -EINVAL;
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);
- struct tiger_hw *card = bch->hw;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- unsigned long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- spin_lock_irqsave(&card->lock, flags);
- ret = bchannel_senddata(bch, skb);
- if (ret > 0) { /* direct TX */
- fill_dma(bc);
- ret = 0;
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return ret;
- case PH_ACTIVATE_REQ:
- spin_lock_irqsave(&card->lock, flags);
- if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
- ret = mode_tiger(bc, ch->protocol);
- else
- ret = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- if (!ret)
- _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- break;
- case PH_DEACTIVATE_REQ:
- spin_lock_irqsave(&card->lock, flags);
- mISDN_clear_bchannel(bch);
- mode_tiger(bc, ISDN_P_NONE);
- spin_unlock_irqrestore(&card->lock, flags);
- _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- ret = 0;
- break;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static int
-channel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq)
-{
- return mISDN_ctrl_bchannel(&bc->bch, cq);
-}
-
-static int
-nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);
- struct tiger_hw *card = bch->hw;
- int ret = -EINVAL;
- u_long flags;
-
- pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
- switch (cmd) {
- case CLOSE_CHANNEL:
- test_and_clear_bit(FLG_OPEN, &bch->Flags);
- cancel_work_sync(&bch->workq);
- spin_lock_irqsave(&card->lock, flags);
- mISDN_clear_bchannel(bch);
- mode_tiger(bc, ISDN_P_NONE);
- spin_unlock_irqrestore(&card->lock, flags);
- ch->protocol = ISDN_P_NONE;
- ch->peer = NULL;
- module_put(THIS_MODULE);
- ret = 0;
- break;
- case CONTROL_CHANNEL:
- ret = channel_bctrl(bc, arg);
- break;
- default:
- pr_info("%s: %s unknown prim(%x)\n", card->name, __func__, cmd);
- }
- return ret;
-}
-
-static int
-channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq)
-{
- int ret = 0;
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3;
- break;
- case MISDN_CTRL_LOOP:
- /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
- if (cq->channel < 0 || cq->channel > 3) {
- ret = -EINVAL;
- break;
- }
- ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel);
- break;
- case MISDN_CTRL_L1_TIMER3:
- ret = card->isac.ctrl(&card->isac, HW_TIMER3_VALUE, cq->p1);
- break;
- default:
- pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int
-open_bchannel(struct tiger_hw *card, struct channel_req *rq)
-{
- struct bchannel *bch;
-
- if (rq->adr.channel == 0 || rq->adr.channel > 2)
- return -EINVAL;
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
- bch = &card->bc[rq->adr.channel - 1].bch;
- if (test_and_set_bit(FLG_OPEN, &bch->Flags))
- return -EBUSY; /* b-channel can be only open once */
- test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
- bch->ch.protocol = rq->protocol;
- rq->ch = &bch->ch;
- return 0;
-}
-
-/*
- * device control function
- */
-static int
-nj_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct tiger_hw *card = dch->hw;
- struct channel_req *rq;
- int err = 0;
-
- pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
- switch (cmd) {
- case OPEN_CHANNEL:
- rq = arg;
- if (rq->protocol == ISDN_P_TE_S0)
- err = card->isac.open(&card->isac, rq);
- else
- err = open_bchannel(card, rq);
- if (err)
- break;
- if (!try_module_get(THIS_MODULE))
- pr_info("%s: cannot get module\n", card->name);
- break;
- case CLOSE_CHANNEL:
- pr_debug("%s: dev(%d) close from %p\n", card->name, dch->dev.id,
- __builtin_return_address(0));
- module_put(THIS_MODULE);
- break;
- case CONTROL_CHANNEL:
- err = channel_ctrl(card, arg);
- break;
- default:
- pr_debug("%s: %s unknown command %x\n",
- card->name, __func__, cmd);
- return -EINVAL;
- }
- return err;
-}
-
-static int
-nj_init_card(struct tiger_hw *card)
-{
- u_long flags;
- int ret;
-
- spin_lock_irqsave(&card->lock, flags);
- nj_disable_hwirq(card);
- spin_unlock_irqrestore(&card->lock, flags);
-
- card->irq = card->pdev->irq;
- if (request_irq(card->irq, nj_irq, IRQF_SHARED, card->name, card)) {
- pr_info("%s: couldn't get interrupt %d\n",
- card->name, card->irq);
- card->irq = -1;
- return -EIO;
- }
-
- spin_lock_irqsave(&card->lock, flags);
- nj_reset(card);
- ret = card->isac.init(&card->isac);
- if (ret)
- goto error;
- ret = inittiger(card);
- if (ret)
- goto error;
- mode_tiger(&card->bc[0], ISDN_P_NONE);
- mode_tiger(&card->bc[1], ISDN_P_NONE);
-error:
- spin_unlock_irqrestore(&card->lock, flags);
- return ret;
-}
-
-
-static void
-nj_release(struct tiger_hw *card)
-{
- u_long flags;
- int i;
-
- if (card->base_s) {
- spin_lock_irqsave(&card->lock, flags);
- nj_disable_hwirq(card);
- mode_tiger(&card->bc[0], ISDN_P_NONE);
- mode_tiger(&card->bc[1], ISDN_P_NONE);
- spin_unlock_irqrestore(&card->lock, flags);
- card->isac.release(&card->isac);
- release_region(card->base, card->base_s);
- card->base_s = 0;
- }
- if (card->irq > 0)
- free_irq(card->irq, card);
- if (device_is_registered(&card->isac.dch.dev.dev))
- mISDN_unregister_device(&card->isac.dch.dev);
-
- for (i = 0; i < 2; i++) {
- mISDN_freebchannel(&card->bc[i].bch);
- kfree(card->bc[i].hsbuf);
- kfree(card->bc[i].hrbuf);
- }
- if (card->dma_p)
- dma_free_coherent(&card->pdev->dev, NJ_DMA_SIZE, card->dma_p,
- card->dma);
- write_lock_irqsave(&card_lock, flags);
- list_del(&card->list);
- write_unlock_irqrestore(&card_lock, flags);
- pci_disable_device(card->pdev);
- pci_set_drvdata(card->pdev, NULL);
- kfree(card);
-}
-
-
-static int
-nj_setup(struct tiger_hw *card)
-{
- card->base = pci_resource_start(card->pdev, 0);
- card->base_s = pci_resource_len(card->pdev, 0);
- if (!request_region(card->base, card->base_s, card->name)) {
- pr_info("%s: NETjet config port %#x-%#x already in use\n",
- card->name, card->base,
- (u32)(card->base + card->base_s - 1));
- card->base_s = 0;
- return -EIO;
- }
- ASSIGN_FUNC(nj, ISAC, card->isac);
- return 0;
-}
-
-
-static int
-setup_instance(struct tiger_hw *card)
-{
- int i, err;
- u_long flags;
-
- snprintf(card->name, MISDN_MAX_IDLEN - 1, "netjet.%d", nj_cnt + 1);
- write_lock_irqsave(&card_lock, flags);
- list_add_tail(&card->list, &Cards);
- write_unlock_irqrestore(&card_lock, flags);
-
- _set_debug(card);
- card->isac.name = card->name;
- spin_lock_init(&card->lock);
- card->isac.hwlock = &card->lock;
- mISDNisac_init(&card->isac, card);
-
- card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
- card->isac.dch.dev.D.ctrl = nj_dctrl;
- for (i = 0; i < 2; i++) {
- card->bc[i].bch.nr = i + 1;
- set_channelmap(i + 1, card->isac.dch.dev.channelmap);
- mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM,
- NJ_DMA_RXSIZE >> 1);
- card->bc[i].bch.hw = card;
- card->bc[i].bch.ch.send = nj_l2l1B;
- card->bc[i].bch.ch.ctrl = nj_bctrl;
- card->bc[i].bch.ch.nr = i + 1;
- list_add(&card->bc[i].bch.ch.list,
- &card->isac.dch.dev.bchannels);
- card->bc[i].bch.hw = card;
- }
- err = nj_setup(card);
- if (err)
- goto error;
- err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev,
- card->name);
- if (err)
- goto error;
- err = nj_init_card(card);
- if (!err) {
- nj_cnt++;
- pr_notice("Netjet %d cards installed\n", nj_cnt);
- return 0;
- }
-error:
- nj_release(card);
- return err;
-}
-
-static int
-nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int err = -ENOMEM;
- int cfg;
- struct tiger_hw *card;
-
- if (pdev->subsystem_vendor == 0x8086 &&
- pdev->subsystem_device == 0x0003) {
- pr_notice("Netjet: Digium X100P/X101P not handled\n");
- return -ENODEV;
- }
-
- if (pdev->subsystem_vendor == 0x55 &&
- pdev->subsystem_device == 0x02) {
- pr_notice("Netjet: Enter!Now not handled yet\n");
- return -ENODEV;
- }
-
- if (pdev->subsystem_vendor == 0xb100 &&
- pdev->subsystem_device == 0x0003) {
- pr_notice("Netjet: Digium TDM400P not handled yet\n");
- return -ENODEV;
- }
-
- card = kzalloc_obj(struct tiger_hw);
- if (!card) {
- pr_info("No kmem for Netjet\n");
- return err;
- }
-
- card->pdev = pdev;
-
- err = pci_enable_device(pdev);
- if (err) {
- kfree(card);
- return err;
- }
-
- printk(KERN_INFO "nj_probe(mISDN): found adapter at %s\n",
- pci_name(pdev));
-
- pci_set_master(pdev);
-
- /* the TJ300 and TJ320 must be detected, the IRQ handling is different
- * unfortunately the chips use the same device ID, but the TJ320 has
- * the bit20 in status PCI cfg register set
- */
- pci_read_config_dword(pdev, 0x04, &cfg);
- if (cfg & 0x00100000)
- card->typ = NETJET_S_TJ320;
- else
- card->typ = NETJET_S_TJ300;
-
- card->base = pci_resource_start(pdev, 0);
- pci_set_drvdata(pdev, card);
- err = setup_instance(card);
- if (err)
- pci_set_drvdata(pdev, NULL);
-
- return err;
-}
-
-
-static void nj_remove(struct pci_dev *pdev)
-{
- struct tiger_hw *card = pci_get_drvdata(pdev);
-
- if (card)
- nj_release(card);
- else
- pr_info("%s drvdata already removed\n", __func__);
-}
-
-/* We cannot select cards with PCI_SUB... IDs, since here are cards with
- * SUB IDs set to PCI_ANY_ID, so we need to match all and reject
- * known other cards which not work with this driver - see probe function */
-static const struct pci_device_id nj_pci_ids[] = {
- { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { }
-};
-MODULE_DEVICE_TABLE(pci, nj_pci_ids);
-
-static struct pci_driver nj_driver = {
- .name = "netjet",
- .probe = nj_probe,
- .remove = nj_remove,
- .id_table = nj_pci_ids,
-};
-
-static int __init nj_init(void)
-{
- int err;
-
- pr_notice("Netjet PCI driver Rev. %s\n", NETJET_REV);
- err = pci_register_driver(&nj_driver);
- return err;
-}
-
-static void __exit nj_cleanup(void)
-{
- pci_unregister_driver(&nj_driver);
-}
-
-module_init(nj_init);
-module_exit(nj_cleanup);
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * NETjet common header file
- *
- * Author Karsten Keil
- * based on work of Matt Henderson and Daniel Potts,
- * Traverse Technologies P/L www.traverse.com.au
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-
-#define NJ_CTRL 0x00
-#define NJ_DMACTRL 0x01
-#define NJ_AUXCTRL 0x02
-#define NJ_AUXDATA 0x03
-#define NJ_IRQMASK0 0x04
-#define NJ_IRQMASK1 0x05
-#define NJ_IRQSTAT0 0x06
-#define NJ_IRQSTAT1 0x07
-#define NJ_DMA_READ_START 0x08
-#define NJ_DMA_READ_IRQ 0x0c
-#define NJ_DMA_READ_END 0x10
-#define NJ_DMA_READ_ADR 0x14
-#define NJ_DMA_WRITE_START 0x18
-#define NJ_DMA_WRITE_IRQ 0x1c
-#define NJ_DMA_WRITE_END 0x20
-#define NJ_DMA_WRITE_ADR 0x24
-#define NJ_PULSE_CNT 0x28
-
-#define NJ_ISAC_OFF 0xc0
-#define NJ_ISACIRQ 0x10
-
-#define NJ_IRQM0_RD_MASK 0x03
-#define NJ_IRQM0_RD_IRQ 0x01
-#define NJ_IRQM0_RD_END 0x02
-#define NJ_IRQM0_WR_MASK 0x0c
-#define NJ_IRQM0_WR_IRQ 0x04
-#define NJ_IRQM0_WR_END 0x08
-
-/* one page here is no need to be smaller */
-#define NJ_DMA_SIZE 4096
-/* 2 * 64 byte is a compromise between IRQ count and latency */
-#define NJ_DMA_RXSIZE 128 /* 2 * 64 */
-#define NJ_DMA_TXSIZE 128 /* 2 * 64 */
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * speedfax.c low level stuff for Sedlbauer Speedfax+ cards
- * based on the ISAR DSP
- * Thanks to Sedlbauer AG for informations and HW
- *
- * Author Karsten Keil <keil@isdn4linux.de>
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/mISDNhw.h>
-#include <linux/firmware.h>
-#include "ipac.h"
-#include "isar.h"
-
-#define SPEEDFAX_REV "2.0"
-
-#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51
-#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54
-#define PCI_SUB_ID_SEDLBAUER 0x01
-
-#define SFAX_PCI_ADDR 0xc8
-#define SFAX_PCI_ISAC 0xd0
-#define SFAX_PCI_ISAR 0xe0
-
-/* TIGER 100 Registers */
-
-#define TIGER_RESET_ADDR 0x00
-#define TIGER_EXTERN_RESET_ON 0x01
-#define TIGER_EXTERN_RESET_OFF 0x00
-#define TIGER_AUX_CTRL 0x02
-#define TIGER_AUX_DATA 0x03
-#define TIGER_AUX_IRQMASK 0x05
-#define TIGER_AUX_STATUS 0x07
-
-/* Tiger AUX BITs */
-#define SFAX_AUX_IOMASK 0xdd /* 1 and 5 are inputs */
-#define SFAX_ISAR_RESET_BIT_OFF 0x00
-#define SFAX_ISAR_RESET_BIT_ON 0x01
-#define SFAX_TIGER_IRQ_BIT 0x02
-#define SFAX_LED1_BIT 0x08
-#define SFAX_LED2_BIT 0x10
-
-#define SFAX_PCI_RESET_ON (SFAX_ISAR_RESET_BIT_ON)
-#define SFAX_PCI_RESET_OFF (SFAX_LED1_BIT | SFAX_LED2_BIT)
-
-static int sfax_cnt;
-static u32 debug;
-static u32 irqloops = 4;
-
-struct sfax_hw {
- struct list_head list;
- struct pci_dev *pdev;
- char name[MISDN_MAX_IDLEN];
- u32 irq;
- u32 irqcnt;
- u32 cfg;
- struct _ioport p_isac;
- struct _ioport p_isar;
- u8 aux_data;
- spinlock_t lock; /* HW access lock */
- struct isac_hw isac;
- struct isar_hw isar;
-};
-
-static LIST_HEAD(Cards);
-static DEFINE_RWLOCK(card_lock); /* protect Cards */
-
-static void
-_set_debug(struct sfax_hw *card)
-{
- card->isac.dch.debug = debug;
- card->isar.ch[0].bch.debug = debug;
- card->isar.ch[1].bch.debug = debug;
-}
-
-static int
-set_debug(const char *val, const struct kernel_param *kp)
-{
- int ret;
- struct sfax_hw *card;
-
- ret = param_set_uint(val, kp);
- if (!ret) {
- read_lock(&card_lock);
- list_for_each_entry(card, &Cards, list)
- _set_debug(card);
- read_unlock(&card_lock);
- }
- return ret;
-}
-
-MODULE_AUTHOR("Karsten Keil");
-MODULE_DESCRIPTION("mISDN driver for Sedlbauer Speedfax+ cards");
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION(SPEEDFAX_REV);
-MODULE_FIRMWARE("isdn/ISAR.BIN");
-module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Speedfax debug mask");
-module_param(irqloops, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)");
-
-IOFUNC_IND(ISAC, sfax_hw, p_isac)
-IOFUNC_IND(ISAR, sfax_hw, p_isar)
-
-static irqreturn_t
-speedfax_irq(int intno, void *dev_id)
-{
- struct sfax_hw *sf = dev_id;
- u8 val;
- int cnt = irqloops;
-
- spin_lock(&sf->lock);
- val = inb(sf->cfg + TIGER_AUX_STATUS);
- if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */
- spin_unlock(&sf->lock);
- return IRQ_NONE; /* shared */
- }
- sf->irqcnt++;
- val = ReadISAR_IND(sf, ISAR_IRQBIT);
-Start_ISAR:
- if (val & ISAR_IRQSTA)
- mISDNisar_irq(&sf->isar);
- val = ReadISAC_IND(sf, ISAC_ISTA);
- if (val)
- mISDNisac_irq(&sf->isac, val);
- val = ReadISAR_IND(sf, ISAR_IRQBIT);
- if ((val & ISAR_IRQSTA) && cnt--)
- goto Start_ISAR;
- if (cnt < irqloops)
- pr_debug("%s: %d irqloops cpu%d\n", sf->name,
- irqloops - cnt, smp_processor_id());
- if (irqloops && !cnt)
- pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name,
- irqloops, smp_processor_id());
- spin_unlock(&sf->lock);
- return IRQ_HANDLED;
-}
-
-static void
-enable_hwirq(struct sfax_hw *sf)
-{
- WriteISAC_IND(sf, ISAC_MASK, 0);
- WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK);
- outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK);
-}
-
-static void
-disable_hwirq(struct sfax_hw *sf)
-{
- WriteISAC_IND(sf, ISAC_MASK, 0xFF);
- WriteISAR_IND(sf, ISAR_IRQBIT, 0);
- outb(0, sf->cfg + TIGER_AUX_IRQMASK);
-}
-
-static void
-reset_speedfax(struct sfax_hw *sf)
-{
-
- pr_debug("%s: resetting card\n", sf->name);
- outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR);
- outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA);
- mdelay(1);
- outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR);
- sf->aux_data = SFAX_PCI_RESET_OFF;
- outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
- mdelay(1);
-}
-
-static int
-sfax_ctrl(struct sfax_hw *sf, u32 cmd, u_long arg)
-{
- int ret = 0;
-
- switch (cmd) {
- case HW_RESET_REQ:
- reset_speedfax(sf);
- break;
- case HW_ACTIVATE_IND:
- if (arg & 1)
- sf->aux_data &= ~SFAX_LED1_BIT;
- if (arg & 2)
- sf->aux_data &= ~SFAX_LED2_BIT;
- outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
- break;
- case HW_DEACT_IND:
- if (arg & 1)
- sf->aux_data |= SFAX_LED1_BIT;
- if (arg & 2)
- sf->aux_data |= SFAX_LED2_BIT;
- outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
- break;
- default:
- pr_info("%s: %s unknown command %x %lx\n",
- sf->name, __func__, cmd, arg);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int
-channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq)
-{
- int ret = 0;
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3;
- break;
- case MISDN_CTRL_LOOP:
- /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
- if (cq->channel < 0 || cq->channel > 3) {
- ret = -EINVAL;
- break;
- }
- ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel);
- break;
- case MISDN_CTRL_L1_TIMER3:
- ret = sf->isac.ctrl(&sf->isac, HW_TIMER3_VALUE, cq->p1);
- break;
- default:
- pr_info("%s: unknown Op %x\n", sf->name, cq->op);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int
-sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct sfax_hw *sf = dch->hw;
- struct channel_req *rq;
- int err = 0;
-
- pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg);
- switch (cmd) {
- case OPEN_CHANNEL:
- rq = arg;
- if (rq->protocol == ISDN_P_TE_S0)
- err = sf->isac.open(&sf->isac, rq);
- else
- err = sf->isar.open(&sf->isar, rq);
- if (err)
- break;
- if (!try_module_get(THIS_MODULE))
- pr_info("%s: cannot get module\n", sf->name);
- break;
- case CLOSE_CHANNEL:
- pr_debug("%s: dev(%d) close from %p\n", sf->name,
- dch->dev.id, __builtin_return_address(0));
- module_put(THIS_MODULE);
- break;
- case CONTROL_CHANNEL:
- err = channel_ctrl(sf, arg);
- break;
- default:
- pr_debug("%s: unknown command %x\n", sf->name, cmd);
- return -EINVAL;
- }
- return err;
-}
-
-static int
-init_card(struct sfax_hw *sf)
-{
- int ret, cnt = 3;
- u_long flags;
-
- ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf);
- if (ret) {
- pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq);
- return ret;
- }
- while (cnt--) {
- spin_lock_irqsave(&sf->lock, flags);
- ret = sf->isac.init(&sf->isac);
- if (ret) {
- spin_unlock_irqrestore(&sf->lock, flags);
- pr_info("%s: ISAC init failed with %d\n",
- sf->name, ret);
- break;
- }
- enable_hwirq(sf);
- /* RESET Receiver and Transmitter */
- WriteISAC_IND(sf, ISAC_CMDR, 0x41);
- spin_unlock_irqrestore(&sf->lock, flags);
- msleep_interruptible(10);
- if (debug & DEBUG_HW)
- pr_notice("%s: IRQ %d count %d\n", sf->name,
- sf->irq, sf->irqcnt);
- if (!sf->irqcnt) {
- pr_info("%s: IRQ(%d) got no requests during init %d\n",
- sf->name, sf->irq, 3 - cnt);
- } else
- return 0;
- }
- free_irq(sf->irq, sf);
- return -EIO;
-}
-
-
-static int
-setup_speedfax(struct sfax_hw *sf)
-{
- u_long flags;
-
- if (!request_region(sf->cfg, 256, sf->name)) {
- pr_info("mISDN: %s config port %x-%x already in use\n",
- sf->name, sf->cfg, sf->cfg + 255);
- return -EIO;
- }
- outb(0xff, sf->cfg);
- outb(0, sf->cfg);
- outb(0xdd, sf->cfg + TIGER_AUX_CTRL);
- outb(0, sf->cfg + TIGER_AUX_IRQMASK);
-
- sf->isac.type = IPAC_TYPE_ISAC;
- sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR;
- sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC;
- sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR;
- sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR;
- ASSIGN_FUNC(IND, ISAC, sf->isac);
- ASSIGN_FUNC(IND, ISAR, sf->isar);
- spin_lock_irqsave(&sf->lock, flags);
- reset_speedfax(sf);
- disable_hwirq(sf);
- spin_unlock_irqrestore(&sf->lock, flags);
- return 0;
-}
-
-static void
-release_card(struct sfax_hw *card) {
- u_long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- disable_hwirq(card);
- spin_unlock_irqrestore(&card->lock, flags);
- card->isac.release(&card->isac);
- free_irq(card->irq, card);
- card->isar.release(&card->isar);
- mISDN_unregister_device(&card->isac.dch.dev);
- release_region(card->cfg, 256);
- pci_disable_device(card->pdev);
- pci_set_drvdata(card->pdev, NULL);
- write_lock_irqsave(&card_lock, flags);
- list_del(&card->list);
- write_unlock_irqrestore(&card_lock, flags);
- kfree(card);
- sfax_cnt--;
-}
-
-static int
-setup_instance(struct sfax_hw *card)
-{
- const struct firmware *firmware;
- int i, err;
- u_long flags;
-
- snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1);
- write_lock_irqsave(&card_lock, flags);
- list_add_tail(&card->list, &Cards);
- write_unlock_irqrestore(&card_lock, flags);
- _set_debug(card);
- spin_lock_init(&card->lock);
- card->isac.hwlock = &card->lock;
- card->isar.hwlock = &card->lock;
- card->isar.ctrl = (void *)&sfax_ctrl;
- card->isac.name = card->name;
- card->isar.name = card->name;
- card->isar.owner = THIS_MODULE;
-
- err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev);
- if (err < 0) {
- pr_info("%s: firmware request failed %d\n",
- card->name, err);
- goto error_fw;
- }
- if (debug & DEBUG_HW)
- pr_notice("%s: got firmware %zu bytes\n",
- card->name, firmware->size);
-
- mISDNisac_init(&card->isac, card);
-
- card->isac.dch.dev.D.ctrl = sfax_dctrl;
- card->isac.dch.dev.Bprotocols =
- mISDNisar_init(&card->isar, card);
- for (i = 0; i < 2; i++) {
- set_channelmap(i + 1, card->isac.dch.dev.channelmap);
- list_add(&card->isar.ch[i].bch.ch.list,
- &card->isac.dch.dev.bchannels);
- }
-
- err = setup_speedfax(card);
- if (err)
- goto error_setup;
- err = card->isar.init(&card->isar);
- if (err)
- goto error;
- err = mISDN_register_device(&card->isac.dch.dev,
- &card->pdev->dev, card->name);
- if (err)
- goto error;
- err = init_card(card);
- if (err)
- goto error_init;
- err = card->isar.firmware(&card->isar, firmware->data, firmware->size);
- if (!err) {
- release_firmware(firmware);
- sfax_cnt++;
- pr_notice("SpeedFax %d cards installed\n", sfax_cnt);
- return 0;
- }
- disable_hwirq(card);
- free_irq(card->irq, card);
-error_init:
- mISDN_unregister_device(&card->isac.dch.dev);
-error:
- release_region(card->cfg, 256);
-error_setup:
- card->isac.release(&card->isac);
- card->isar.release(&card->isar);
- release_firmware(firmware);
-error_fw:
- pci_disable_device(card->pdev);
- write_lock_irqsave(&card_lock, flags);
- list_del(&card->list);
- write_unlock_irqrestore(&card_lock, flags);
- kfree(card);
- return err;
-}
-
-static int
-sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int err = -ENOMEM;
- struct sfax_hw *card = kzalloc_obj(struct sfax_hw);
-
- if (!card) {
- pr_info("No memory for Speedfax+ PCI\n");
- return err;
- }
- card->pdev = pdev;
- err = pci_enable_device(pdev);
- if (err) {
- kfree(card);
- return err;
- }
-
- pr_notice("mISDN: Speedfax found adapter %s at %s\n",
- (char *)ent->driver_data, pci_name(pdev));
-
- card->cfg = pci_resource_start(pdev, 0);
- card->irq = pdev->irq;
- pci_set_drvdata(pdev, card);
- err = setup_instance(card);
- if (err)
- pci_set_drvdata(pdev, NULL);
- return err;
-}
-
-static void
-sfax_remove_pci(struct pci_dev *pdev)
-{
- struct sfax_hw *card = pci_get_drvdata(pdev);
-
- if (card)
- release_card(card);
- else
- pr_debug("%s: drvdata already removed\n", __func__);
-}
-
-static struct pci_device_id sfaxpci_ids[] = {
- { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
- PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER,
- 0, 0, (unsigned long) "Pyramid Speedfax + PCI"
- },
- { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
- PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER,
- 0, 0, (unsigned long) "Sedlbauer Speedfax + PCI"
- },
- { }
-};
-MODULE_DEVICE_TABLE(pci, sfaxpci_ids);
-
-static struct pci_driver sfaxpci_driver = {
- .name = "speedfax+ pci",
- .probe = sfaxpci_probe,
- .remove = sfax_remove_pci,
- .id_table = sfaxpci_ids,
-};
-
-static int __init
-Speedfax_init(void)
-{
- int err;
-
- pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n",
- SPEEDFAX_REV);
- err = pci_register_driver(&sfaxpci_driver);
- return err;
-}
-
-static void __exit
-Speedfax_cleanup(void)
-{
- pci_unregister_driver(&sfaxpci_driver);
-}
-
-module_init(Speedfax_init);
-module_exit(Speedfax_cleanup);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * w6692.c mISDN driver for Winbond w6692 based cards
- *
- * Author Karsten Keil <kkeil@suse.de>
- * based on the w6692 I4L driver from Petr Novak <petr.novak@i.cz>
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/mISDNhw.h>
-#include <linux/slab.h>
-#include "w6692.h"
-
-#define W6692_REV "2.0"
-
-#define DBUSY_TIMER_VALUE 80
-
-enum {
- W6692_ASUS,
- W6692_WINBOND,
- W6692_USR
-};
-
-/* private data in the PCI devices list */
-struct w6692map {
- u_int subtype;
- char *name;
-};
-
-static const struct w6692map w6692_map[] =
-{
- {W6692_ASUS, "Dynalink/AsusCom IS64PH"},
- {W6692_WINBOND, "Winbond W6692"},
- {W6692_USR, "USR W6692"}
-};
-
-#define PCI_DEVICE_ID_USR_6692 0x3409
-
-struct w6692_ch {
- struct bchannel bch;
- u32 addr;
- struct timer_list timer;
- u8 b_mode;
-};
-
-struct w6692_hw {
- struct list_head list;
- struct pci_dev *pdev;
- char name[MISDN_MAX_IDLEN];
- u32 irq;
- u32 irqcnt;
- u32 addr;
- u32 fmask; /* feature mask - bit set per card nr */
- int subtype;
- spinlock_t lock; /* hw lock */
- u8 imask;
- u8 pctl;
- u8 xaddr;
- u8 xdata;
- u8 state;
- struct w6692_ch bc[2];
- struct dchannel dch;
- char log[64];
-};
-
-static LIST_HEAD(Cards);
-static DEFINE_RWLOCK(card_lock); /* protect Cards */
-
-static int w6692_cnt;
-static int debug;
-static u32 led;
-static u32 pots;
-
-static void
-_set_debug(struct w6692_hw *card)
-{
- card->dch.debug = debug;
- card->bc[0].bch.debug = debug;
- card->bc[1].bch.debug = debug;
-}
-
-static int
-set_debug(const char *val, const struct kernel_param *kp)
-{
- int ret;
- struct w6692_hw *card;
-
- ret = param_set_uint(val, kp);
- if (!ret) {
- read_lock(&card_lock);
- list_for_each_entry(card, &Cards, list)
- _set_debug(card);
- read_unlock(&card_lock);
- }
- return ret;
-}
-
-MODULE_AUTHOR("Karsten Keil");
-MODULE_DESCRIPTION("mISDN driver for Winbond w6692 based cards");
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION(W6692_REV);
-module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "W6692 debug mask");
-module_param(led, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(led, "W6692 LED support bitmask (one bit per card)");
-module_param(pots, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(pots, "W6692 POTS support bitmask (one bit per card)");
-
-static inline u8
-ReadW6692(struct w6692_hw *card, u8 offset)
-{
- return inb(card->addr + offset);
-}
-
-static inline void
-WriteW6692(struct w6692_hw *card, u8 offset, u8 value)
-{
- outb(value, card->addr + offset);
-}
-
-static inline u8
-ReadW6692B(struct w6692_ch *bc, u8 offset)
-{
- return inb(bc->addr + offset);
-}
-
-static inline void
-WriteW6692B(struct w6692_ch *bc, u8 offset, u8 value)
-{
- outb(value, bc->addr + offset);
-}
-
-static void
-enable_hwirq(struct w6692_hw *card)
-{
- WriteW6692(card, W_IMASK, card->imask);
-}
-
-static void
-disable_hwirq(struct w6692_hw *card)
-{
- WriteW6692(card, W_IMASK, 0xff);
-}
-
-static const char *W6692Ver[] = {"V00", "V01", "V10", "V11"};
-
-static void
-W6692Version(struct w6692_hw *card)
-{
- int val;
-
- val = ReadW6692(card, W_D_RBCH);
- pr_notice("%s: Winbond W6692 version: %s\n", card->name,
- W6692Ver[(val >> 6) & 3]);
-}
-
-static void
-w6692_led_handler(struct w6692_hw *card, int on)
-{
- if ((!(card->fmask & led)) || card->subtype == W6692_USR)
- return;
- if (on) {
- card->xdata &= 0xfb; /* LED ON */
- WriteW6692(card, W_XDATA, card->xdata);
- } else {
- card->xdata |= 0x04; /* LED OFF */
- WriteW6692(card, W_XDATA, card->xdata);
- }
-}
-
-static void
-ph_command(struct w6692_hw *card, u8 cmd)
-{
- pr_debug("%s: ph_command %x\n", card->name, cmd);
- WriteW6692(card, W_CIX, cmd);
-}
-
-static void
-W6692_new_ph(struct w6692_hw *card)
-{
- if (card->state == W_L1CMD_RST)
- ph_command(card, W_L1CMD_DRC);
- schedule_event(&card->dch, FLG_PHCHANGE);
-}
-
-static void
-W6692_ph_bh(struct dchannel *dch)
-{
- struct w6692_hw *card = dch->hw;
-
- switch (card->state) {
- case W_L1CMD_RST:
- dch->state = 0;
- l1_event(dch->l1, HW_RESET_IND);
- break;
- case W_L1IND_CD:
- dch->state = 3;
- l1_event(dch->l1, HW_DEACT_CNF);
- break;
- case W_L1IND_DRD:
- dch->state = 3;
- l1_event(dch->l1, HW_DEACT_IND);
- break;
- case W_L1IND_CE:
- dch->state = 4;
- l1_event(dch->l1, HW_POWERUP_IND);
- break;
- case W_L1IND_LD:
- if (dch->state <= 5) {
- dch->state = 5;
- l1_event(dch->l1, ANYSIGNAL);
- } else {
- dch->state = 8;
- l1_event(dch->l1, LOSTFRAMING);
- }
- break;
- case W_L1IND_ARD:
- dch->state = 6;
- l1_event(dch->l1, INFO2);
- break;
- case W_L1IND_AI8:
- dch->state = 7;
- l1_event(dch->l1, INFO4_P8);
- break;
- case W_L1IND_AI10:
- dch->state = 7;
- l1_event(dch->l1, INFO4_P10);
- break;
- default:
- pr_debug("%s: TE unknown state %02x dch state %02x\n",
- card->name, card->state, dch->state);
- break;
- }
- pr_debug("%s: TE newstate %02x\n", card->name, dch->state);
-}
-
-static void
-W6692_empty_Dfifo(struct w6692_hw *card, int count)
-{
- struct dchannel *dch = &card->dch;
- u8 *ptr;
-
- pr_debug("%s: empty_Dfifo %d\n", card->name, count);
- if (!dch->rx_skb) {
- dch->rx_skb = mI_alloc_skb(card->dch.maxlen, GFP_ATOMIC);
- if (!dch->rx_skb) {
- pr_info("%s: D receive out of memory\n", card->name);
- WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
- return;
- }
- }
- if ((dch->rx_skb->len + count) >= dch->maxlen) {
- pr_debug("%s: empty_Dfifo overrun %d\n", card->name,
- dch->rx_skb->len + count);
- WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
- return;
- }
- ptr = skb_put(dch->rx_skb, count);
- insb(card->addr + W_D_RFIFO, ptr, count);
- WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
- if (debug & DEBUG_HW_DFIFO) {
- snprintf(card->log, 63, "D-recv %s %d ",
- card->name, count);
- print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
- }
-}
-
-static void
-W6692_fill_Dfifo(struct w6692_hw *card)
-{
- struct dchannel *dch = &card->dch;
- int count;
- u8 *ptr;
- u8 cmd = W_D_CMDR_XMS;
-
- pr_debug("%s: fill_Dfifo\n", card->name);
- if (!dch->tx_skb)
- return;
- count = dch->tx_skb->len - dch->tx_idx;
- if (count <= 0)
- return;
- if (count > W_D_FIFO_THRESH)
- count = W_D_FIFO_THRESH;
- else
- cmd |= W_D_CMDR_XME;
- ptr = dch->tx_skb->data + dch->tx_idx;
- dch->tx_idx += count;
- outsb(card->addr + W_D_XFIFO, ptr, count);
- WriteW6692(card, W_D_CMDR, cmd);
- if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) {
- pr_debug("%s: fill_Dfifo dbusytimer running\n", card->name);
- timer_delete(&dch->timer);
- }
- dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
- add_timer(&dch->timer);
- if (debug & DEBUG_HW_DFIFO) {
- snprintf(card->log, 63, "D-send %s %d ",
- card->name, count);
- print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
- }
-}
-
-static void
-d_retransmit(struct w6692_hw *card)
-{
- struct dchannel *dch = &card->dch;
-
- if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
- timer_delete(&dch->timer);
-#ifdef FIXME
- if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
- dchannel_sched_event(dch, D_CLEARBUSY);
-#endif
- if (test_bit(FLG_TX_BUSY, &dch->Flags)) {
- /* Restart frame */
- dch->tx_idx = 0;
- W6692_fill_Dfifo(card);
- } else if (dch->tx_skb) { /* should not happen */
- pr_info("%s: %s without TX_BUSY\n", card->name, __func__);
- test_and_set_bit(FLG_TX_BUSY, &dch->Flags);
- dch->tx_idx = 0;
- W6692_fill_Dfifo(card);
- } else {
- pr_info("%s: XDU no TX_BUSY\n", card->name);
- if (get_next_dframe(dch))
- W6692_fill_Dfifo(card);
- }
-}
-
-static void
-handle_rxD(struct w6692_hw *card) {
- u8 stat;
- int count;
-
- stat = ReadW6692(card, W_D_RSTA);
- if (stat & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) {
- if (stat & W_D_RSTA_RDOV) {
- pr_debug("%s: D-channel RDOV\n", card->name);
-#ifdef ERROR_STATISTIC
- card->dch.err_rx++;
-#endif
- }
- if (stat & W_D_RSTA_CRCE) {
- pr_debug("%s: D-channel CRC error\n", card->name);
-#ifdef ERROR_STATISTIC
- card->dch.err_crc++;
-#endif
- }
- if (stat & W_D_RSTA_RMB) {
- pr_debug("%s: D-channel ABORT\n", card->name);
-#ifdef ERROR_STATISTIC
- card->dch.err_rx++;
-#endif
- }
- dev_kfree_skb(card->dch.rx_skb);
- card->dch.rx_skb = NULL;
- WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST);
- } else {
- count = ReadW6692(card, W_D_RBCL) & (W_D_FIFO_THRESH - 1);
- if (count == 0)
- count = W_D_FIFO_THRESH;
- W6692_empty_Dfifo(card, count);
- recv_Dchannel(&card->dch);
- }
-}
-
-static void
-handle_txD(struct w6692_hw *card) {
- if (test_and_clear_bit(FLG_BUSY_TIMER, &card->dch.Flags))
- timer_delete(&card->dch.timer);
- if (card->dch.tx_skb && card->dch.tx_idx < card->dch.tx_skb->len) {
- W6692_fill_Dfifo(card);
- } else {
- dev_kfree_skb(card->dch.tx_skb);
- if (get_next_dframe(&card->dch))
- W6692_fill_Dfifo(card);
- }
-}
-
-static void
-handle_statusD(struct w6692_hw *card)
-{
- struct dchannel *dch = &card->dch;
- u8 exval, v1, cir;
-
- exval = ReadW6692(card, W_D_EXIR);
-
- pr_debug("%s: D_EXIR %02x\n", card->name, exval);
- if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) {
- /* Transmit underrun/collision */
- pr_debug("%s: D-channel underrun/collision\n", card->name);
-#ifdef ERROR_STATISTIC
- dch->err_tx++;
-#endif
- d_retransmit(card);
- }
- if (exval & W_D_EXI_RDOV) { /* RDOV */
- pr_debug("%s: D-channel RDOV\n", card->name);
- WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST);
- }
- if (exval & W_D_EXI_TIN2) /* TIN2 - never */
- pr_debug("%s: spurious TIN2 interrupt\n", card->name);
- if (exval & W_D_EXI_MOC) { /* MOC - not supported */
- v1 = ReadW6692(card, W_MOSR);
- pr_debug("%s: spurious MOC interrupt MOSR %02x\n",
- card->name, v1);
- }
- if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */
- cir = ReadW6692(card, W_CIR);
- pr_debug("%s: ISC CIR %02X\n", card->name, cir);
- if (cir & W_CIR_ICC) {
- v1 = cir & W_CIR_COD_MASK;
- pr_debug("%s: ph_state_change %x -> %x\n", card->name,
- dch->state, v1);
- card->state = v1;
- if (card->fmask & led) {
- switch (v1) {
- case W_L1IND_AI8:
- case W_L1IND_AI10:
- w6692_led_handler(card, 1);
- break;
- default:
- w6692_led_handler(card, 0);
- break;
- }
- }
- W6692_new_ph(card);
- }
- if (cir & W_CIR_SCC) {
- v1 = ReadW6692(card, W_SQR);
- pr_debug("%s: SCC SQR %02X\n", card->name, v1);
- }
- }
- if (exval & W_D_EXI_WEXP)
- pr_debug("%s: spurious WEXP interrupt!\n", card->name);
- if (exval & W_D_EXI_TEXP)
- pr_debug("%s: spurious TEXP interrupt!\n", card->name);
-}
-
-static void
-W6692_empty_Bfifo(struct w6692_ch *wch, int count)
-{
- struct w6692_hw *card = wch->bch.hw;
- u8 *ptr;
- int maxlen;
-
- pr_debug("%s: empty_Bfifo %d\n", card->name, count);
- if (unlikely(wch->bch.state == ISDN_P_NONE)) {
- pr_debug("%s: empty_Bfifo ISDN_P_NONE\n", card->name);
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
- if (wch->bch.rx_skb)
- skb_trim(wch->bch.rx_skb, 0);
- return;
- }
- if (test_bit(FLG_RX_OFF, &wch->bch.Flags)) {
- wch->bch.dropcnt += count;
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
- return;
- }
- maxlen = bchannel_get_rxbuf(&wch->bch, count);
- if (maxlen < 0) {
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
- if (wch->bch.rx_skb)
- skb_trim(wch->bch.rx_skb, 0);
- pr_warn("%s.B%d: No bufferspace for %d bytes\n",
- card->name, wch->bch.nr, count);
- return;
- }
- ptr = skb_put(wch->bch.rx_skb, count);
- insb(wch->addr + W_B_RFIFO, ptr, count);
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
- if (debug & DEBUG_HW_DFIFO) {
- snprintf(card->log, 63, "B%1d-recv %s %d ",
- wch->bch.nr, card->name, count);
- print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
- }
-}
-
-static void
-W6692_fill_Bfifo(struct w6692_ch *wch)
-{
- struct w6692_hw *card = wch->bch.hw;
- int count, fillempty = 0;
- u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS;
-
- pr_debug("%s: fill Bfifo\n", card->name);
- if (!wch->bch.tx_skb) {
- if (!test_bit(FLG_TX_EMPTY, &wch->bch.Flags))
- return;
- ptr = wch->bch.fill;
- count = W_B_FIFO_THRESH;
- fillempty = 1;
- } else {
- count = wch->bch.tx_skb->len - wch->bch.tx_idx;
- if (count <= 0)
- return;
- ptr = wch->bch.tx_skb->data + wch->bch.tx_idx;
- }
- if (count > W_B_FIFO_THRESH)
- count = W_B_FIFO_THRESH;
- else if (test_bit(FLG_HDLC, &wch->bch.Flags))
- cmd |= W_B_CMDR_XME;
-
- pr_debug("%s: fill Bfifo%d/%d\n", card->name,
- count, wch->bch.tx_idx);
- wch->bch.tx_idx += count;
- if (fillempty) {
- while (count > 0) {
- outsb(wch->addr + W_B_XFIFO, ptr, MISDN_BCH_FILL_SIZE);
- count -= MISDN_BCH_FILL_SIZE;
- }
- } else {
- outsb(wch->addr + W_B_XFIFO, ptr, count);
- }
- WriteW6692B(wch, W_B_CMDR, cmd);
- if ((debug & DEBUG_HW_BFIFO) && !fillempty) {
- snprintf(card->log, 63, "B%1d-send %s %d ",
- wch->bch.nr, card->name, count);
- print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
- }
-}
-
-#if 0
-static int
-setvolume(struct w6692_ch *wch, int mic, struct sk_buff *skb)
-{
- struct w6692_hw *card = wch->bch.hw;
- u16 *vol = (u16 *)skb->data;
- u8 val;
-
- if ((!(card->fmask & pots)) ||
- !test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
- return -ENODEV;
- if (skb->len < 2)
- return -EINVAL;
- if (*vol > 7)
- return -EINVAL;
- val = *vol & 7;
- val = 7 - val;
- if (mic) {
- val <<= 3;
- card->xaddr &= 0xc7;
- } else {
- card->xaddr &= 0xf8;
- }
- card->xaddr |= val;
- WriteW6692(card, W_XADDR, card->xaddr);
- return 0;
-}
-
-static int
-enable_pots(struct w6692_ch *wch)
-{
- struct w6692_hw *card = wch->bch.hw;
-
- if ((!(card->fmask & pots)) ||
- !test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
- return -ENODEV;
- wch->b_mode |= W_B_MODE_EPCM | W_B_MODE_BSW0;
- WriteW6692B(wch, W_B_MODE, wch->b_mode);
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
- card->pctl |= ((wch->bch.nr & 2) ? W_PCTL_PCX : 0);
- WriteW6692(card, W_PCTL, card->pctl);
- return 0;
-}
-#endif
-
-static int
-disable_pots(struct w6692_ch *wch)
-{
- struct w6692_hw *card = wch->bch.hw;
-
- if (!(card->fmask & pots))
- return -ENODEV;
- wch->b_mode &= ~(W_B_MODE_EPCM | W_B_MODE_BSW0);
- WriteW6692B(wch, W_B_MODE, wch->b_mode);
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT |
- W_B_CMDR_XRST);
- return 0;
-}
-
-static int
-w6692_mode(struct w6692_ch *wch, u32 pr)
-{
- struct w6692_hw *card;
-
- card = wch->bch.hw;
- pr_debug("%s: B%d protocol %x-->%x\n", card->name,
- wch->bch.nr, wch->bch.state, pr);
- switch (pr) {
- case ISDN_P_NONE:
- if ((card->fmask & pots) && (wch->b_mode & W_B_MODE_EPCM))
- disable_pots(wch);
- wch->b_mode = 0;
- mISDN_clear_bchannel(&wch->bch);
- WriteW6692B(wch, W_B_MODE, wch->b_mode);
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
- test_and_clear_bit(FLG_HDLC, &wch->bch.Flags);
- test_and_clear_bit(FLG_TRANSPARENT, &wch->bch.Flags);
- break;
- case ISDN_P_B_RAW:
- wch->b_mode = W_B_MODE_MMS;
- WriteW6692B(wch, W_B_MODE, wch->b_mode);
- WriteW6692B(wch, W_B_EXIM, 0);
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT |
- W_B_CMDR_XRST);
- test_and_set_bit(FLG_TRANSPARENT, &wch->bch.Flags);
- break;
- case ISDN_P_B_HDLC:
- wch->b_mode = W_B_MODE_ITF;
- WriteW6692B(wch, W_B_MODE, wch->b_mode);
- WriteW6692B(wch, W_B_ADM1, 0xff);
- WriteW6692B(wch, W_B_ADM2, 0xff);
- WriteW6692B(wch, W_B_EXIM, 0);
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT |
- W_B_CMDR_XRST);
- test_and_set_bit(FLG_HDLC, &wch->bch.Flags);
- break;
- default:
- pr_info("%s: protocol %x not known\n", card->name, pr);
- return -ENOPROTOOPT;
- }
- wch->bch.state = pr;
- return 0;
-}
-
-static void
-send_next(struct w6692_ch *wch)
-{
- if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len) {
- W6692_fill_Bfifo(wch);
- } else {
- dev_kfree_skb(wch->bch.tx_skb);
- if (get_next_bframe(&wch->bch)) {
- W6692_fill_Bfifo(wch);
- test_and_clear_bit(FLG_TX_EMPTY, &wch->bch.Flags);
- } else if (test_bit(FLG_TX_EMPTY, &wch->bch.Flags)) {
- W6692_fill_Bfifo(wch);
- }
- }
-}
-
-static void
-W6692B_interrupt(struct w6692_hw *card, int ch)
-{
- struct w6692_ch *wch = &card->bc[ch];
- int count;
- u8 stat, star = 0;
-
- stat = ReadW6692B(wch, W_B_EXIR);
- pr_debug("%s: B%d EXIR %02x\n", card->name, wch->bch.nr, stat);
- if (stat & W_B_EXI_RME) {
- star = ReadW6692B(wch, W_B_STAR);
- if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) {
- if ((star & W_B_STAR_RDOV) &&
- test_bit(FLG_ACTIVE, &wch->bch.Flags)) {
- pr_debug("%s: B%d RDOV proto=%x\n", card->name,
- wch->bch.nr, wch->bch.state);
-#ifdef ERROR_STATISTIC
- wch->bch.err_rdo++;
-#endif
- }
- if (test_bit(FLG_HDLC, &wch->bch.Flags)) {
- if (star & W_B_STAR_CRCE) {
- pr_debug("%s: B%d CRC error\n",
- card->name, wch->bch.nr);
-#ifdef ERROR_STATISTIC
- wch->bch.err_crc++;
-#endif
- }
- if (star & W_B_STAR_RMB) {
- pr_debug("%s: B%d message abort\n",
- card->name, wch->bch.nr);
-#ifdef ERROR_STATISTIC
- wch->bch.err_inv++;
-#endif
- }
- }
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
- W_B_CMDR_RRST | W_B_CMDR_RACT);
- if (wch->bch.rx_skb)
- skb_trim(wch->bch.rx_skb, 0);
- } else {
- count = ReadW6692B(wch, W_B_RBCL) &
- (W_B_FIFO_THRESH - 1);
- if (count == 0)
- count = W_B_FIFO_THRESH;
- W6692_empty_Bfifo(wch, count);
- recv_Bchannel(&wch->bch, 0, false);
- }
- }
- if (stat & W_B_EXI_RMR) {
- if (!(stat & W_B_EXI_RME))
- star = ReadW6692B(wch, W_B_STAR);
- if (star & W_B_STAR_RDOV) {
- pr_debug("%s: B%d RDOV proto=%x\n", card->name,
- wch->bch.nr, wch->bch.state);
-#ifdef ERROR_STATISTIC
- wch->bch.err_rdo++;
-#endif
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
- W_B_CMDR_RRST | W_B_CMDR_RACT);
- } else {
- W6692_empty_Bfifo(wch, W_B_FIFO_THRESH);
- if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
- recv_Bchannel(&wch->bch, 0, false);
- }
- }
- if (stat & W_B_EXI_RDOV) {
- /* only if it is not handled yet */
- if (!(star & W_B_STAR_RDOV)) {
- pr_debug("%s: B%d RDOV IRQ proto=%x\n", card->name,
- wch->bch.nr, wch->bch.state);
-#ifdef ERROR_STATISTIC
- wch->bch.err_rdo++;
-#endif
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
- W_B_CMDR_RRST | W_B_CMDR_RACT);
- }
- }
- if (stat & W_B_EXI_XFR) {
- if (!(stat & (W_B_EXI_RME | W_B_EXI_RMR))) {
- star = ReadW6692B(wch, W_B_STAR);
- pr_debug("%s: B%d star %02x\n", card->name,
- wch->bch.nr, star);
- }
- if (star & W_B_STAR_XDOW) {
- pr_warn("%s: B%d XDOW proto=%x\n", card->name,
- wch->bch.nr, wch->bch.state);
-#ifdef ERROR_STATISTIC
- wch->bch.err_xdu++;
-#endif
- WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST |
- W_B_CMDR_RACT);
- /* resend */
- if (wch->bch.tx_skb) {
- if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
- wch->bch.tx_idx = 0;
- }
- }
- send_next(wch);
- if (star & W_B_STAR_XDOW)
- return; /* handle XDOW only once */
- }
- if (stat & W_B_EXI_XDUN) {
- pr_warn("%s: B%d XDUN proto=%x\n", card->name,
- wch->bch.nr, wch->bch.state);
-#ifdef ERROR_STATISTIC
- wch->bch.err_xdu++;
-#endif
- /* resend - no XRST needed */
- if (wch->bch.tx_skb) {
- if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
- wch->bch.tx_idx = 0;
- } else if (test_bit(FLG_FILLEMPTY, &wch->bch.Flags)) {
- test_and_set_bit(FLG_TX_EMPTY, &wch->bch.Flags);
- }
- send_next(wch);
- }
-}
-
-static irqreturn_t
-w6692_irq(int intno, void *dev_id)
-{
- struct w6692_hw *card = dev_id;
- u8 ista;
-
- spin_lock(&card->lock);
- ista = ReadW6692(card, W_ISTA);
- if ((ista | card->imask) == card->imask) {
- /* possible a shared IRQ reqest */
- spin_unlock(&card->lock);
- return IRQ_NONE;
- }
- card->irqcnt++;
- pr_debug("%s: ista %02x\n", card->name, ista);
- ista &= ~card->imask;
- if (ista & W_INT_B1_EXI)
- W6692B_interrupt(card, 0);
- if (ista & W_INT_B2_EXI)
- W6692B_interrupt(card, 1);
- if (ista & W_INT_D_RME)
- handle_rxD(card);
- if (ista & W_INT_D_RMR)
- W6692_empty_Dfifo(card, W_D_FIFO_THRESH);
- if (ista & W_INT_D_XFR)
- handle_txD(card);
- if (ista & W_INT_D_EXI)
- handle_statusD(card);
- if (ista & (W_INT_XINT0 | W_INT_XINT1)) /* XINT0/1 - never */
- pr_debug("%s: W6692 spurious XINT!\n", card->name);
-/* End IRQ Handler */
- spin_unlock(&card->lock);
- return IRQ_HANDLED;
-}
-
-static void
-dbusy_timer_handler(struct timer_list *t)
-{
- struct dchannel *dch = timer_container_of(dch, t, timer);
- struct w6692_hw *card = dch->hw;
- int rbch, star;
- u_long flags;
-
- if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) {
- spin_lock_irqsave(&card->lock, flags);
- rbch = ReadW6692(card, W_D_RBCH);
- star = ReadW6692(card, W_D_STAR);
- pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n",
- card->name, rbch, star);
- if (star & W_D_STAR_XBZ) /* D-Channel Busy */
- test_and_set_bit(FLG_L1_BUSY, &dch->Flags);
- else {
- /* discard frame; reset transceiver */
- test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags);
- if (dch->tx_idx)
- dch->tx_idx = 0;
- else
- pr_info("%s: W6692 D-Channel Busy no tx_idx\n",
- card->name);
- /* Transmitter reset */
- WriteW6692(card, W_D_CMDR, W_D_CMDR_XRST);
- }
- spin_unlock_irqrestore(&card->lock, flags);
- }
-}
-
-static void initW6692(struct w6692_hw *card)
-{
- u8 val;
-
- timer_setup(&card->dch.timer, dbusy_timer_handler, 0);
- w6692_mode(&card->bc[0], ISDN_P_NONE);
- w6692_mode(&card->bc[1], ISDN_P_NONE);
- WriteW6692(card, W_D_CTL, 0x00);
- disable_hwirq(card);
- WriteW6692(card, W_D_SAM, 0xff);
- WriteW6692(card, W_D_TAM, 0xff);
- WriteW6692(card, W_D_MODE, W_D_MODE_RACT);
- card->state = W_L1CMD_RST;
- ph_command(card, W_L1CMD_RST);
- ph_command(card, W_L1CMD_ECK);
- /* enable all IRQ but extern */
- card->imask = 0x18;
- WriteW6692(card, W_D_EXIM, 0x00);
- WriteW6692B(&card->bc[0], W_B_EXIM, 0);
- WriteW6692B(&card->bc[1], W_B_EXIM, 0);
- /* Reset D-chan receiver and transmitter */
- WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST);
- /* Reset B-chan receiver and transmitter */
- WriteW6692B(&card->bc[0], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
- WriteW6692B(&card->bc[1], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
- /* enable peripheral */
- if (card->subtype == W6692_USR) {
- /* seems that USR implemented some power control features
- * Pin 79 is connected to the oscilator circuit so we
- * have to handle it here
- */
- card->pctl = 0x80;
- card->xdata = 0;
- WriteW6692(card, W_PCTL, card->pctl);
- WriteW6692(card, W_XDATA, card->xdata);
- } else {
- card->pctl = W_PCTL_OE5 | W_PCTL_OE4 | W_PCTL_OE2 |
- W_PCTL_OE1 | W_PCTL_OE0;
- card->xaddr = 0x00;/* all sw off */
- if (card->fmask & pots)
- card->xdata |= 0x06; /* POWER UP/ LED OFF / ALAW */
- if (card->fmask & led)
- card->xdata |= 0x04; /* LED OFF */
- if ((card->fmask & pots) || (card->fmask & led)) {
- WriteW6692(card, W_PCTL, card->pctl);
- WriteW6692(card, W_XADDR, card->xaddr);
- WriteW6692(card, W_XDATA, card->xdata);
- val = ReadW6692(card, W_XADDR);
- if (debug & DEBUG_HW)
- pr_notice("%s: W_XADDR=%02x\n",
- card->name, val);
- }
- }
-}
-
-static void
-reset_w6692(struct w6692_hw *card)
-{
- WriteW6692(card, W_D_CTL, W_D_CTL_SRST);
- mdelay(10);
- WriteW6692(card, W_D_CTL, 0);
-}
-
-static int
-init_card(struct w6692_hw *card)
-{
- int cnt = 3;
- u_long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- disable_hwirq(card);
- spin_unlock_irqrestore(&card->lock, flags);
- if (request_irq(card->irq, w6692_irq, IRQF_SHARED, card->name, card)) {
- pr_info("%s: couldn't get interrupt %d\n", card->name,
- card->irq);
- return -EIO;
- }
- while (cnt--) {
- spin_lock_irqsave(&card->lock, flags);
- initW6692(card);
- enable_hwirq(card);
- spin_unlock_irqrestore(&card->lock, flags);
- /* Timeout 10ms */
- msleep_interruptible(10);
- if (debug & DEBUG_HW)
- pr_notice("%s: IRQ %d count %d\n", card->name,
- card->irq, card->irqcnt);
- if (!card->irqcnt) {
- pr_info("%s: IRQ(%d) getting no IRQs during init %d\n",
- card->name, card->irq, 3 - cnt);
- reset_w6692(card);
- } else
- return 0;
- }
- free_irq(card->irq, card);
- return -EIO;
-}
-
-static int
-w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch);
- struct w6692_hw *card = bch->hw;
- int ret = -EINVAL;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- unsigned long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- spin_lock_irqsave(&card->lock, flags);
- ret = bchannel_senddata(bch, skb);
- if (ret > 0) { /* direct TX */
- ret = 0;
- W6692_fill_Bfifo(bc);
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return ret;
- case PH_ACTIVATE_REQ:
- spin_lock_irqsave(&card->lock, flags);
- if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
- ret = w6692_mode(bc, ch->protocol);
- else
- ret = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- if (!ret)
- _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- break;
- case PH_DEACTIVATE_REQ:
- spin_lock_irqsave(&card->lock, flags);
- mISDN_clear_bchannel(bch);
- w6692_mode(bc, ISDN_P_NONE);
- spin_unlock_irqrestore(&card->lock, flags);
- _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- ret = 0;
- break;
- default:
- pr_info("%s: %s unknown prim(%x,%x)\n",
- card->name, __func__, hh->prim, hh->id);
- ret = -EINVAL;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static int
-channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
-{
- return mISDN_ctrl_bchannel(bch, cq);
-}
-
-static int
-open_bchannel(struct w6692_hw *card, struct channel_req *rq)
-{
- struct bchannel *bch;
-
- if (rq->adr.channel == 0 || rq->adr.channel > 2)
- return -EINVAL;
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
- bch = &card->bc[rq->adr.channel - 1].bch;
- if (test_and_set_bit(FLG_OPEN, &bch->Flags))
- return -EBUSY; /* b-channel can be only open once */
- bch->ch.protocol = rq->protocol;
- rq->ch = &bch->ch;
- return 0;
-}
-
-static int
-channel_ctrl(struct w6692_hw *card, struct mISDN_ctrl_req *cq)
-{
- int ret = 0;
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_L1_TIMER3;
- break;
- case MISDN_CTRL_L1_TIMER3:
- ret = l1_event(card->dch.l1, HW_TIMER3_VALUE | (cq->p1 & 0xff));
- break;
- default:
- pr_info("%s: unknown CTRL OP %x\n", card->name, cq->op);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int
-w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch);
- struct w6692_hw *card = bch->hw;
- int ret = -EINVAL;
- u_long flags;
-
- pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
- switch (cmd) {
- case CLOSE_CHANNEL:
- test_and_clear_bit(FLG_OPEN, &bch->Flags);
- cancel_work_sync(&bch->workq);
- spin_lock_irqsave(&card->lock, flags);
- mISDN_clear_bchannel(bch);
- w6692_mode(bc, ISDN_P_NONE);
- spin_unlock_irqrestore(&card->lock, flags);
- ch->protocol = ISDN_P_NONE;
- ch->peer = NULL;
- module_put(THIS_MODULE);
- ret = 0;
- break;
- case CONTROL_CHANNEL:
- ret = channel_bctrl(bch, arg);
- break;
- default:
- pr_info("%s: %s unknown prim(%x)\n",
- card->name, __func__, cmd);
- }
- return ret;
-}
-
-static int
-w6692_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct w6692_hw *card = container_of(dch, struct w6692_hw, dch);
- int ret = -EINVAL;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- u32 id;
- u_long flags;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- spin_lock_irqsave(&card->lock, flags);
- ret = dchannel_senddata(dch, skb);
- if (ret > 0) { /* direct TX */
- id = hh->id; /* skb can be freed */
- W6692_fill_Dfifo(card);
- ret = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
- } else
- spin_unlock_irqrestore(&card->lock, flags);
- return ret;
- case PH_ACTIVATE_REQ:
- ret = l1_event(dch->l1, hh->prim);
- break;
- case PH_DEACTIVATE_REQ:
- test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
- ret = l1_event(dch->l1, hh->prim);
- break;
- }
-
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static int
-w6692_l1callback(struct dchannel *dch, u32 cmd)
-{
- struct w6692_hw *card = container_of(dch, struct w6692_hw, dch);
- u_long flags;
-
- pr_debug("%s: cmd(%x) state(%02x)\n", card->name, cmd, card->state);
- switch (cmd) {
- case INFO3_P8:
- spin_lock_irqsave(&card->lock, flags);
- ph_command(card, W_L1CMD_AR8);
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- case INFO3_P10:
- spin_lock_irqsave(&card->lock, flags);
- ph_command(card, W_L1CMD_AR10);
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- case HW_RESET_REQ:
- spin_lock_irqsave(&card->lock, flags);
- if (card->state != W_L1IND_DRD)
- ph_command(card, W_L1CMD_RST);
- ph_command(card, W_L1CMD_ECK);
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- case HW_DEACT_REQ:
- skb_queue_purge(&dch->squeue);
- if (dch->tx_skb) {
- dev_kfree_skb(dch->tx_skb);
- dch->tx_skb = NULL;
- }
- dch->tx_idx = 0;
- if (dch->rx_skb) {
- dev_kfree_skb(dch->rx_skb);
- dch->rx_skb = NULL;
- }
- test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
- if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
- timer_delete(&dch->timer);
- break;
- case HW_POWERUP_REQ:
- spin_lock_irqsave(&card->lock, flags);
- ph_command(card, W_L1CMD_ECK);
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- case PH_ACTIVATE_IND:
- test_and_set_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
- GFP_ATOMIC);
- break;
- case PH_DEACTIVATE_IND:
- test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
- GFP_ATOMIC);
- break;
- default:
- pr_debug("%s: %s unknown command %x\n", card->name,
- __func__, cmd);
- return -1;
- }
- return 0;
-}
-
-static int
-open_dchannel(struct w6692_hw *card, struct channel_req *rq, void *caller)
-{
- pr_debug("%s: %s dev(%d) open from %p\n", card->name, __func__,
- card->dch.dev.id, caller);
- if (rq->protocol != ISDN_P_TE_S0)
- return -EINVAL;
- if (rq->adr.channel == 1)
- /* E-Channel not supported */
- return -EINVAL;
- rq->ch = &card->dch.dev.D;
- rq->ch->protocol = rq->protocol;
- if (card->dch.state == 7)
- _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
- 0, NULL, GFP_KERNEL);
- return 0;
-}
-
-static int
-w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct w6692_hw *card = container_of(dch, struct w6692_hw, dch);
- struct channel_req *rq;
- int err = 0;
-
- pr_debug("%s: DCTRL: %x %p\n", card->name, cmd, arg);
- switch (cmd) {
- case OPEN_CHANNEL:
- rq = arg;
- if (rq->protocol == ISDN_P_TE_S0)
- err = open_dchannel(card, rq, __builtin_return_address(0));
- else
- err = open_bchannel(card, rq);
- if (err)
- break;
- if (!try_module_get(THIS_MODULE))
- pr_info("%s: cannot get module\n", card->name);
- break;
- case CLOSE_CHANNEL:
- pr_debug("%s: dev(%d) close from %p\n", card->name,
- dch->dev.id, __builtin_return_address(0));
- module_put(THIS_MODULE);
- break;
- case CONTROL_CHANNEL:
- err = channel_ctrl(card, arg);
- break;
- default:
- pr_debug("%s: unknown DCTRL command %x\n", card->name, cmd);
- return -EINVAL;
- }
- return err;
-}
-
-static int
-setup_w6692(struct w6692_hw *card)
-{
- u32 val;
-
- if (!request_region(card->addr, 256, card->name)) {
- pr_info("%s: config port %x-%x already in use\n", card->name,
- card->addr, card->addr + 255);
- return -EIO;
- }
- W6692Version(card);
- card->bc[0].addr = card->addr;
- card->bc[1].addr = card->addr + 0x40;
- val = ReadW6692(card, W_ISTA);
- if (debug & DEBUG_HW)
- pr_notice("%s ISTA=%02x\n", card->name, val);
- val = ReadW6692(card, W_IMASK);
- if (debug & DEBUG_HW)
- pr_notice("%s IMASK=%02x\n", card->name, val);
- val = ReadW6692(card, W_D_EXIR);
- if (debug & DEBUG_HW)
- pr_notice("%s D_EXIR=%02x\n", card->name, val);
- val = ReadW6692(card, W_D_EXIM);
- if (debug & DEBUG_HW)
- pr_notice("%s D_EXIM=%02x\n", card->name, val);
- val = ReadW6692(card, W_D_RSTA);
- if (debug & DEBUG_HW)
- pr_notice("%s D_RSTA=%02x\n", card->name, val);
- return 0;
-}
-
-static void
-release_card(struct w6692_hw *card)
-{
- u_long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- disable_hwirq(card);
- w6692_mode(&card->bc[0], ISDN_P_NONE);
- w6692_mode(&card->bc[1], ISDN_P_NONE);
- if ((card->fmask & led) || card->subtype == W6692_USR) {
- card->xdata |= 0x04; /* LED OFF */
- WriteW6692(card, W_XDATA, card->xdata);
- }
- spin_unlock_irqrestore(&card->lock, flags);
- free_irq(card->irq, card);
- l1_event(card->dch.l1, CLOSE_CHANNEL);
- mISDN_unregister_device(&card->dch.dev);
- release_region(card->addr, 256);
- mISDN_freebchannel(&card->bc[1].bch);
- mISDN_freebchannel(&card->bc[0].bch);
- mISDN_freedchannel(&card->dch);
- write_lock_irqsave(&card_lock, flags);
- list_del(&card->list);
- write_unlock_irqrestore(&card_lock, flags);
- pci_disable_device(card->pdev);
- pci_set_drvdata(card->pdev, NULL);
- kfree(card);
-}
-
-static int
-setup_instance(struct w6692_hw *card)
-{
- int i, err;
- u_long flags;
-
- snprintf(card->name, MISDN_MAX_IDLEN - 1, "w6692.%d", w6692_cnt + 1);
- write_lock_irqsave(&card_lock, flags);
- list_add_tail(&card->list, &Cards);
- write_unlock_irqrestore(&card_lock, flags);
- card->fmask = (1 << w6692_cnt);
- _set_debug(card);
- spin_lock_init(&card->lock);
- mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, W6692_ph_bh);
- card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0);
- card->dch.dev.D.send = w6692_l2l1D;
- card->dch.dev.D.ctrl = w6692_dctrl;
- card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
- card->dch.hw = card;
- card->dch.dev.nrbchan = 2;
- for (i = 0; i < 2; i++) {
- mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM,
- W_B_FIFO_THRESH);
- card->bc[i].bch.hw = card;
- card->bc[i].bch.nr = i + 1;
- card->bc[i].bch.ch.nr = i + 1;
- card->bc[i].bch.ch.send = w6692_l2l1B;
- card->bc[i].bch.ch.ctrl = w6692_bctrl;
- set_channelmap(i + 1, card->dch.dev.channelmap);
- list_add(&card->bc[i].bch.ch.list, &card->dch.dev.bchannels);
- }
- err = setup_w6692(card);
- if (err)
- goto error_setup;
- err = mISDN_register_device(&card->dch.dev, &card->pdev->dev,
- card->name);
- if (err)
- goto error_reg;
- err = init_card(card);
- if (err)
- goto error_init;
- err = create_l1(&card->dch, w6692_l1callback);
- if (!err) {
- w6692_cnt++;
- pr_notice("W6692 %d cards installed\n", w6692_cnt);
- return 0;
- }
-
- free_irq(card->irq, card);
-error_init:
- mISDN_unregister_device(&card->dch.dev);
-error_reg:
- release_region(card->addr, 256);
-error_setup:
- mISDN_freebchannel(&card->bc[1].bch);
- mISDN_freebchannel(&card->bc[0].bch);
- mISDN_freedchannel(&card->dch);
- write_lock_irqsave(&card_lock, flags);
- list_del(&card->list);
- write_unlock_irqrestore(&card_lock, flags);
- kfree(card);
- return err;
-}
-
-static int
-w6692_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int err = -ENOMEM;
- struct w6692_hw *card;
- struct w6692map *m = (struct w6692map *)ent->driver_data;
-
- card = kzalloc_obj(struct w6692_hw);
- if (!card) {
- pr_info("No kmem for w6692 card\n");
- return err;
- }
- card->pdev = pdev;
- card->subtype = m->subtype;
- err = pci_enable_device(pdev);
- if (err) {
- kfree(card);
- return err;
- }
-
- printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n",
- m->name, pci_name(pdev));
-
- card->addr = pci_resource_start(pdev, 1);
- card->irq = pdev->irq;
- pci_set_drvdata(pdev, card);
- err = setup_instance(card);
- if (err)
- pci_set_drvdata(pdev, NULL);
- return err;
-}
-
-static void
-w6692_remove_pci(struct pci_dev *pdev)
-{
- struct w6692_hw *card = pci_get_drvdata(pdev);
-
- if (card)
- release_card(card);
- else
- if (debug)
- pr_notice("%s: drvdata already removed\n", __func__);
-}
-
-static const struct pci_device_id w6692_ids[] = {
- { PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[0]},
- { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692,
- PCI_VENDOR_ID_USR, PCI_DEVICE_ID_USR_6692, 0, 0,
- (ulong)&w6692_map[2]},
- { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[1]},
- { }
-};
-MODULE_DEVICE_TABLE(pci, w6692_ids);
-
-static struct pci_driver w6692_driver = {
- .name = "w6692",
- .probe = w6692_probe,
- .remove = w6692_remove_pci,
- .id_table = w6692_ids,
-};
-
-static int __init w6692_init(void)
-{
- int err;
-
- pr_notice("Winbond W6692 PCI driver Rev. %s\n", W6692_REV);
-
- err = pci_register_driver(&w6692_driver);
- return err;
-}
-
-static void __exit w6692_cleanup(void)
-{
- pci_unregister_driver(&w6692_driver);
-}
-
-module_init(w6692_init);
-module_exit(w6692_cleanup);
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Winbond W6692 specific defines
- *
- * Author Karsten Keil <keil@isdn4linux.de>
- * based on the w6692 I4L driver from Petr Novak <petr.novak@i.cz>
- *
- * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
- */
-
-/* Specifications of W6692 registers */
-
-#define W_D_RFIFO 0x00 /* R */
-#define W_D_XFIFO 0x04 /* W */
-#define W_D_CMDR 0x08 /* W */
-#define W_D_MODE 0x0c /* R/W */
-#define W_D_TIMR 0x10 /* R/W */
-#define W_ISTA 0x14 /* R_clr */
-#define W_IMASK 0x18 /* R/W */
-#define W_D_EXIR 0x1c /* R_clr */
-#define W_D_EXIM 0x20 /* R/W */
-#define W_D_STAR 0x24 /* R */
-#define W_D_RSTA 0x28 /* R */
-#define W_D_SAM 0x2c /* R/W */
-#define W_D_SAP1 0x30 /* R/W */
-#define W_D_SAP2 0x34 /* R/W */
-#define W_D_TAM 0x38 /* R/W */
-#define W_D_TEI1 0x3c /* R/W */
-#define W_D_TEI2 0x40 /* R/W */
-#define W_D_RBCH 0x44 /* R */
-#define W_D_RBCL 0x48 /* R */
-#define W_TIMR2 0x4c /* W */
-#define W_L1_RC 0x50 /* R/W */
-#define W_D_CTL 0x54 /* R/W */
-#define W_CIR 0x58 /* R */
-#define W_CIX 0x5c /* W */
-#define W_SQR 0x60 /* R */
-#define W_SQX 0x64 /* W */
-#define W_PCTL 0x68 /* R/W */
-#define W_MOR 0x6c /* R */
-#define W_MOX 0x70 /* R/W */
-#define W_MOSR 0x74 /* R_clr */
-#define W_MOCR 0x78 /* R/W */
-#define W_GCR 0x7c /* R/W */
-
-#define W_B_RFIFO 0x80 /* R */
-#define W_B_XFIFO 0x84 /* W */
-#define W_B_CMDR 0x88 /* W */
-#define W_B_MODE 0x8c /* R/W */
-#define W_B_EXIR 0x90 /* R_clr */
-#define W_B_EXIM 0x94 /* R/W */
-#define W_B_STAR 0x98 /* R */
-#define W_B_ADM1 0x9c /* R/W */
-#define W_B_ADM2 0xa0 /* R/W */
-#define W_B_ADR1 0xa4 /* R/W */
-#define W_B_ADR2 0xa8 /* R/W */
-#define W_B_RBCL 0xac /* R */
-#define W_B_RBCH 0xb0 /* R */
-
-#define W_XADDR 0xf4 /* R/W */
-#define W_XDATA 0xf8 /* R/W */
-#define W_EPCTL 0xfc /* W */
-
-/* W6692 register bits */
-
-#define W_D_CMDR_XRST 0x01
-#define W_D_CMDR_XME 0x02
-#define W_D_CMDR_XMS 0x08
-#define W_D_CMDR_STT 0x10
-#define W_D_CMDR_RRST 0x40
-#define W_D_CMDR_RACK 0x80
-
-#define W_D_MODE_RLP 0x01
-#define W_D_MODE_DLP 0x02
-#define W_D_MODE_MFD 0x04
-#define W_D_MODE_TEE 0x08
-#define W_D_MODE_TMS 0x10
-#define W_D_MODE_RACT 0x40
-#define W_D_MODE_MMS 0x80
-
-#define W_INT_B2_EXI 0x01
-#define W_INT_B1_EXI 0x02
-#define W_INT_D_EXI 0x04
-#define W_INT_XINT0 0x08
-#define W_INT_XINT1 0x10
-#define W_INT_D_XFR 0x20
-#define W_INT_D_RME 0x40
-#define W_INT_D_RMR 0x80
-
-#define W_D_EXI_WEXP 0x01
-#define W_D_EXI_TEXP 0x02
-#define W_D_EXI_ISC 0x04
-#define W_D_EXI_MOC 0x08
-#define W_D_EXI_TIN2 0x10
-#define W_D_EXI_XCOL 0x20
-#define W_D_EXI_XDUN 0x40
-#define W_D_EXI_RDOV 0x80
-
-#define W_D_STAR_DRDY 0x10
-#define W_D_STAR_XBZ 0x20
-#define W_D_STAR_XDOW 0x80
-
-#define W_D_RSTA_RMB 0x10
-#define W_D_RSTA_CRCE 0x20
-#define W_D_RSTA_RDOV 0x40
-
-#define W_D_CTL_SRST 0x20
-
-#define W_CIR_SCC 0x80
-#define W_CIR_ICC 0x40
-#define W_CIR_COD_MASK 0x0f
-
-#define W_PCTL_PCX 0x01
-#define W_PCTL_XMODE 0x02
-#define W_PCTL_OE0 0x04
-#define W_PCTL_OE1 0x08
-#define W_PCTL_OE2 0x10
-#define W_PCTL_OE3 0x20
-#define W_PCTL_OE4 0x40
-#define W_PCTL_OE5 0x80
-
-#define W_B_CMDR_XRST 0x01
-#define W_B_CMDR_XME 0x02
-#define W_B_CMDR_XMS 0x04
-#define W_B_CMDR_RACT 0x20
-#define W_B_CMDR_RRST 0x40
-#define W_B_CMDR_RACK 0x80
-
-#define W_B_MODE_FTS0 0x01
-#define W_B_MODE_FTS1 0x02
-#define W_B_MODE_SW56 0x04
-#define W_B_MODE_BSW0 0x08
-#define W_B_MODE_BSW1 0x10
-#define W_B_MODE_EPCM 0x20
-#define W_B_MODE_ITF 0x40
-#define W_B_MODE_MMS 0x80
-
-#define W_B_EXI_XDUN 0x01
-#define W_B_EXI_XFR 0x02
-#define W_B_EXI_RDOV 0x10
-#define W_B_EXI_RME 0x20
-#define W_B_EXI_RMR 0x40
-
-#define W_B_STAR_XBZ 0x01
-#define W_B_STAR_XDOW 0x04
-#define W_B_STAR_RMB 0x10
-#define W_B_STAR_CRCE 0x20
-#define W_B_STAR_RDOV 0x40
-
-#define W_B_RBCH_LOV 0x20
-
-/* W6692 Layer1 commands */
-
-#define W_L1CMD_ECK 0x00
-#define W_L1CMD_RST 0x01
-#define W_L1CMD_SCP 0x04
-#define W_L1CMD_SSP 0x02
-#define W_L1CMD_AR8 0x08
-#define W_L1CMD_AR10 0x09
-#define W_L1CMD_EAL 0x0a
-#define W_L1CMD_DRC 0x0f
-
-/* W6692 Layer1 indications */
-
-#define W_L1IND_CE 0x07
-#define W_L1IND_DRD 0x00
-#define W_L1IND_LD 0x04
-#define W_L1IND_ARD 0x08
-#define W_L1IND_TI 0x0a
-#define W_L1IND_ATI 0x0b
-#define W_L1IND_AI8 0x0c
-#define W_L1IND_AI10 0x0d
-#define W_L1IND_CD 0x0f
-
-/* FIFO thresholds */
-#define W_D_FIFO_THRESH 64
-#define W_B_FIFO_THRESH 64
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# modularer ISDN driver
-#
-
-menuconfig MISDN
- tristate "Modular ISDN driver"
- help
- Enable support for the modular ISDN driver.
-
-if MISDN != n
-
-config MISDN_DSP
- tristate "Digital Audio Processing of transparent data"
- depends on MISDN
- select BITREVERSE
- help
- Enable support for digital audio processing capability.
-
- This module may be used for special applications that require
- cross connecting of bchannels, conferencing, dtmf decoding,
- echo cancellation, tone generation, and Blowfish encryption and
- decryption. It may use hardware features if available.
-
- E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu
- and get more information about this module and its usage.
-
- If unsure, say 'N'.
-
-config MISDN_L1OIP
- tristate "ISDN over IP tunnel"
- depends on MISDN
- help
- Enable support for ISDN over IP tunnel.
-
- It features:
- - dynamic IP exchange, if one or both peers have dynamic IPs
- - BRI (S0) and PRI (S2M) interface
- - layer 1 control via network keepalive frames
- - direct tunneling of physical interface via IP
-
- NOTE: This protocol is called 'Layer 1 over IP' and is not
- compatible with ISDNoIP (Agfeo) or TDMoIP. Protocol description is
- provided in the source code.
-
-source "drivers/isdn/hardware/mISDN/Kconfig"
-
-endif #MISDN
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for the modular ISDN driver
-#
-
-obj-$(CONFIG_MISDN) += mISDN_core.o
-obj-$(CONFIG_MISDN_DSP) += mISDN_dsp.o
-obj-$(CONFIG_MISDN_L1OIP) += l1oip.o
-
-# multi objects
-
-mISDN_core-objs := core.o fsm.o socket.o clock.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o
-mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_pipeline.o dsp_hwec.o
-l1oip-objs := l1oip_core.o l1oip_codec.o
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright 2008 by Andreas Eversberg <andreas@eversberg.eu>
- *
- * Quick API description:
- *
- * A clock source registers using mISDN_register_clock:
- * name = text string to name clock source
- * priority = value to priorize clock sources (0 = default)
- * ctl = callback function to enable/disable clock source
- * priv = private pointer of clock source
- * return = pointer to clock source structure;
- *
- * Note: Callback 'ctl' can be called before mISDN_register_clock returns!
- * Also it can be called during mISDN_unregister_clock.
- *
- * A clock source calls mISDN_clock_update with given samples elapsed, if
- * enabled. If function call is delayed, tv must be set with the timestamp
- * of the actual event.
- *
- * A clock source unregisters using mISDN_unregister_clock.
- *
- * To get current clock, call mISDN_clock_get. The signed short value
- * counts the number of samples since. Time since last clock event is added.
- */
-
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/spinlock.h>
-#include <linux/ktime.h>
-#include <linux/mISDNif.h>
-#include <linux/export.h>
-#include "core.h"
-
-static u_int *debug;
-static LIST_HEAD(iclock_list);
-static DEFINE_RWLOCK(iclock_lock);
-static u16 iclock_count; /* counter of last clock */
-static ktime_t iclock_timestamp; /* time stamp of last clock */
-static int iclock_timestamp_valid; /* already received one timestamp */
-static struct mISDNclock *iclock_current;
-
-void
-mISDN_init_clock(u_int *dp)
-{
- debug = dp;
- iclock_timestamp = ktime_get();
-}
-
-static void
-select_iclock(void)
-{
- struct mISDNclock *iclock, *bestclock = NULL, *lastclock = NULL;
- int pri = -128;
-
- list_for_each_entry(iclock, &iclock_list, list) {
- if (iclock->pri > pri) {
- pri = iclock->pri;
- bestclock = iclock;
- }
- if (iclock_current == iclock)
- lastclock = iclock;
- }
- if (lastclock && bestclock != lastclock) {
- /* last used clock source still exists but changes, disable */
- if (*debug & DEBUG_CLOCK)
- printk(KERN_DEBUG "Old clock source '%s' disable.\n",
- lastclock->name);
- lastclock->ctl(lastclock->priv, 0);
- }
- if (bestclock && bestclock != iclock_current) {
- /* new clock source selected, enable */
- if (*debug & DEBUG_CLOCK)
- printk(KERN_DEBUG "New clock source '%s' enable.\n",
- bestclock->name);
- bestclock->ctl(bestclock->priv, 1);
- }
- if (bestclock != iclock_current) {
- /* no clock received yet */
- iclock_timestamp_valid = 0;
- }
- iclock_current = bestclock;
-}
-
-struct mISDNclock
-*mISDN_register_clock(char *name, int pri, clockctl_func_t *ctl, void *priv)
-{
- u_long flags;
- struct mISDNclock *iclock;
-
- if (*debug & (DEBUG_CORE | DEBUG_CLOCK))
- printk(KERN_DEBUG "%s: %s %d\n", __func__, name, pri);
- iclock = kzalloc_obj(struct mISDNclock, GFP_ATOMIC);
- if (!iclock) {
- printk(KERN_ERR "%s: No memory for clock entry.\n", __func__);
- return NULL;
- }
- strscpy(iclock->name, name, sizeof(iclock->name));
- iclock->pri = pri;
- iclock->priv = priv;
- iclock->ctl = ctl;
- write_lock_irqsave(&iclock_lock, flags);
- list_add_tail(&iclock->list, &iclock_list);
- select_iclock();
- write_unlock_irqrestore(&iclock_lock, flags);
- return iclock;
-}
-EXPORT_SYMBOL(mISDN_register_clock);
-
-void
-mISDN_unregister_clock(struct mISDNclock *iclock)
-{
- u_long flags;
-
- if (*debug & (DEBUG_CORE | DEBUG_CLOCK))
- printk(KERN_DEBUG "%s: %s %d\n", __func__, iclock->name,
- iclock->pri);
- write_lock_irqsave(&iclock_lock, flags);
- if (iclock_current == iclock) {
- if (*debug & DEBUG_CLOCK)
- printk(KERN_DEBUG
- "Current clock source '%s' unregisters.\n",
- iclock->name);
- iclock->ctl(iclock->priv, 0);
- }
- list_del(&iclock->list);
- select_iclock();
- write_unlock_irqrestore(&iclock_lock, flags);
-}
-EXPORT_SYMBOL(mISDN_unregister_clock);
-
-void
-mISDN_clock_update(struct mISDNclock *iclock, int samples, ktime_t *timestamp)
-{
- u_long flags;
- ktime_t timestamp_now;
- u16 delta;
-
- write_lock_irqsave(&iclock_lock, flags);
- if (iclock_current != iclock) {
- printk(KERN_ERR "%s: '%s' sends us clock updates, but we do "
- "listen to '%s'. This is a bug!\n", __func__,
- iclock->name,
- iclock_current ? iclock_current->name : "nothing");
- iclock->ctl(iclock->priv, 0);
- write_unlock_irqrestore(&iclock_lock, flags);
- return;
- }
- if (iclock_timestamp_valid) {
- /* increment sample counter by given samples */
- iclock_count += samples;
- if (timestamp) { /* timestamp must be set, if function call is delayed */
- iclock_timestamp = *timestamp;
- } else {
- iclock_timestamp = ktime_get();
- }
- } else {
- /* calc elapsed time by system clock */
- if (timestamp) { /* timestamp must be set, if function call is delayed */
- timestamp_now = *timestamp;
- } else {
- timestamp_now = ktime_get();
- }
- delta = ktime_divns(ktime_sub(timestamp_now, iclock_timestamp),
- (NSEC_PER_SEC / 8000));
- /* add elapsed time to counter and set new timestamp */
- iclock_count += delta;
- iclock_timestamp = timestamp_now;
- iclock_timestamp_valid = 1;
- if (*debug & DEBUG_CLOCK)
- printk("Received first clock from source '%s'.\n",
- iclock_current ? iclock_current->name : "nothing");
- }
- write_unlock_irqrestore(&iclock_lock, flags);
-}
-EXPORT_SYMBOL(mISDN_clock_update);
-
-unsigned short
-mISDN_clock_get(void)
-{
- u_long flags;
- ktime_t timestamp_now;
- u16 delta;
- u16 count;
-
- read_lock_irqsave(&iclock_lock, flags);
- /* calc elapsed time by system clock */
- timestamp_now = ktime_get();
- delta = ktime_divns(ktime_sub(timestamp_now, iclock_timestamp),
- (NSEC_PER_SEC / 8000));
- /* add elapsed time to counter */
- count = iclock_count + delta;
- read_unlock_irqrestore(&iclock_lock, flags);
- return count;
-}
-EXPORT_SYMBOL(mISDN_clock_get);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/mISDNif.h>
-#include "core.h"
-
-static u_int debug;
-
-MODULE_AUTHOR("Karsten Keil");
-MODULE_DESCRIPTION("Modular ISDN core driver");
-MODULE_LICENSE("GPL");
-module_param(debug, uint, S_IRUGO | S_IWUSR);
-
-static u64 device_ids;
-#define MAX_DEVICE_ID 63
-
-static LIST_HEAD(Bprotocols);
-static DEFINE_RWLOCK(bp_lock);
-
-static void mISDN_dev_release(struct device *dev)
-{
- /* nothing to do: the device is part of its parent's data structure */
-}
-
-static ssize_t id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mISDNdevice *mdev = dev_to_mISDN(dev);
-
- if (!mdev)
- return -ENODEV;
- return sprintf(buf, "%d\n", mdev->id);
-}
-static DEVICE_ATTR_RO(id);
-
-static ssize_t nrbchan_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mISDNdevice *mdev = dev_to_mISDN(dev);
-
- if (!mdev)
- return -ENODEV;
- return sprintf(buf, "%d\n", mdev->nrbchan);
-}
-static DEVICE_ATTR_RO(nrbchan);
-
-static ssize_t d_protocols_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mISDNdevice *mdev = dev_to_mISDN(dev);
-
- if (!mdev)
- return -ENODEV;
- return sprintf(buf, "%d\n", mdev->Dprotocols);
-}
-static DEVICE_ATTR_RO(d_protocols);
-
-static ssize_t b_protocols_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mISDNdevice *mdev = dev_to_mISDN(dev);
-
- if (!mdev)
- return -ENODEV;
- return sprintf(buf, "%d\n", mdev->Bprotocols | get_all_Bprotocols());
-}
-static DEVICE_ATTR_RO(b_protocols);
-
-static ssize_t protocol_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mISDNdevice *mdev = dev_to_mISDN(dev);
-
- if (!mdev)
- return -ENODEV;
- return sprintf(buf, "%d\n", mdev->D.protocol);
-}
-static DEVICE_ATTR_RO(protocol);
-
-static ssize_t name_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- strcpy(buf, dev_name(dev));
- return strlen(buf);
-}
-static DEVICE_ATTR_RO(name);
-
-#if 0 /* hangs */
-static ssize_t name_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int err = 0;
- char *out = kmalloc(count + 1, GFP_KERNEL);
-
- if (!out)
- return -ENOMEM;
-
- memcpy(out, buf, count);
- if (count && out[count - 1] == '\n')
- out[--count] = 0;
- if (count)
- err = device_rename(dev, out);
- kfree(out);
-
- return (err < 0) ? err : count;
-}
-static DEVICE_ATTR_RW(name);
-#endif
-
-static ssize_t channelmap_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mISDNdevice *mdev = dev_to_mISDN(dev);
- char *bp = buf;
- int i;
-
- for (i = 0; i <= mdev->nrbchan; i++)
- *bp++ = test_channelmap(i, mdev->channelmap) ? '1' : '0';
-
- return bp - buf;
-}
-static DEVICE_ATTR_RO(channelmap);
-
-static struct attribute *mISDN_attrs[] = {
- &dev_attr_id.attr,
- &dev_attr_d_protocols.attr,
- &dev_attr_b_protocols.attr,
- &dev_attr_protocol.attr,
- &dev_attr_channelmap.attr,
- &dev_attr_nrbchan.attr,
- &dev_attr_name.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(mISDN);
-
-static int mISDN_uevent(const struct device *dev, struct kobj_uevent_env *env)
-{
- const struct mISDNdevice *mdev = dev_to_mISDN(dev);
-
- if (!mdev)
- return 0;
-
- if (add_uevent_var(env, "nchans=%d", mdev->nrbchan))
- return -ENOMEM;
-
- return 0;
-}
-
-static struct class mISDN_class = {
- .name = "mISDN",
- .dev_uevent = mISDN_uevent,
- .dev_groups = mISDN_groups,
- .dev_release = mISDN_dev_release,
-};
-
-static int
-_get_mdevice(struct device *dev, const void *id)
-{
- struct mISDNdevice *mdev = dev_to_mISDN(dev);
-
- if (!mdev)
- return 0;
- if (mdev->id != *(const u_int *)id)
- return 0;
- return 1;
-}
-
-struct mISDNdevice
-*get_mdevice(u_int id)
-{
- return dev_to_mISDN(class_find_device(&mISDN_class, NULL, &id,
- _get_mdevice));
-}
-
-static int
-_get_mdevice_count(struct device *dev, void *cnt)
-{
- *(int *)cnt += 1;
- return 0;
-}
-
-int
-get_mdevice_count(void)
-{
- int cnt = 0;
-
- class_for_each_device(&mISDN_class, NULL, &cnt, _get_mdevice_count);
- return cnt;
-}
-
-static int
-get_free_devid(void)
-{
- u_int i;
-
- for (i = 0; i <= MAX_DEVICE_ID; i++)
- if (!test_and_set_bit(i, (u_long *)&device_ids))
- break;
- if (i > MAX_DEVICE_ID)
- return -EBUSY;
- return i;
-}
-
-int
-mISDN_register_device(struct mISDNdevice *dev,
- struct device *parent, char *name)
-{
- int err;
-
- err = get_free_devid();
- if (err < 0)
- return err;
- dev->id = err;
-
- device_initialize(&dev->dev);
- if (name && name[0])
- dev_set_name(&dev->dev, "%s", name);
- else
- dev_set_name(&dev->dev, "mISDN%d", dev->id);
- if (debug & DEBUG_CORE)
- printk(KERN_DEBUG "mISDN_register %s %d\n",
- dev_name(&dev->dev), dev->id);
- dev->dev.class = &mISDN_class;
-
- err = create_stack(dev);
- if (err)
- goto error1;
-
- dev->dev.platform_data = dev;
- dev->dev.parent = parent;
- dev_set_drvdata(&dev->dev, dev);
-
- err = device_add(&dev->dev);
- if (err)
- goto error3;
- return 0;
-
-error3:
- delete_stack(dev);
-error1:
- put_device(&dev->dev);
- return err;
-
-}
-EXPORT_SYMBOL(mISDN_register_device);
-
-void
-mISDN_unregister_device(struct mISDNdevice *dev) {
- if (debug & DEBUG_CORE)
- printk(KERN_DEBUG "mISDN_unregister %s %d\n",
- dev_name(&dev->dev), dev->id);
- /* sysfs_remove_link(&dev->dev.kobj, "device"); */
- device_del(&dev->dev);
- dev_set_drvdata(&dev->dev, NULL);
-
- test_and_clear_bit(dev->id, (u_long *)&device_ids);
- delete_stack(dev);
- put_device(&dev->dev);
-}
-EXPORT_SYMBOL(mISDN_unregister_device);
-
-u_int
-get_all_Bprotocols(void)
-{
- struct Bprotocol *bp;
- u_int m = 0;
-
- read_lock(&bp_lock);
- list_for_each_entry(bp, &Bprotocols, list)
- m |= bp->Bprotocols;
- read_unlock(&bp_lock);
- return m;
-}
-
-struct Bprotocol *
-get_Bprotocol4mask(u_int m)
-{
- struct Bprotocol *bp;
-
- read_lock(&bp_lock);
- list_for_each_entry(bp, &Bprotocols, list)
- if (bp->Bprotocols & m) {
- read_unlock(&bp_lock);
- return bp;
- }
- read_unlock(&bp_lock);
- return NULL;
-}
-
-int
-mISDN_register_Bprotocol(struct Bprotocol *bp)
-{
- u_long flags;
- struct Bprotocol *old;
-
- if (debug & DEBUG_CORE)
- printk(KERN_DEBUG "%s: %s/%x\n", __func__,
- bp->name, bp->Bprotocols);
- old = get_Bprotocol4mask(bp->Bprotocols);
- if (old) {
- printk(KERN_WARNING
- "register duplicate protocol old %s/%x new %s/%x\n",
- old->name, old->Bprotocols, bp->name, bp->Bprotocols);
- return -EBUSY;
- }
- write_lock_irqsave(&bp_lock, flags);
- list_add_tail(&bp->list, &Bprotocols);
- write_unlock_irqrestore(&bp_lock, flags);
- return 0;
-}
-EXPORT_SYMBOL(mISDN_register_Bprotocol);
-
-void
-mISDN_unregister_Bprotocol(struct Bprotocol *bp)
-{
- u_long flags;
-
- if (debug & DEBUG_CORE)
- printk(KERN_DEBUG "%s: %s/%x\n", __func__, bp->name,
- bp->Bprotocols);
- write_lock_irqsave(&bp_lock, flags);
- list_del(&bp->list);
- write_unlock_irqrestore(&bp_lock, flags);
-}
-EXPORT_SYMBOL(mISDN_unregister_Bprotocol);
-
-static const char *msg_no_channel = "<no channel>";
-static const char *msg_no_stack = "<no stack>";
-static const char *msg_no_stackdev = "<no stack device>";
-
-const char *mISDNDevName4ch(struct mISDNchannel *ch)
-{
- if (!ch)
- return msg_no_channel;
- if (!ch->st)
- return msg_no_stack;
- if (!ch->st->dev)
- return msg_no_stackdev;
- return dev_name(&ch->st->dev->dev);
-};
-EXPORT_SYMBOL(mISDNDevName4ch);
-
-static int
-mISDNInit(void)
-{
- int err;
-
- printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n",
- MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE);
- mISDN_init_clock(&debug);
- mISDN_initstack(&debug);
- err = class_register(&mISDN_class);
- if (err)
- goto error1;
- err = mISDN_inittimer(&debug);
- if (err)
- goto error2;
- err = Isdnl1_Init(&debug);
- if (err)
- goto error3;
- err = Isdnl2_Init(&debug);
- if (err)
- goto error4;
- err = misdn_sock_init(&debug);
- if (err)
- goto error5;
- return 0;
-
-error5:
- Isdnl2_cleanup();
-error4:
- Isdnl1_cleanup();
-error3:
- mISDN_timer_cleanup();
-error2:
- class_unregister(&mISDN_class);
-error1:
- return err;
-}
-
-static void mISDN_cleanup(void)
-{
- misdn_sock_cleanup();
- Isdnl2_cleanup();
- Isdnl1_cleanup();
- mISDN_timer_cleanup();
- class_unregister(&mISDN_class);
-
- printk(KERN_DEBUG "mISDNcore unloaded\n");
-}
-
-module_init(mISDNInit);
-module_exit(mISDN_cleanup);
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#ifndef mISDN_CORE_H
-#define mISDN_CORE_H
-
-extern struct mISDNdevice *get_mdevice(u_int);
-extern int get_mdevice_count(void);
-
-/* stack status flag */
-#define mISDN_STACK_ACTION_MASK 0x0000ffff
-#define mISDN_STACK_COMMAND_MASK 0x000f0000
-#define mISDN_STACK_STATUS_MASK 0xfff00000
-/* action bits 0-15 */
-#define mISDN_STACK_WORK 0
-#define mISDN_STACK_SETUP 1
-#define mISDN_STACK_CLEARING 2
-#define mISDN_STACK_RESTART 3
-#define mISDN_STACK_WAKEUP 4
-#define mISDN_STACK_ABORT 15
-/* command bits 16-19 */
-#define mISDN_STACK_STOPPED 16
-#define mISDN_STACK_INIT 17
-#define mISDN_STACK_THREADSTART 18
-/* status bits 20-31 */
-#define mISDN_STACK_BCHANNEL 20
-#define mISDN_STACK_ACTIVE 29
-#define mISDN_STACK_RUNNING 30
-#define mISDN_STACK_KILLED 31
-
-
-/* manager options */
-#define MGR_OPT_USER 24
-#define MGR_OPT_NETWORK 25
-
-extern int connect_Bstack(struct mISDNdevice *, struct mISDNchannel *,
- u_int, struct sockaddr_mISDN *);
-extern int connect_layer1(struct mISDNdevice *, struct mISDNchannel *,
- u_int, struct sockaddr_mISDN *);
-extern int create_l2entity(struct mISDNdevice *, struct mISDNchannel *,
- u_int, struct sockaddr_mISDN *);
-
-extern int create_stack(struct mISDNdevice *);
-extern int create_teimanager(struct mISDNdevice *);
-extern void delete_teimanager(struct mISDNchannel *);
-extern void delete_channel(struct mISDNchannel *);
-extern void delete_stack(struct mISDNdevice *);
-extern void mISDN_initstack(u_int *);
-extern int misdn_sock_init(u_int *);
-extern void misdn_sock_cleanup(void);
-extern void add_layer2(struct mISDNchannel *, struct mISDNstack *);
-extern void __add_layer2(struct mISDNchannel *, struct mISDNstack *);
-
-extern u_int get_all_Bprotocols(void);
-struct Bprotocol *get_Bprotocol4mask(u_int);
-
-extern int mISDN_inittimer(u_int *);
-extern void mISDN_timer_cleanup(void);
-
-extern int Isdnl1_Init(u_int *);
-extern void Isdnl1_cleanup(void);
-extern int Isdnl2_Init(u_int *);
-extern void Isdnl2_cleanup(void);
-
-extern void mISDN_init_clock(u_int *);
-
-#endif
+++ /dev/null
-/*
- * Audio support data for ISDN4Linux.
- *
- * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define DEBUG_DSP_CTRL 0x0001
-#define DEBUG_DSP_CORE 0x0002
-#define DEBUG_DSP_DTMF 0x0004
-#define DEBUG_DSP_CMX 0x0010
-#define DEBUG_DSP_TONE 0x0020
-#define DEBUG_DSP_BLOWFISH 0x0040
-#define DEBUG_DSP_DELAY 0x0100
-#define DEBUG_DSP_CLOCK 0x0200
-#define DEBUG_DSP_DTMFCOEFF 0x8000 /* heavy output */
-
-/* options may be:
- *
- * bit 0 = use ulaw instead of alaw
- * bit 1 = enable hfc hardware acceleration for all channels
- *
- */
-#define DSP_OPT_ULAW (1 << 0)
-#define DSP_OPT_NOHARDWARE (1 << 1)
-
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-
-#include "dsp_ecdis.h"
-
-extern int dsp_options;
-extern int dsp_debug;
-extern int dsp_poll;
-extern int dsp_tics;
-extern spinlock_t dsp_lock;
-extern struct work_struct dsp_workq;
-extern u32 dsp_poll_diff; /* calculated fix-comma corrected poll value */
-
-/***************
- * audio stuff *
- ***************/
-
-extern s32 dsp_audio_alaw_to_s32[256];
-extern s32 dsp_audio_ulaw_to_s32[256];
-extern s32 *dsp_audio_law_to_s32;
-extern u8 dsp_audio_s16_to_law[65536];
-extern u8 dsp_audio_alaw_to_ulaw[256];
-extern u8 dsp_audio_mix_law[65536];
-extern u8 dsp_audio_seven2law[128];
-extern u8 dsp_audio_law2seven[256];
-extern void dsp_audio_generate_law_tables(void);
-extern void dsp_audio_generate_s2law_table(void);
-extern void dsp_audio_generate_seven(void);
-extern void dsp_audio_generate_mix_table(void);
-extern void dsp_audio_generate_ulaw_samples(void);
-extern void dsp_audio_generate_volume_changes(void);
-extern u8 dsp_silence;
-
-
-/*************
- * cmx stuff *
- *************/
-
-#define MAX_POLL 256 /* maximum number of send-chunks */
-
-#define CMX_BUFF_SIZE 0x8000 /* must be 2**n (0x1000 about 1/2 second) */
-#define CMX_BUFF_HALF 0x4000 /* CMX_BUFF_SIZE / 2 */
-#define CMX_BUFF_MASK 0x7fff /* CMX_BUFF_SIZE - 1 */
-
-/* how many seconds will we check the lowest delay until the jitter buffer
- is reduced by that delay */
-#define MAX_SECONDS_JITTER_CHECK 5
-
-extern struct timer_list dsp_spl_tl;
-
-/* the datatype need to match jiffies datatype */
-extern unsigned long dsp_spl_jiffies;
-
-/* the structure of conferences:
- *
- * each conference has a unique number, given by user space.
- * the conferences are linked in a chain.
- * each conference has members linked in a chain.
- * each dsplayer points to a member, each member points to a dsplayer.
- */
-
-/* all members within a conference (this is linked 1:1 with the dsp) */
-struct dsp;
-struct dsp_conf_member {
- struct list_head list;
- struct dsp *dsp;
-};
-
-/* the list of all conferences */
-struct dsp_conf {
- struct list_head list;
- u32 id;
- /* all cmx stacks with the same ID are
- connected */
- struct list_head mlist;
- int software; /* conf is processed by software */
- int hardware; /* conf is processed by hardware */
- /* note: if both unset, has only one member */
-};
-
-
-/**************
- * DTMF stuff *
- **************/
-
-#define DSP_DTMF_NPOINTS 102
-
-#define ECHOCAN_BUFF_SIZE 0x400 /* must be 2**n */
-#define ECHOCAN_BUFF_MASK 0x3ff /* -1 */
-
-struct dsp_dtmf {
- int enable; /* dtmf is enabled */
- int treshold; /* above this is dtmf (square of) */
- int software; /* dtmf uses software decoding */
- int hardware; /* dtmf uses hardware decoding */
- int size; /* number of bytes in buffer */
- signed short buffer[DSP_DTMF_NPOINTS];
- /* buffers one full dtmf frame */
- u8 lastwhat, lastdigit;
- int count;
- u8 digits[16]; /* dtmf result */
-};
-
-
-/******************
- * pipeline stuff *
- ******************/
-struct dsp_pipeline {
- rwlock_t lock;
- struct list_head list;
- int inuse;
-};
-
-/***************
- * tones stuff *
- ***************/
-
-struct dsp_tone {
- int software; /* tones are generated by software */
- int hardware; /* tones are generated by hardware */
- int tone;
- void *pattern;
- int count;
- int index;
- struct timer_list tl;
-};
-
-/***************
- * echo stuff *
- ***************/
-
-struct dsp_echo {
- int software; /* echo is generated by software */
- int hardware; /* echo is generated by hardware */
-};
-
-/*****************
- * general stuff *
- *****************/
-
-struct dsp {
- struct list_head list;
- struct mISDNchannel ch;
- struct mISDNchannel *up;
- unsigned char name[64];
- int b_active;
- struct dsp_echo echo;
- int rx_disabled; /* what the user wants */
- int rx_is_off; /* what the card is */
- int tx_mix;
- struct dsp_tone tone;
- struct dsp_dtmf dtmf;
- int tx_volume, rx_volume;
-
- /* queue for sending frames */
- struct work_struct workq;
- struct sk_buff_head sendq;
- int hdlc; /* if mode is hdlc */
- int data_pending; /* currently an unconfirmed frame */
-
- /* conference stuff */
- u32 conf_id;
- struct dsp_conf *conf;
- struct dsp_conf_member
- *member;
-
- /* buffer stuff */
- int rx_W; /* current write pos for data without timestamp */
- int rx_R; /* current read pos for transmit clock */
- int rx_init; /* if set, pointers will be adjusted first */
- int tx_W; /* current write pos for transmit data */
- int tx_R; /* current read pos for transmit clock */
- int rx_delay[MAX_SECONDS_JITTER_CHECK];
- int tx_delay[MAX_SECONDS_JITTER_CHECK];
- u8 tx_buff[CMX_BUFF_SIZE];
- u8 rx_buff[CMX_BUFF_SIZE];
- int last_tx; /* if set, we transmitted last poll interval */
- int cmx_delay; /* initial delay of buffers,
- or 0 for dynamic jitter buffer */
- int tx_dejitter; /* if set, dejitter tx buffer */
- int tx_data; /* enables tx-data of CMX to upper layer */
-
- /* hardware stuff */
- struct dsp_features features;
- int features_rx_off; /* set if rx_off is featured */
- int features_fill_empty; /* set if fill_empty is featured */
- int pcm_slot_rx; /* current PCM slot (or -1) */
- int pcm_bank_rx;
- int pcm_slot_tx;
- int pcm_bank_tx;
- int hfc_conf; /* unique id of current conference (or -1) */
-
- /* encryption stuff */
- int bf_enable;
- u32 bf_p[18];
- u32 bf_s[1024];
- int bf_crypt_pos;
- u8 bf_data_in[9];
- u8 bf_crypt_out[9];
- int bf_decrypt_in_pos;
- int bf_decrypt_out_pos;
- u8 bf_crypt_inring[16];
- u8 bf_data_out[9];
- int bf_sync;
-
- struct dsp_pipeline
- pipeline;
-};
-
-/* functions */
-
-extern void dsp_change_volume(struct sk_buff *skb, int volume);
-
-extern struct list_head dsp_ilist;
-extern struct list_head conf_ilist;
-extern void dsp_cmx_debug(struct dsp *dsp);
-extern void dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp);
-extern int dsp_cmx_conf(struct dsp *dsp, u32 conf_id);
-extern void dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb);
-extern void dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb);
-extern void dsp_cmx_send(struct timer_list *arg);
-extern void dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb);
-extern int dsp_cmx_del_conf_member(struct dsp *dsp);
-extern int dsp_cmx_del_conf(struct dsp_conf *conf);
-
-extern void dsp_dtmf_goertzel_init(struct dsp *dsp);
-extern void dsp_dtmf_hardware(struct dsp *dsp);
-extern u8 *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len,
- int fmt);
-
-extern int dsp_tone(struct dsp *dsp, int tone);
-extern void dsp_tone_copy(struct dsp *dsp, u8 *data, int len);
-extern void dsp_tone_timeout(struct timer_list *t);
-
-extern void dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len);
-extern void dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len);
-extern int dsp_bf_init(struct dsp *dsp, const u8 *key, unsigned int keylen);
-extern void dsp_bf_cleanup(struct dsp *dsp);
-
-extern int dsp_pipeline_module_init(void);
-extern void dsp_pipeline_module_exit(void);
-extern int dsp_pipeline_init(struct dsp_pipeline *pipeline);
-extern void dsp_pipeline_destroy(struct dsp_pipeline *pipeline);
-extern int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg);
-extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data,
- int len);
-extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data,
- int len, unsigned int txlen);
+++ /dev/null
-/*
- * Audio support data for mISDN_dsp.
- *
- * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu)
- * Rewritten by Peter
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/mISDNif.h>
-#include <linux/mISDNdsp.h>
-#include <linux/export.h>
-#include <linux/bitrev.h>
-#include "core.h"
-#include "dsp.h"
-
-/* ulaw[unsigned char] -> signed 16-bit */
-s32 dsp_audio_ulaw_to_s32[256];
-/* alaw[unsigned char] -> signed 16-bit */
-s32 dsp_audio_alaw_to_s32[256];
-
-s32 *dsp_audio_law_to_s32;
-EXPORT_SYMBOL(dsp_audio_law_to_s32);
-
-/* signed 16-bit -> law */
-u8 dsp_audio_s16_to_law[65536];
-EXPORT_SYMBOL(dsp_audio_s16_to_law);
-
-/* alaw -> ulaw */
-u8 dsp_audio_alaw_to_ulaw[256];
-/* ulaw -> alaw */
-static u8 dsp_audio_ulaw_to_alaw[256];
-u8 dsp_silence;
-
-
-/*****************************************************
- * generate table for conversion of s16 to alaw/ulaw *
- *****************************************************/
-
-#define AMI_MASK 0x55
-
-static inline unsigned char linear2alaw(short int linear)
-{
- int mask;
- int seg;
- int pcm_val;
- static int seg_end[8] = {
- 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
- };
-
- pcm_val = linear;
- if (pcm_val >= 0) {
- /* Sign (7th) bit = 1 */
- mask = AMI_MASK | 0x80;
- } else {
- /* Sign bit = 0 */
- mask = AMI_MASK;
- pcm_val = -pcm_val;
- }
-
- /* Convert the scaled magnitude to segment number. */
- for (seg = 0; seg < 8; seg++) {
- if (pcm_val <= seg_end[seg])
- break;
- }
- /* Combine the sign, segment, and quantization bits. */
- return ((seg << 4) |
- ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask;
-}
-
-
-static inline short int alaw2linear(unsigned char alaw)
-{
- int i;
- int seg;
-
- alaw ^= AMI_MASK;
- i = ((alaw & 0x0F) << 4) + 8 /* rounding error */;
- seg = (((int) alaw & 0x70) >> 4);
- if (seg)
- i = (i + 0x100) << (seg - 1);
- return (short int) ((alaw & 0x80) ? i : -i);
-}
-
-static inline short int ulaw2linear(unsigned char ulaw)
-{
- short mu, e, f, y;
- static short etab[] = {0, 132, 396, 924, 1980, 4092, 8316, 16764};
-
- mu = 255 - ulaw;
- e = (mu & 0x70) / 16;
- f = mu & 0x0f;
- y = f * (1 << (e + 3));
- y += etab[e];
- if (mu & 0x80)
- y = -y;
- return y;
-}
-
-#define BIAS 0x84 /*!< define the add-in bias for 16 bit samples */
-
-static unsigned char linear2ulaw(short 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 */
-
- /* 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);
-
- return ulawbyte;
-}
-
-void dsp_audio_generate_law_tables(void)
-{
- int i;
- for (i = 0; i < 256; i++)
- dsp_audio_alaw_to_s32[i] = alaw2linear(bitrev8((u8)i));
-
- for (i = 0; i < 256; i++)
- dsp_audio_ulaw_to_s32[i] = ulaw2linear(bitrev8((u8)i));
-
- for (i = 0; i < 256; i++) {
- dsp_audio_alaw_to_ulaw[i] =
- linear2ulaw(dsp_audio_alaw_to_s32[i]);
- dsp_audio_ulaw_to_alaw[i] =
- linear2alaw(dsp_audio_ulaw_to_s32[i]);
- }
-}
-
-void
-dsp_audio_generate_s2law_table(void)
-{
- int i;
-
- if (dsp_options & DSP_OPT_ULAW) {
- /* generating ulaw-table */
- for (i = -32768; i < 32768; i++) {
- dsp_audio_s16_to_law[i & 0xffff] =
- bitrev8(linear2ulaw(i));
- }
- } else {
- /* generating alaw-table */
- for (i = -32768; i < 32768; i++) {
- dsp_audio_s16_to_law[i & 0xffff] =
- bitrev8(linear2alaw(i));
- }
- }
-}
-
-
-/*
- * the seven bit sample is the number of every second alaw-sample ordered by
- * aplitude. 0x00 is negative, 0x7f is positive amplitude.
- */
-u8 dsp_audio_seven2law[128];
-u8 dsp_audio_law2seven[256];
-
-/********************************************************************
- * generate table for conversion law from/to 7-bit alaw-like sample *
- ********************************************************************/
-
-void
-dsp_audio_generate_seven(void)
-{
- int i, j, k;
- u8 spl;
- u8 sorted_alaw[256];
-
- /* generate alaw table, sorted by the linear value */
- for (i = 0; i < 256; i++) {
- j = 0;
- for (k = 0; k < 256; k++) {
- if (dsp_audio_alaw_to_s32[k]
- < dsp_audio_alaw_to_s32[i])
- j++;
- }
- sorted_alaw[j] = i;
- }
-
- /* generate tabels */
- for (i = 0; i < 256; i++) {
- /* spl is the source: the law-sample (converted to alaw) */
- spl = i;
- if (dsp_options & DSP_OPT_ULAW)
- spl = dsp_audio_ulaw_to_alaw[i];
- /* find the 7-bit-sample */
- for (j = 0; j < 256; j++) {
- if (sorted_alaw[j] == spl)
- break;
- }
- /* write 7-bit audio value */
- dsp_audio_law2seven[i] = j >> 1;
- }
- for (i = 0; i < 128; i++) {
- spl = sorted_alaw[i << 1];
- if (dsp_options & DSP_OPT_ULAW)
- spl = dsp_audio_alaw_to_ulaw[spl];
- dsp_audio_seven2law[i] = spl;
- }
-}
-
-
-/* mix 2*law -> law */
-u8 dsp_audio_mix_law[65536];
-
-/******************************************************
- * generate mix table to mix two law samples into one *
- ******************************************************/
-
-void
-dsp_audio_generate_mix_table(void)
-{
- int i, j;
- s32 sample;
-
- i = 0;
- while (i < 256) {
- j = 0;
- while (j < 256) {
- sample = dsp_audio_law_to_s32[i];
- sample += dsp_audio_law_to_s32[j];
- if (sample > 32767)
- sample = 32767;
- if (sample < -32768)
- sample = -32768;
- dsp_audio_mix_law[(i << 8) | j] =
- dsp_audio_s16_to_law[sample & 0xffff];
- j++;
- }
- i++;
- }
-}
-
-
-/*************************************
- * generate different volume changes *
- *************************************/
-
-static u8 dsp_audio_reduce8[256];
-static u8 dsp_audio_reduce7[256];
-static u8 dsp_audio_reduce6[256];
-static u8 dsp_audio_reduce5[256];
-static u8 dsp_audio_reduce4[256];
-static u8 dsp_audio_reduce3[256];
-static u8 dsp_audio_reduce2[256];
-static u8 dsp_audio_reduce1[256];
-static u8 dsp_audio_increase1[256];
-static u8 dsp_audio_increase2[256];
-static u8 dsp_audio_increase3[256];
-static u8 dsp_audio_increase4[256];
-static u8 dsp_audio_increase5[256];
-static u8 dsp_audio_increase6[256];
-static u8 dsp_audio_increase7[256];
-static u8 dsp_audio_increase8[256];
-
-static u8 *dsp_audio_volume_change[16] = {
- dsp_audio_reduce8,
- dsp_audio_reduce7,
- dsp_audio_reduce6,
- dsp_audio_reduce5,
- dsp_audio_reduce4,
- dsp_audio_reduce3,
- dsp_audio_reduce2,
- dsp_audio_reduce1,
- dsp_audio_increase1,
- dsp_audio_increase2,
- dsp_audio_increase3,
- dsp_audio_increase4,
- dsp_audio_increase5,
- dsp_audio_increase6,
- dsp_audio_increase7,
- dsp_audio_increase8,
-};
-
-void
-dsp_audio_generate_volume_changes(void)
-{
- register s32 sample;
- int i;
- int num[] = { 110, 125, 150, 175, 200, 300, 400, 500 };
- int denum[] = { 100, 100, 100, 100, 100, 100, 100, 100 };
-
- i = 0;
- while (i < 256) {
- dsp_audio_reduce8[i] = dsp_audio_s16_to_law[
- (dsp_audio_law_to_s32[i] * denum[7] / num[7]) & 0xffff];
- dsp_audio_reduce7[i] = dsp_audio_s16_to_law[
- (dsp_audio_law_to_s32[i] * denum[6] / num[6]) & 0xffff];
- dsp_audio_reduce6[i] = dsp_audio_s16_to_law[
- (dsp_audio_law_to_s32[i] * denum[5] / num[5]) & 0xffff];
- dsp_audio_reduce5[i] = dsp_audio_s16_to_law[
- (dsp_audio_law_to_s32[i] * denum[4] / num[4]) & 0xffff];
- dsp_audio_reduce4[i] = dsp_audio_s16_to_law[
- (dsp_audio_law_to_s32[i] * denum[3] / num[3]) & 0xffff];
- dsp_audio_reduce3[i] = dsp_audio_s16_to_law[
- (dsp_audio_law_to_s32[i] * denum[2] / num[2]) & 0xffff];
- dsp_audio_reduce2[i] = dsp_audio_s16_to_law[
- (dsp_audio_law_to_s32[i] * denum[1] / num[1]) & 0xffff];
- dsp_audio_reduce1[i] = dsp_audio_s16_to_law[
- (dsp_audio_law_to_s32[i] * denum[0] / num[0]) & 0xffff];
- sample = dsp_audio_law_to_s32[i] * num[0] / denum[0];
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- dsp_audio_increase1[i] = dsp_audio_s16_to_law[sample & 0xffff];
- sample = dsp_audio_law_to_s32[i] * num[1] / denum[1];
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- dsp_audio_increase2[i] = dsp_audio_s16_to_law[sample & 0xffff];
- sample = dsp_audio_law_to_s32[i] * num[2] / denum[2];
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- dsp_audio_increase3[i] = dsp_audio_s16_to_law[sample & 0xffff];
- sample = dsp_audio_law_to_s32[i] * num[3] / denum[3];
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- dsp_audio_increase4[i] = dsp_audio_s16_to_law[sample & 0xffff];
- sample = dsp_audio_law_to_s32[i] * num[4] / denum[4];
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- dsp_audio_increase5[i] = dsp_audio_s16_to_law[sample & 0xffff];
- sample = dsp_audio_law_to_s32[i] * num[5] / denum[5];
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- dsp_audio_increase6[i] = dsp_audio_s16_to_law[sample & 0xffff];
- sample = dsp_audio_law_to_s32[i] * num[6] / denum[6];
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- dsp_audio_increase7[i] = dsp_audio_s16_to_law[sample & 0xffff];
- sample = dsp_audio_law_to_s32[i] * num[7] / denum[7];
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- dsp_audio_increase8[i] = dsp_audio_s16_to_law[sample & 0xffff];
-
- i++;
- }
-}
-
-
-/**************************************
- * change the volume of the given skb *
- **************************************/
-
-/* this is a helper function for changing volume of skb. the range may be
- * -8 to 8, which is a shift to the power of 2. 0 == no volume, 3 == volume*8
- */
-void
-dsp_change_volume(struct sk_buff *skb, int volume)
-{
- u8 *volume_change;
- int i, ii;
- u8 *p;
- int shift;
-
- if (volume == 0)
- return;
-
- /* get correct conversion table */
- if (volume < 0) {
- shift = volume + 8;
- if (shift < 0)
- shift = 0;
- } else {
- shift = volume + 7;
- if (shift > 15)
- shift = 15;
- }
- volume_change = dsp_audio_volume_change[shift];
- i = 0;
- ii = skb->len;
- p = skb->data;
- /* change volume */
- while (i < ii) {
- *p = volume_change[*p];
- p++;
- i++;
- }
-}
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * biquad.h - General telephony bi-quad section routines (currently this just
- * handles canonic/type 2 form)
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2001 Steve Underwood
- *
- * All rights reserved.
- */
-
-struct biquad2_state {
- int32_t gain;
- int32_t a1;
- int32_t a2;
- int32_t b1;
- int32_t b2;
-
- int32_t z1;
- int32_t z2;
-};
-
-static inline void biquad2_init(struct biquad2_state *bq,
- int32_t gain, int32_t a1, int32_t a2, int32_t b1, int32_t b2)
-{
- bq->gain = gain;
- bq->a1 = a1;
- bq->a2 = a2;
- bq->b1 = b1;
- bq->b2 = b2;
-
- bq->z1 = 0;
- bq->z2 = 0;
-}
-
-static inline int16_t biquad2(struct biquad2_state *bq, int16_t sample)
-{
- int32_t y;
- int32_t z0;
-
- z0 = sample * bq->gain + bq->z1 * bq->a1 + bq->z2 * bq->a2;
- y = z0 + bq->z1 * bq->b1 + bq->z2 * bq->b2;
-
- bq->z2 = bq->z1;
- bq->z1 = z0 >> 15;
- y >>= 15;
- return y;
-}
+++ /dev/null
-/*
- * Blowfish encryption/decryption for mISDN_dsp.
- *
- * Copyright Andreas Eversberg (jolly@eversberg.eu)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/mISDNif.h>
-#include <linux/mISDNdsp.h>
-#include "core.h"
-#include "dsp.h"
-
-/*
- * how to encode a sample stream to 64-bit blocks that will be encryped
- *
- * first of all, data is collected until a block of 9 samples are received.
- * of course, a packet may have much more than 9 sample, but is may have
- * not excacly the multiple of 9 samples. if there is a rest, the next
- * received data will complete the block.
- *
- * the block is then converted to 9 uLAW samples without the least sigificant
- * bit. the result is a 7-bit encoded sample.
- *
- * the samples will be reoganised to form 8 bytes of data:
- * (5(6) means: encoded sample no. 5, bit 6)
- *
- * 0(6) 0(5) 0(4) 0(3) 0(2) 0(1) 0(0) 1(6)
- * 1(5) 1(4) 1(3) 1(2) 1(1) 1(0) 2(6) 2(5)
- * 2(4) 2(3) 2(2) 2(1) 2(0) 3(6) 3(5) 3(4)
- * 3(3) 3(2) 3(1) 3(0) 4(6) 4(5) 4(4) 4(3)
- * 4(2) 4(1) 4(0) 5(6) 5(5) 5(4) 5(3) 5(2)
- * 5(1) 5(0) 6(6) 6(5) 6(4) 6(3) 6(2) 6(1)
- * 6(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0)
- * 8(6) 8(5) 8(4) 8(3) 8(2) 8(1) 8(0)
- *
- * the missing bit 0 of the last byte is filled with some
- * random noise, to fill all 8 bytes.
- *
- * the 8 bytes will be encrypted using blowfish.
- *
- * the result will be converted into 9 bytes. the bit 7 is used for
- * checksumme (CS) for sync (0, 1) and for the last bit:
- * (5(6) means: crypted byte 5, bit 6)
- *
- * 1 0(7) 0(6) 0(5) 0(4) 0(3) 0(2) 0(1)
- * 0 0(0) 1(7) 1(6) 1(5) 1(4) 1(3) 1(2)
- * 0 1(1) 1(0) 2(7) 2(6) 2(5) 2(4) 2(3)
- * 0 2(2) 2(1) 2(0) 3(7) 3(6) 3(5) 3(4)
- * 0 3(3) 3(2) 3(1) 3(0) 4(7) 4(6) 4(5)
- * CS 4(4) 4(3) 4(2) 4(1) 4(0) 5(7) 5(6)
- * CS 5(5) 5(4) 5(3) 5(2) 5(1) 5(0) 6(7)
- * CS 6(6) 6(5) 6(4) 6(3) 6(2) 6(1) 6(0)
- * 7(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0)
- *
- * the checksum is used to detect transmission errors and frame drops.
- *
- * synchronisation of received block is done by shifting the upper bit of each
- * byte (bit 7) to a shift register. if the rigister has the first five bits
- * (10000), this is used to find the sync. only if sync has been found, the
- * current block of 9 received bytes are decrypted. before that the check
- * sum is calculated. if it is incorrect the block is dropped.
- * this will avoid loud noise due to corrupt encrypted data.
- *
- * if the last block is corrupt, the current decoded block is repeated
- * until a valid block has been received.
- */
-
-/*
- * some blowfish parts are taken from the
- * crypto-api for faster implementation
- */
-
-static const u32 bf_pbox[16 + 2] = {
- 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
- 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
- 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
- 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
- 0x9216d5d9, 0x8979fb1b,
-};
-
-static const u32 bf_sbox[256 * 4] = {
- 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
- 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
- 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
- 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
- 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
- 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
- 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
- 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
- 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
- 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
- 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
- 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
- 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
- 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
- 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
- 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
- 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
- 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
- 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
- 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
- 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
- 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
- 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
- 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
- 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
- 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
- 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
- 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
- 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
- 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
- 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
- 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
- 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
- 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
- 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
- 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
- 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
- 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
- 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
- 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
- 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
- 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
- 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
- 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
- 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
- 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
- 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
- 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
- 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
- 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
- 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
- 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
- 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
- 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
- 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
- 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
- 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
- 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
- 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
- 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
- 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
- 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
- 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
- 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
- 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
- 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
- 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
- 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
- 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
- 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
- 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
- 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
- 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
- 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
- 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
- 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
- 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
- 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
- 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
- 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
- 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
- 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
- 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
- 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
- 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
- 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
- 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
- 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
- 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
- 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
- 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
- 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
- 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
- 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
- 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
- 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
- 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
- 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
- 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
- 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
- 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
- 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
- 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
- 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
- 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
- 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
- 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
- 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
- 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
- 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
- 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
- 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
- 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
- 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
- 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
- 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
- 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
- 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
- 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
- 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
- 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
- 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
- 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
- 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
- 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
- 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
- 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
- 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
- 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
- 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
- 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
- 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
- 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
- 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
- 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
- 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
- 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
- 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
- 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
- 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
- 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
- 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
- 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
- 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
- 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
- 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
- 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
- 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
- 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
- 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
- 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
- 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
- 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
- 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
- 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
- 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
- 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
- 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
- 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
- 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
- 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
- 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
- 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
- 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
- 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
- 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
- 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
- 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
- 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
- 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
- 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
- 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
- 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
- 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
- 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
- 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
- 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
- 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
- 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
- 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
- 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
- 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
- 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
- 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
- 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
- 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
- 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
- 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
- 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
- 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
- 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
- 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
- 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
- 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
- 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
- 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
- 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
- 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
- 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
- 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
- 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
- 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
- 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
- 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
- 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
- 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
- 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
- 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
- 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
- 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
- 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
- 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
- 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
- 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
- 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
- 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
- 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
- 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
- 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
- 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
- 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
- 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
- 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
- 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
- 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
- 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
- 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
- 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
- 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
- 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
- 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
- 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
- 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
- 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
- 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
- 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
- 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
- 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
- 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
- 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
- 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
- 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
- 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
- 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
- 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
- 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
- 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
- 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
- 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
- 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
- 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
- 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
- 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
- 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
- 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
- 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
-};
-
-/*
- * Round loop unrolling macros, S is a pointer to a S-Box array
- * organized in 4 unsigned longs at a row.
- */
-#define GET32_3(x) (((x) & 0xff))
-#define GET32_2(x) (((x) >> (8)) & (0xff))
-#define GET32_1(x) (((x) >> (16)) & (0xff))
-#define GET32_0(x) (((x) >> (24)) & (0xff))
-
-#define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \
- S[512 + GET32_2(x)]) + S[768 + GET32_3(x)])
-
-#define EROUND(a, b, n) do { b ^= P[n]; a ^= bf_F(b); } while (0)
-#define DROUND(a, b, n) do { a ^= bf_F(b); b ^= P[n]; } while (0)
-
-
-/*
- * encrypt isdn data frame
- * every block with 9 samples is encrypted
- */
-void
-dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len)
-{
- int i = 0, j = dsp->bf_crypt_pos;
- u8 *bf_data_in = dsp->bf_data_in;
- u8 *bf_crypt_out = dsp->bf_crypt_out;
- u32 *P = dsp->bf_p;
- u32 *S = dsp->bf_s;
- u32 yl, yr;
- u32 cs;
- u8 nibble;
-
- while (i < len) {
- /* collect a block of 9 samples */
- if (j < 9) {
- bf_data_in[j] = *data;
- *data++ = bf_crypt_out[j++];
- i++;
- continue;
- }
- j = 0;
- /* transcode 9 samples xlaw to 8 bytes */
- yl = dsp_audio_law2seven[bf_data_in[0]];
- yl = (yl << 7) | dsp_audio_law2seven[bf_data_in[1]];
- yl = (yl << 7) | dsp_audio_law2seven[bf_data_in[2]];
- yl = (yl << 7) | dsp_audio_law2seven[bf_data_in[3]];
- nibble = dsp_audio_law2seven[bf_data_in[4]];
- yr = nibble;
- yl = (yl << 4) | (nibble >> 3);
- yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[5]];
- yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[6]];
- yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[7]];
- yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[8]];
- yr = (yr << 1) | (bf_data_in[0] & 1);
-
- /* fill unused bit with random noise of audio input */
- /* encrypt */
-
- EROUND(yr, yl, 0);
- EROUND(yl, yr, 1);
- EROUND(yr, yl, 2);
- EROUND(yl, yr, 3);
- EROUND(yr, yl, 4);
- EROUND(yl, yr, 5);
- EROUND(yr, yl, 6);
- EROUND(yl, yr, 7);
- EROUND(yr, yl, 8);
- EROUND(yl, yr, 9);
- EROUND(yr, yl, 10);
- EROUND(yl, yr, 11);
- EROUND(yr, yl, 12);
- EROUND(yl, yr, 13);
- EROUND(yr, yl, 14);
- EROUND(yl, yr, 15);
- yl ^= P[16];
- yr ^= P[17];
-
- /* calculate 3-bit checksumme */
- cs = yl ^ (yl >> 3) ^ (yl >> 6) ^ (yl >> 9) ^ (yl >> 12) ^ (yl >> 15)
- ^ (yl >> 18) ^ (yl >> 21) ^ (yl >> 24) ^ (yl >> 27) ^ (yl >> 30)
- ^ (yr << 2) ^ (yr >> 1) ^ (yr >> 4) ^ (yr >> 7) ^ (yr >> 10)
- ^ (yr >> 13) ^ (yr >> 16) ^ (yr >> 19) ^ (yr >> 22) ^ (yr >> 25)
- ^ (yr >> 28) ^ (yr >> 31);
-
- /*
- * transcode 8 crypted bytes to 9 data bytes with sync
- * and checksum information
- */
- bf_crypt_out[0] = (yl >> 25) | 0x80;
- bf_crypt_out[1] = (yl >> 18) & 0x7f;
- bf_crypt_out[2] = (yl >> 11) & 0x7f;
- bf_crypt_out[3] = (yl >> 4) & 0x7f;
- bf_crypt_out[4] = ((yl << 3) & 0x78) | ((yr >> 29) & 0x07);
- bf_crypt_out[5] = ((yr >> 22) & 0x7f) | ((cs << 5) & 0x80);
- bf_crypt_out[6] = ((yr >> 15) & 0x7f) | ((cs << 6) & 0x80);
- bf_crypt_out[7] = ((yr >> 8) & 0x7f) | (cs << 7);
- bf_crypt_out[8] = yr;
- }
-
- /* write current count */
- dsp->bf_crypt_pos = j;
-
-}
-
-
-/*
- * decrypt isdn data frame
- * every block with 9 bytes is decrypted
- */
-void
-dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len)
-{
- int i = 0;
- u8 j = dsp->bf_decrypt_in_pos;
- u8 k = dsp->bf_decrypt_out_pos;
- u8 *bf_crypt_inring = dsp->bf_crypt_inring;
- u8 *bf_data_out = dsp->bf_data_out;
- u16 sync = dsp->bf_sync;
- u32 *P = dsp->bf_p;
- u32 *S = dsp->bf_s;
- u32 yl, yr;
- u8 nibble;
- u8 cs, cs0, cs1, cs2;
-
- while (i < len) {
- /*
- * shift upper bit and rotate data to buffer ring
- * send current decrypted data
- */
- sync = (sync << 1) | ((*data) >> 7);
- bf_crypt_inring[j++ & 15] = *data;
- *data++ = bf_data_out[k++];
- i++;
- if (k == 9)
- k = 0; /* repeat if no sync has been found */
- /* check if not in sync */
- if ((sync & 0x1f0) != 0x100)
- continue;
- j -= 9;
- /* transcode receive data to 64 bit block of encrypted data */
- yl = bf_crypt_inring[j++ & 15];
- yl = (yl << 7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
- yl = (yl << 7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
- yl = (yl << 7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
- nibble = bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
- yr = nibble;
- yl = (yl << 4) | (nibble >> 3);
- cs2 = bf_crypt_inring[j++ & 15];
- yr = (yr << 7) | (cs2 & 0x7f);
- cs1 = bf_crypt_inring[j++ & 15];
- yr = (yr << 7) | (cs1 & 0x7f);
- cs0 = bf_crypt_inring[j++ & 15];
- yr = (yr << 7) | (cs0 & 0x7f);
- yr = (yr << 8) | bf_crypt_inring[j++ & 15];
-
- /* calculate 3-bit checksumme */
- cs = yl ^ (yl >> 3) ^ (yl >> 6) ^ (yl >> 9) ^ (yl >> 12) ^ (yl >> 15)
- ^ (yl >> 18) ^ (yl >> 21) ^ (yl >> 24) ^ (yl >> 27) ^ (yl >> 30)
- ^ (yr << 2) ^ (yr >> 1) ^ (yr >> 4) ^ (yr >> 7) ^ (yr >> 10)
- ^ (yr >> 13) ^ (yr >> 16) ^ (yr >> 19) ^ (yr >> 22) ^ (yr >> 25)
- ^ (yr >> 28) ^ (yr >> 31);
-
- /* check if frame is valid */
- if ((cs & 0x7) != (((cs2 >> 5) & 4) | ((cs1 >> 6) & 2) | (cs0 >> 7))) {
- if (dsp_debug & DEBUG_DSP_BLOWFISH)
- printk(KERN_DEBUG
- "DSP BLOWFISH: received corrupt frame, "
- "checksumme is not correct\n");
- continue;
- }
-
- /* decrypt */
- yr ^= P[17];
- yl ^= P[16];
- DROUND(yl, yr, 15);
- DROUND(yr, yl, 14);
- DROUND(yl, yr, 13);
- DROUND(yr, yl, 12);
- DROUND(yl, yr, 11);
- DROUND(yr, yl, 10);
- DROUND(yl, yr, 9);
- DROUND(yr, yl, 8);
- DROUND(yl, yr, 7);
- DROUND(yr, yl, 6);
- DROUND(yl, yr, 5);
- DROUND(yr, yl, 4);
- DROUND(yl, yr, 3);
- DROUND(yr, yl, 2);
- DROUND(yl, yr, 1);
- DROUND(yr, yl, 0);
-
- /* transcode 8 crypted bytes to 9 sample bytes */
- bf_data_out[0] = dsp_audio_seven2law[(yl >> 25) & 0x7f];
- bf_data_out[1] = dsp_audio_seven2law[(yl >> 18) & 0x7f];
- bf_data_out[2] = dsp_audio_seven2law[(yl >> 11) & 0x7f];
- bf_data_out[3] = dsp_audio_seven2law[(yl >> 4) & 0x7f];
- bf_data_out[4] = dsp_audio_seven2law[((yl << 3) & 0x78) |
- ((yr >> 29) & 0x07)];
-
- bf_data_out[5] = dsp_audio_seven2law[(yr >> 22) & 0x7f];
- bf_data_out[6] = dsp_audio_seven2law[(yr >> 15) & 0x7f];
- bf_data_out[7] = dsp_audio_seven2law[(yr >> 8) & 0x7f];
- bf_data_out[8] = dsp_audio_seven2law[(yr >> 1) & 0x7f];
- k = 0; /* start with new decoded frame */
- }
-
- /* write current count and sync */
- dsp->bf_decrypt_in_pos = j;
- dsp->bf_decrypt_out_pos = k;
- dsp->bf_sync = sync;
-}
-
-
-/* used to encrypt S and P boxes */
-static inline void
-encrypt_block(const u32 *P, const u32 *S, u32 *dst, u32 *src)
-{
- u32 yl = src[0];
- u32 yr = src[1];
-
- EROUND(yr, yl, 0);
- EROUND(yl, yr, 1);
- EROUND(yr, yl, 2);
- EROUND(yl, yr, 3);
- EROUND(yr, yl, 4);
- EROUND(yl, yr, 5);
- EROUND(yr, yl, 6);
- EROUND(yl, yr, 7);
- EROUND(yr, yl, 8);
- EROUND(yl, yr, 9);
- EROUND(yr, yl, 10);
- EROUND(yl, yr, 11);
- EROUND(yr, yl, 12);
- EROUND(yl, yr, 13);
- EROUND(yr, yl, 14);
- EROUND(yl, yr, 15);
-
- yl ^= P[16];
- yr ^= P[17];
-
- dst[0] = yr;
- dst[1] = yl;
-}
-
-/*
- * initialize the dsp for encryption and decryption using the same key
- * Calculates the blowfish S and P boxes for encryption and decryption.
- * The margin of keylen must be 4-56 bytes.
- * returns 0 if ok.
- */
-int
-dsp_bf_init(struct dsp *dsp, const u8 *key, uint keylen)
-{
- short i, j, count;
- u32 data[2], temp;
- u32 *P = (u32 *)dsp->bf_p;
- u32 *S = (u32 *)dsp->bf_s;
-
- if (keylen < 4 || keylen > 56)
- return 1;
-
- /* Set dsp states */
- i = 0;
- while (i < 9) {
- dsp->bf_crypt_out[i] = 0xff;
- dsp->bf_data_out[i] = dsp_silence;
- i++;
- }
- dsp->bf_crypt_pos = 0;
- dsp->bf_decrypt_in_pos = 0;
- dsp->bf_decrypt_out_pos = 0;
- dsp->bf_sync = 0x1ff;
- dsp->bf_enable = 1;
-
- /* Copy the initialization s-boxes */
- for (i = 0, count = 0; i < 256; i++)
- for (j = 0; j < 4; j++, count++)
- S[count] = bf_sbox[count];
-
- /* Set the p-boxes */
- for (i = 0; i < 16 + 2; i++)
- P[i] = bf_pbox[i];
-
- /* Actual subkey generation */
- for (j = 0, i = 0; i < 16 + 2; i++) {
- temp = (((u32)key[j] << 24) |
- ((u32)key[(j + 1) % keylen] << 16) |
- ((u32)key[(j + 2) % keylen] << 8) |
- ((u32)key[(j + 3) % keylen]));
-
- P[i] = P[i] ^ temp;
- j = (j + 4) % keylen;
- }
-
- data[0] = 0x00000000;
- data[1] = 0x00000000;
-
- for (i = 0; i < 16 + 2; i += 2) {
- encrypt_block(P, S, data, data);
-
- P[i] = data[0];
- P[i + 1] = data[1];
- }
-
- for (i = 0; i < 4; i++) {
- for (j = 0, count = i * 256; j < 256; j += 2, count += 2) {
- encrypt_block(P, S, data, data);
-
- S[count] = data[0];
- S[count + 1] = data[1];
- }
- }
-
- return 0;
-}
-
-
-/*
- * turn encryption off
- */
-void
-dsp_bf_cleanup(struct dsp *dsp)
-{
- dsp->bf_enable = 0;
-}
+++ /dev/null
-/*
- * Audio crossconnecting/conferrencing (hardware level).
- *
- * Copyright 2002 by Andreas Eversberg (jolly@eversberg.eu)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/*
- * The process of adding and removing parties to/from a conference:
- *
- * There is a chain of struct dsp_conf which has one or more members in a chain
- * of struct dsp_conf_member.
- *
- * After a party is added, the conference is checked for hardware capability.
- * Also if a party is removed, the conference is checked again.
- *
- * There are 3 different solutions: -1 = software, 0 = hardware-crossconnect
- * 1-n = hardware-conference. The n will give the conference number.
- *
- * Depending on the change after removal or insertion of a party, hardware
- * commands are given.
- *
- * The current solution is stored within the struct dsp_conf entry.
- */
-
-/*
- * HOW THE CMX WORKS:
- *
- * There are 3 types of interaction: One member is alone, in this case only
- * data flow from upper to lower layer is done.
- * Two members will also exchange their data so they are crossconnected.
- * Three or more members will be added in a conference and will hear each
- * other but will not receive their own speech (echo) if not enabled.
- *
- * Features of CMX are:
- * - Crossconnecting or even conference, if more than two members are together.
- * - Force mixing of transmit data with other crossconnect/conference members.
- * - Echo generation to benchmark the delay of audio processing.
- * - Use hardware to minimize cpu load, disable FIFO load and minimize delay.
- * - Dejittering and clock generation.
- *
- * There are 2 buffers:
- *
- *
- * RX-Buffer
- * R W
- * | |
- * ----------------+-------------+-------------------
- *
- * The rx-buffer is a ring buffer used to store the received data for each
- * individual member. This is only the case if data needs to be dejittered
- * or in case of a conference where different clocks require reclocking.
- * The transmit-clock (R) will read the buffer.
- * If the clock overruns the write-pointer, we will have a buffer underrun.
- * If the write pointer always has a certain distance from the transmit-
- * clock, we will have a delay. The delay will dynamically be increased and
- * reduced.
- *
- *
- * TX-Buffer
- * R W
- * | |
- * -----------------+--------+-----------------------
- *
- * The tx-buffer is a ring buffer to queue the transmit data from user space
- * until it will be mixed or sent. There are two pointers, R and W. If the write
- * pointer W would reach or overrun R, the buffer would overrun. In this case
- * (some) data is dropped so that it will not overrun.
- * Additionally a dynamic dejittering can be enabled. this allows data from
- * user space that have jitter and different clock source.
- *
- *
- * Clock:
- *
- * A Clock is not required, if the data source has exactly one clock. In this
- * case the data source is forwarded to the destination.
- *
- * A Clock is required, because the data source
- * - has multiple clocks.
- * - has no usable clock due to jitter or packet loss (VoIP).
- * In this case the system's clock is used. The clock resolution depends on
- * the jiffy resolution.
- *
- * If a member joins a conference:
- *
- * - If a member joins, its rx_buff is set to silence and change read pointer
- * to transmit clock.
- *
- * The procedure of received data from card is explained in cmx_receive.
- * The procedure of received data from user space is explained in cmx_transmit.
- * The procedure of transmit data to card is cmx_send.
- *
- *
- * Interaction with other features:
- *
- * DTMF:
- * DTMF decoding is done before the data is crossconnected.
- *
- * Volume change:
- * Changing rx-volume is done before the data is crossconnected. The tx-volume
- * must be changed whenever data is transmitted to the card by the cmx.
- *
- * Tones:
- * If a tone is enabled, it will be processed whenever data is transmitted to
- * the card. It will replace the tx-data from the user space.
- * If tones are generated by hardware, this conference member is removed for
- * this time.
- *
- * Disable rx-data:
- * If cmx is realized in hardware, rx data will be disabled if requested by
- * the upper layer. If dtmf decoding is done by software and enabled, rx data
- * will not be disabled but blocked to the upper layer.
- *
- * HFC conference engine:
- * If it is possible to realize all features using hardware, hardware will be
- * used if not forbidden by control command. Disabling rx-data provides
- * absolutely traffic free audio processing. (except for the quick 1-frame
- * upload of a tone loop, only once for a new tone)
- *
- */
-
-/* delay.h is required for hw_lock.h */
-
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/mISDNif.h>
-#include <linux/mISDNdsp.h>
-#include "core.h"
-#include "dsp.h"
-/*
- * debugging of multi party conference,
- * by using conference even with two members
- */
-
-/* #define CMX_CONF_DEBUG */
-
-/*#define CMX_DEBUG * massive read/write pointer output */
-/*#define CMX_DELAY_DEBUG * gives rx-buffer delay overview */
-/*#define CMX_TX_DEBUG * massive read/write on tx-buffer with content */
-
-/*
- * debug cmx memory structure
- */
-void
-dsp_cmx_debug(struct dsp *dsp)
-{
- struct dsp_conf *conf;
- struct dsp_conf_member *member;
- struct dsp *odsp;
-
- printk(KERN_DEBUG "-----Current DSP\n");
- list_for_each_entry(odsp, &dsp_ilist, list) {
- printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d",
- odsp->name, odsp->echo.hardware, odsp->echo.software,
- odsp->tx_mix);
- if (odsp->conf)
- printk(" (Conf %d)", odsp->conf->id);
- if (dsp == odsp)
- printk(" *this*");
- printk("\n");
- }
- printk(KERN_DEBUG "-----Current Conf:\n");
- list_for_each_entry(conf, &conf_ilist, list) {
- printk(KERN_DEBUG "* Conf %d (%p)\n", conf->id, conf);
- list_for_each_entry(member, &conf->mlist, list) {
- printk(KERN_DEBUG
- " - member = %s (slot_tx %d, bank_tx %d, "
- "slot_rx %d, bank_rx %d hfc_conf %d "
- "tx_data %d rx_is_off %d)%s\n",
- member->dsp->name, member->dsp->pcm_slot_tx,
- member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx,
- member->dsp->pcm_bank_rx, member->dsp->hfc_conf,
- member->dsp->tx_data, member->dsp->rx_is_off,
- (member->dsp == dsp) ? " *this*" : "");
- }
- }
- printk(KERN_DEBUG "-----end\n");
-}
-
-/*
- * search conference
- */
-static struct dsp_conf *
-dsp_cmx_search_conf(u32 id)
-{
- struct dsp_conf *conf;
-
- if (!id) {
- printk(KERN_WARNING "%s: conference ID is 0.\n", __func__);
- return NULL;
- }
-
- /* search conference */
- list_for_each_entry(conf, &conf_ilist, list)
- if (conf->id == id)
- return conf;
-
- return NULL;
-}
-
-
-/*
- * add member to conference
- */
-static int
-dsp_cmx_add_conf_member(struct dsp *dsp, struct dsp_conf *conf)
-{
- struct dsp_conf_member *member;
-
- if (!conf || !dsp) {
- printk(KERN_WARNING "%s: conf or dsp is 0.\n", __func__);
- return -EINVAL;
- }
- if (dsp->member) {
- printk(KERN_WARNING "%s: dsp is already member in a conf.\n",
- __func__);
- return -EINVAL;
- }
-
- if (dsp->conf) {
- printk(KERN_WARNING "%s: dsp is already in a conf.\n",
- __func__);
- return -EINVAL;
- }
-
- member = kzalloc_obj(struct dsp_conf_member, GFP_ATOMIC);
- if (!member) {
- printk(KERN_ERR "kzalloc struct dsp_conf_member failed\n");
- return -ENOMEM;
- }
- member->dsp = dsp;
- /* clear rx buffer */
- memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));
- dsp->rx_init = 1; /* rx_W and rx_R will be adjusted on first frame */
- dsp->rx_W = 0;
- dsp->rx_R = 0;
-
- list_add_tail(&member->list, &conf->mlist);
-
- dsp->conf = conf;
- dsp->member = member;
-
- return 0;
-}
-
-
-/*
- * del member from conference
- */
-int
-dsp_cmx_del_conf_member(struct dsp *dsp)
-{
- struct dsp_conf_member *member;
-
- if (!dsp) {
- printk(KERN_WARNING "%s: dsp is 0.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!dsp->conf) {
- printk(KERN_WARNING "%s: dsp is not in a conf.\n",
- __func__);
- return -EINVAL;
- }
-
- if (list_empty(&dsp->conf->mlist)) {
- printk(KERN_WARNING "%s: dsp has linked an empty conf.\n",
- __func__);
- return -EINVAL;
- }
-
- /* find us in conf */
- list_for_each_entry(member, &dsp->conf->mlist, list) {
- if (member->dsp == dsp) {
- list_del(&member->list);
- dsp->conf = NULL;
- dsp->member = NULL;
- kfree(member);
- return 0;
- }
- }
- printk(KERN_WARNING
- "%s: dsp is not present in its own conf_member list.\n",
- __func__);
-
- return -EINVAL;
-}
-
-
-/*
- * new conference
- */
-static struct dsp_conf
-*dsp_cmx_new_conf(u32 id)
-{
- struct dsp_conf *conf;
-
- if (!id) {
- printk(KERN_WARNING "%s: id is 0.\n",
- __func__);
- return NULL;
- }
-
- conf = kzalloc_obj(struct dsp_conf, GFP_ATOMIC);
- if (!conf) {
- printk(KERN_ERR "kzalloc struct dsp_conf failed\n");
- return NULL;
- }
- INIT_LIST_HEAD(&conf->mlist);
- conf->id = id;
-
- list_add_tail(&conf->list, &conf_ilist);
-
- return conf;
-}
-
-
-/*
- * del conference
- */
-int
-dsp_cmx_del_conf(struct dsp_conf *conf)
-{
- if (!conf) {
- printk(KERN_WARNING "%s: conf is null.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!list_empty(&conf->mlist)) {
- printk(KERN_WARNING "%s: conf not empty.\n",
- __func__);
- return -EINVAL;
- }
- list_del(&conf->list);
- kfree(conf);
-
- return 0;
-}
-
-
-/*
- * send HW message to hfc card
- */
-static void
-dsp_cmx_hw_message(struct dsp *dsp, u32 message, u32 param1, u32 param2,
- u32 param3, u32 param4)
-{
- struct mISDN_ctrl_req cq;
-
- memset(&cq, 0, sizeof(cq));
- cq.op = message;
- cq.p1 = param1 | (param2 << 8);
- cq.p2 = param3 | (param4 << 8);
- if (dsp->ch.peer)
- dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq);
-}
-
-
-/*
- * do hardware update and set the software/hardware flag
- *
- * either a conference or a dsp instance can be given
- * if only dsp instance is given, the instance is not associated with a conf
- * and therefore removed. if a conference is given, the dsp is expected to
- * be member of that conference.
- */
-void
-dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp)
-{
- struct dsp_conf_member *member, *nextm;
- struct dsp *finddsp;
- int memb = 0, i, ii, i1, i2;
- int freeunits[8];
- u_char freeslots[256];
- int same_hfc = -1, same_pcm = -1, current_conf = -1,
- all_conf = 1, tx_data = 0;
-
- /* dsp gets updated (no conf) */
- if (!conf) {
- if (!dsp)
- return;
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG "%s checking dsp %s\n",
- __func__, dsp->name);
- one_member:
- /* remove HFC conference if enabled */
- if (dsp->hfc_conf >= 0) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s removing %s from HFC conf %d "
- "because dsp is split\n", __func__,
- dsp->name, dsp->hfc_conf);
- dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_CONF_SPLIT,
- 0, 0, 0, 0);
- dsp->hfc_conf = -1;
- }
- /* process hw echo */
- if (dsp->features.pcm_banks < 1)
- return;
- if (!dsp->echo.software && !dsp->echo.hardware) {
- /* NO ECHO: remove PCM slot if assigned */
- if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG "%s removing %s from"
- " PCM slot %d (TX) %d (RX) because"
- " dsp is split (no echo)\n",
- __func__, dsp->name,
- dsp->pcm_slot_tx, dsp->pcm_slot_rx);
- dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_DISC,
- 0, 0, 0, 0);
- dsp->pcm_slot_tx = -1;
- dsp->pcm_bank_tx = -1;
- dsp->pcm_slot_rx = -1;
- dsp->pcm_bank_rx = -1;
- }
- return;
- }
- /* echo is enabled, find out if we use soft or hardware */
- dsp->echo.software = dsp->tx_data;
- dsp->echo.hardware = 0;
- /* ECHO: already echo */
- if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 &&
- dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) {
- dsp->echo.hardware = 1;
- return;
- }
- /* ECHO: if slot already assigned */
- if (dsp->pcm_slot_tx >= 0) {
- dsp->pcm_slot_rx = dsp->pcm_slot_tx;
- dsp->pcm_bank_tx = 2; /* 2 means loop */
- dsp->pcm_bank_rx = 2;
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s refresh %s for echo using slot %d\n",
- __func__, dsp->name,
- dsp->pcm_slot_tx);
- dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN,
- dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);
- dsp->echo.hardware = 1;
- return;
- }
- /* ECHO: find slot */
- dsp->pcm_slot_tx = -1;
- dsp->pcm_slot_rx = -1;
- memset(freeslots, 1, sizeof(freeslots));
- list_for_each_entry(finddsp, &dsp_ilist, list) {
- if (finddsp->features.pcm_id == dsp->features.pcm_id) {
- if (finddsp->pcm_slot_rx >= 0 &&
- finddsp->pcm_slot_rx < sizeof(freeslots))
- freeslots[finddsp->pcm_slot_rx] = 0;
- if (finddsp->pcm_slot_tx >= 0 &&
- finddsp->pcm_slot_tx < sizeof(freeslots))
- freeslots[finddsp->pcm_slot_tx] = 0;
- }
- }
- i = 0;
- ii = dsp->features.pcm_slots;
- while (i < ii) {
- if (freeslots[i])
- break;
- i++;
- }
- if (i == ii) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s no slot available for echo\n",
- __func__);
- /* no more slots available */
- dsp->echo.software = 1;
- return;
- }
- /* assign free slot */
- dsp->pcm_slot_tx = i;
- dsp->pcm_slot_rx = i;
- dsp->pcm_bank_tx = 2; /* loop */
- dsp->pcm_bank_rx = 2;
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s assign echo for %s using slot %d\n",
- __func__, dsp->name, dsp->pcm_slot_tx);
- dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN,
- dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);
- dsp->echo.hardware = 1;
- return;
- }
-
- /* conf gets updated (all members) */
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG "%s checking conference %d\n",
- __func__, conf->id);
-
- if (list_empty(&conf->mlist)) {
- printk(KERN_ERR "%s: conference without members\n",
- __func__);
- return;
- }
- member = list_entry(conf->mlist.next, struct dsp_conf_member, list);
- same_hfc = member->dsp->features.hfc_id;
- same_pcm = member->dsp->features.pcm_id;
- /* check all members in our conference */
- list_for_each_entry(member, &conf->mlist, list) {
- /* check if member uses mixing */
- if (member->dsp->tx_mix) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s dsp %s cannot form a conf, because "
- "tx_mix is turned on\n", __func__,
- member->dsp->name);
- conf_software:
- list_for_each_entry(member, &conf->mlist, list) {
- dsp = member->dsp;
- /* remove HFC conference if enabled */
- if (dsp->hfc_conf >= 0) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s removing %s from HFC "
- "conf %d because not "
- "possible with hardware\n",
- __func__,
- dsp->name,
- dsp->hfc_conf);
- dsp_cmx_hw_message(dsp,
- MISDN_CTRL_HFC_CONF_SPLIT,
- 0, 0, 0, 0);
- dsp->hfc_conf = -1;
- }
- /* remove PCM slot if assigned */
- if (dsp->pcm_slot_tx >= 0 ||
- dsp->pcm_slot_rx >= 0) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG "%s removing "
- "%s from PCM slot %d (TX)"
- " slot %d (RX) because not"
- " possible with hardware\n",
- __func__,
- dsp->name,
- dsp->pcm_slot_tx,
- dsp->pcm_slot_rx);
- dsp_cmx_hw_message(dsp,
- MISDN_CTRL_HFC_PCM_DISC,
- 0, 0, 0, 0);
- dsp->pcm_slot_tx = -1;
- dsp->pcm_bank_tx = -1;
- dsp->pcm_slot_rx = -1;
- dsp->pcm_bank_rx = -1;
- }
- }
- conf->hardware = 0;
- conf->software = 1;
- return;
- }
- /* check if member has echo turned on */
- if (member->dsp->echo.hardware || member->dsp->echo.software) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s dsp %s cannot form a conf, because "
- "echo is turned on\n", __func__,
- member->dsp->name);
- goto conf_software;
- }
- /* check if member has tx_mix turned on */
- if (member->dsp->tx_mix) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s dsp %s cannot form a conf, because "
- "tx_mix is turned on\n",
- __func__, member->dsp->name);
- goto conf_software;
- }
- /* check if member changes volume at an not suppoted level */
- if (member->dsp->tx_volume) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s dsp %s cannot form a conf, because "
- "tx_volume is changed\n",
- __func__, member->dsp->name);
- goto conf_software;
- }
- if (member->dsp->rx_volume) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s dsp %s cannot form a conf, because "
- "rx_volume is changed\n",
- __func__, member->dsp->name);
- goto conf_software;
- }
- /* check if tx-data turned on */
- if (member->dsp->tx_data) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s dsp %s tx_data is turned on\n",
- __func__, member->dsp->name);
- tx_data = 1;
- }
- /* check if pipeline exists */
- if (member->dsp->pipeline.inuse) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s dsp %s cannot form a conf, because "
- "pipeline exists\n", __func__,
- member->dsp->name);
- goto conf_software;
- }
- /* check if encryption is enabled */
- if (member->dsp->bf_enable) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG "%s dsp %s cannot form a "
- "conf, because encryption is enabled\n",
- __func__, member->dsp->name);
- goto conf_software;
- }
- /* check if member is on a card with PCM support */
- if (member->dsp->features.pcm_id < 0) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s dsp %s cannot form a conf, because "
- "dsp has no PCM bus\n",
- __func__, member->dsp->name);
- goto conf_software;
- }
- /* check if relations are on the same PCM bus */
- if (member->dsp->features.pcm_id != same_pcm) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s dsp %s cannot form a conf, because "
- "dsp is on a different PCM bus than the "
- "first dsp\n",
- __func__, member->dsp->name);
- goto conf_software;
- }
- /* determine if members are on the same hfc chip */
- if (same_hfc != member->dsp->features.hfc_id)
- same_hfc = -1;
- /* if there are members already in a conference */
- if (current_conf < 0 && member->dsp->hfc_conf >= 0)
- current_conf = member->dsp->hfc_conf;
- /* if any member is not in a conference */
- if (member->dsp->hfc_conf < 0)
- all_conf = 0;
-
- memb++;
- }
-
- /* if no member, this is an error */
- if (memb < 1)
- return;
-
- /* one member */
- if (memb == 1) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s conf %d cannot form a HW conference, "
- "because dsp is alone\n", __func__, conf->id);
- conf->hardware = 0;
- conf->software = 0;
- member = list_entry(conf->mlist.next, struct dsp_conf_member,
- list);
- dsp = member->dsp;
- goto one_member;
- }
-
- /*
- * ok, now we are sure that all members are on the same pcm.
- * now we will see if we have only two members, so we can do
- * crossconnections, which don't have any limitations.
- */
-
- /* if we have only two members */
- if (memb == 2) {
- member = list_entry(conf->mlist.next, struct dsp_conf_member,
- list);
- nextm = list_entry(member->list.next, struct dsp_conf_member,
- list);
- /* remove HFC conference if enabled */
- if (member->dsp->hfc_conf >= 0) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s removing %s from HFC conf %d because "
- "two parties require only a PCM slot\n",
- __func__, member->dsp->name,
- member->dsp->hfc_conf);
- dsp_cmx_hw_message(member->dsp,
- MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0);
- member->dsp->hfc_conf = -1;
- }
- if (nextm->dsp->hfc_conf >= 0) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s removing %s from HFC conf %d because "
- "two parties require only a PCM slot\n",
- __func__, nextm->dsp->name,
- nextm->dsp->hfc_conf);
- dsp_cmx_hw_message(nextm->dsp,
- MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0);
- nextm->dsp->hfc_conf = -1;
- }
- /* if members have two banks (and not on the same chip) */
- if (member->dsp->features.pcm_banks > 1 &&
- nextm->dsp->features.pcm_banks > 1 &&
- member->dsp->features.hfc_id !=
- nextm->dsp->features.hfc_id) {
- /* if both members have same slots with crossed banks */
- if (member->dsp->pcm_slot_tx >= 0 &&
- member->dsp->pcm_slot_rx >= 0 &&
- nextm->dsp->pcm_slot_tx >= 0 &&
- nextm->dsp->pcm_slot_rx >= 0 &&
- nextm->dsp->pcm_slot_tx ==
- member->dsp->pcm_slot_rx &&
- nextm->dsp->pcm_slot_rx ==
- member->dsp->pcm_slot_tx &&
- nextm->dsp->pcm_slot_tx ==
- member->dsp->pcm_slot_tx &&
- member->dsp->pcm_bank_tx !=
- member->dsp->pcm_bank_rx &&
- nextm->dsp->pcm_bank_tx !=
- nextm->dsp->pcm_bank_rx) {
- /* all members have same slot */
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s dsp %s & %s stay joined on "
- "PCM slot %d bank %d (TX) bank %d "
- "(RX) (on different chips)\n",
- __func__,
- member->dsp->name,
- nextm->dsp->name,
- member->dsp->pcm_slot_tx,
- member->dsp->pcm_bank_tx,
- member->dsp->pcm_bank_rx);
- conf->hardware = 1;
- conf->software = tx_data;
- return;
- }
- /* find a new slot */
- memset(freeslots, 1, sizeof(freeslots));
- list_for_each_entry(dsp, &dsp_ilist, list) {
- if (dsp != member->dsp &&
- dsp != nextm->dsp &&
- member->dsp->features.pcm_id ==
- dsp->features.pcm_id) {
- if (dsp->pcm_slot_rx >= 0 &&
- dsp->pcm_slot_rx <
- sizeof(freeslots))
- freeslots[dsp->pcm_slot_rx] = 0;
- if (dsp->pcm_slot_tx >= 0 &&
- dsp->pcm_slot_tx <
- sizeof(freeslots))
- freeslots[dsp->pcm_slot_tx] = 0;
- }
- }
- i = 0;
- ii = member->dsp->features.pcm_slots;
- while (i < ii) {
- if (freeslots[i])
- break;
- i++;
- }
- if (i == ii) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s no slot available for "
- "%s & %s\n", __func__,
- member->dsp->name,
- nextm->dsp->name);
- /* no more slots available */
- goto conf_software;
- }
- /* assign free slot */
- member->dsp->pcm_slot_tx = i;
- member->dsp->pcm_slot_rx = i;
- nextm->dsp->pcm_slot_tx = i;
- nextm->dsp->pcm_slot_rx = i;
- member->dsp->pcm_bank_rx = 0;
- member->dsp->pcm_bank_tx = 1;
- nextm->dsp->pcm_bank_rx = 1;
- nextm->dsp->pcm_bank_tx = 0;
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s adding %s & %s to new PCM slot %d "
- "(TX and RX on different chips) because "
- "both members have not same slots\n",
- __func__,
- member->dsp->name,
- nextm->dsp->name,
- member->dsp->pcm_slot_tx);
- dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN,
- member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx,
- member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx);
- dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN,
- nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx,
- nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);
- conf->hardware = 1;
- conf->software = tx_data;
- return;
- /* if members have one bank (or on the same chip) */
- } else {
- /* if both members have different crossed slots */
- if (member->dsp->pcm_slot_tx >= 0 &&
- member->dsp->pcm_slot_rx >= 0 &&
- nextm->dsp->pcm_slot_tx >= 0 &&
- nextm->dsp->pcm_slot_rx >= 0 &&
- nextm->dsp->pcm_slot_tx ==
- member->dsp->pcm_slot_rx &&
- nextm->dsp->pcm_slot_rx ==
- member->dsp->pcm_slot_tx &&
- member->dsp->pcm_slot_tx !=
- member->dsp->pcm_slot_rx &&
- member->dsp->pcm_bank_tx == 0 &&
- member->dsp->pcm_bank_rx == 0 &&
- nextm->dsp->pcm_bank_tx == 0 &&
- nextm->dsp->pcm_bank_rx == 0) {
- /* all members have same slot */
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s dsp %s & %s stay joined on PCM "
- "slot %d (TX) %d (RX) on same chip "
- "or one bank PCM)\n", __func__,
- member->dsp->name,
- nextm->dsp->name,
- member->dsp->pcm_slot_tx,
- member->dsp->pcm_slot_rx);
- conf->hardware = 1;
- conf->software = tx_data;
- return;
- }
- /* find two new slot */
- memset(freeslots, 1, sizeof(freeslots));
- list_for_each_entry(dsp, &dsp_ilist, list) {
- if (dsp != member->dsp &&
- dsp != nextm->dsp &&
- member->dsp->features.pcm_id ==
- dsp->features.pcm_id) {
- if (dsp->pcm_slot_rx >= 0 &&
- dsp->pcm_slot_rx <
- sizeof(freeslots))
- freeslots[dsp->pcm_slot_rx] = 0;
- if (dsp->pcm_slot_tx >= 0 &&
- dsp->pcm_slot_tx <
- sizeof(freeslots))
- freeslots[dsp->pcm_slot_tx] = 0;
- }
- }
- i1 = 0;
- ii = member->dsp->features.pcm_slots;
- while (i1 < ii) {
- if (freeslots[i1])
- break;
- i1++;
- }
- if (i1 == ii) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s no slot available "
- "for %s & %s\n", __func__,
- member->dsp->name,
- nextm->dsp->name);
- /* no more slots available */
- goto conf_software;
- }
- i2 = i1 + 1;
- while (i2 < ii) {
- if (freeslots[i2])
- break;
- i2++;
- }
- if (i2 == ii) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s no slot available "
- "for %s & %s\n",
- __func__,
- member->dsp->name,
- nextm->dsp->name);
- /* no more slots available */
- goto conf_software;
- }
- /* assign free slots */
- member->dsp->pcm_slot_tx = i1;
- member->dsp->pcm_slot_rx = i2;
- nextm->dsp->pcm_slot_tx = i2;
- nextm->dsp->pcm_slot_rx = i1;
- member->dsp->pcm_bank_rx = 0;
- member->dsp->pcm_bank_tx = 0;
- nextm->dsp->pcm_bank_rx = 0;
- nextm->dsp->pcm_bank_tx = 0;
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s adding %s & %s to new PCM slot %d "
- "(TX) %d (RX) on same chip or one bank "
- "PCM, because both members have not "
- "crossed slots\n", __func__,
- member->dsp->name,
- nextm->dsp->name,
- member->dsp->pcm_slot_tx,
- member->dsp->pcm_slot_rx);
- dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN,
- member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx,
- member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx);
- dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN,
- nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx,
- nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);
- conf->hardware = 1;
- conf->software = tx_data;
- return;
- }
- }
-
- /*
- * if we have more than two, we may check if we have a conference
- * unit available on the chip. also all members must be on the same
- */
-
- /* if not the same HFC chip */
- if (same_hfc < 0) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s conference %d cannot be formed, because "
- "members are on different chips or not "
- "on HFC chip\n",
- __func__, conf->id);
- goto conf_software;
- }
-
- /* for more than two members.. */
-
- /* if all members already have the same conference */
- if (all_conf) {
- conf->hardware = 1;
- conf->software = tx_data;
- return;
- }
-
- /*
- * if there is an existing conference, but not all members have joined
- */
- if (current_conf >= 0) {
- join_members:
- list_for_each_entry(member, &conf->mlist, list) {
- /* if no conference engine on our chip, change to
- * software */
- if (!member->dsp->features.hfc_conf)
- goto conf_software;
- /* in case of hdlc, change to software */
- if (member->dsp->hdlc)
- goto conf_software;
- /* join to current conference */
- if (member->dsp->hfc_conf == current_conf)
- continue;
- /* get a free timeslot first */
- memset(freeslots, 1, sizeof(freeslots));
- list_for_each_entry(dsp, &dsp_ilist, list) {
- /*
- * not checking current member, because
- * slot will be overwritten.
- */
- if (
- dsp != member->dsp &&
- /* dsp must be on the same PCM */
- member->dsp->features.pcm_id ==
- dsp->features.pcm_id) {
- /* dsp must be on a slot */
- if (dsp->pcm_slot_tx >= 0 &&
- dsp->pcm_slot_tx <
- sizeof(freeslots))
- freeslots[dsp->pcm_slot_tx] = 0;
- if (dsp->pcm_slot_rx >= 0 &&
- dsp->pcm_slot_rx <
- sizeof(freeslots))
- freeslots[dsp->pcm_slot_rx] = 0;
- }
- }
- i = 0;
- ii = member->dsp->features.pcm_slots;
- while (i < ii) {
- if (freeslots[i])
- break;
- i++;
- }
- if (i == ii) {
- /* no more slots available */
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s conference %d cannot be formed,"
- " because no slot free\n",
- __func__, conf->id);
- goto conf_software;
- }
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s changing dsp %s to HW conference "
- "%d slot %d\n", __func__,
- member->dsp->name, current_conf, i);
- /* assign free slot & set PCM & join conf */
- member->dsp->pcm_slot_tx = i;
- member->dsp->pcm_slot_rx = i;
- member->dsp->pcm_bank_tx = 2; /* loop */
- member->dsp->pcm_bank_rx = 2;
- member->dsp->hfc_conf = current_conf;
- dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN,
- i, 2, i, 2);
- dsp_cmx_hw_message(member->dsp,
- MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0);
- }
- conf->hardware = 1;
- conf->software = tx_data;
- return;
- }
-
- /*
- * no member is in a conference yet, so we find a free one
- */
- memset(freeunits, 1, sizeof(freeunits));
- list_for_each_entry(dsp, &dsp_ilist, list) {
- /* dsp must be on the same chip */
- if (dsp->features.hfc_id == same_hfc &&
- /* dsp must have joined a HW conference */
- dsp->hfc_conf >= 0 &&
- /* slot must be within range */
- dsp->hfc_conf < 8)
- freeunits[dsp->hfc_conf] = 0;
- }
- i = 0;
- ii = 8;
- while (i < ii) {
- if (freeunits[i])
- break;
- i++;
- }
- if (i == ii) {
- /* no more conferences available */
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "%s conference %d cannot be formed, because "
- "no conference number free\n",
- __func__, conf->id);
- goto conf_software;
- }
- /* join all members */
- current_conf = i;
- goto join_members;
-}
-
-
-/*
- * conf_id != 0: join or change conference
- * conf_id == 0: split from conference if not already
- */
-int
-dsp_cmx_conf(struct dsp *dsp, u32 conf_id)
-{
- int err;
- struct dsp_conf *conf;
- struct dsp_conf_member *member;
-
- /* if conference doesn't change */
- if (dsp->conf_id == conf_id)
- return 0;
-
- /* first remove us from current conf */
- if (dsp->conf_id) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG "removing us from conference %d\n",
- dsp->conf->id);
- /* remove us from conf */
- conf = dsp->conf;
- err = dsp_cmx_del_conf_member(dsp);
- if (err)
- return err;
- dsp->conf_id = 0;
-
- /* update hardware */
- dsp_cmx_hardware(NULL, dsp);
-
- /* conf now empty? */
- if (list_empty(&conf->mlist)) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "conference is empty, so we remove it.\n");
- err = dsp_cmx_del_conf(conf);
- if (err)
- return err;
- } else {
- /* update members left on conf */
- dsp_cmx_hardware(conf, NULL);
- }
- }
-
- /* if split */
- if (!conf_id)
- return 0;
-
- /* now add us to conf */
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG "searching conference %d\n",
- conf_id);
- conf = dsp_cmx_search_conf(conf_id);
- if (!conf) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "conference doesn't exist yet, creating.\n");
- /* the conference doesn't exist, so we create */
- conf = dsp_cmx_new_conf(conf_id);
- if (!conf)
- return -EINVAL;
- } else if (!list_empty(&conf->mlist)) {
- member = list_entry(conf->mlist.next, struct dsp_conf_member,
- list);
- if (dsp->hdlc && !member->dsp->hdlc) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "cannot join transparent conference.\n");
- return -EINVAL;
- }
- if (!dsp->hdlc && member->dsp->hdlc) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "cannot join hdlc conference.\n");
- return -EINVAL;
- }
- }
- /* add conference member */
- err = dsp_cmx_add_conf_member(dsp, conf);
- if (err)
- return err;
- dsp->conf_id = conf_id;
-
- /* if we are alone, we do nothing! */
- if (list_empty(&conf->mlist)) {
- if (dsp_debug & DEBUG_DSP_CMX)
- printk(KERN_DEBUG
- "we are alone in this conference, so exit.\n");
- /* update hardware */
- dsp_cmx_hardware(NULL, dsp);
- return 0;
- }
-
- /* update members on conf */
- dsp_cmx_hardware(conf, NULL);
-
- return 0;
-}
-
-#ifdef CMX_DELAY_DEBUG
-int delaycount;
-static void
-showdelay(struct dsp *dsp, int samples, int delay)
-{
- char bar[] = "--------------------------------------------------|";
- int sdelay;
-
- delaycount += samples;
- if (delaycount < 8000)
- return;
- delaycount = 0;
-
- sdelay = delay * 50 / (dsp_poll << 2);
-
- printk(KERN_DEBUG "DELAY (%s) %3d >%s\n", dsp->name, delay,
- sdelay > 50 ? "..." : bar + 50 - sdelay);
-}
-#endif
-
-/*
- * audio data is received from card
- */
-void
-dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb)
-{
- u8 *d, *p;
- int len = skb->len;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- int w, i, ii;
-
- /* check if we have sompen */
- if (len < 1)
- return;
-
- /* half of the buffer should be larger than maximum packet size */
- if (len >= CMX_BUFF_HALF) {
- printk(KERN_ERR
- "%s line %d: packet from card is too large (%d bytes). "
- "please make card send smaller packets OR increase "
- "CMX_BUFF_SIZE\n", __FILE__, __LINE__, len);
- return;
- }
-
- /*
- * initialize pointers if not already -
- * also add delay if requested by PH_SIGNAL
- */
- if (dsp->rx_init) {
- dsp->rx_init = 0;
- if (dsp->features.unordered) {
- dsp->rx_R = (hh->id & CMX_BUFF_MASK);
- if (dsp->cmx_delay)
- dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)
- & CMX_BUFF_MASK;
- else
- dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1))
- & CMX_BUFF_MASK;
- } else {
- dsp->rx_R = 0;
- if (dsp->cmx_delay)
- dsp->rx_W = dsp->cmx_delay;
- else
- dsp->rx_W = dsp_poll >> 1;
- }
- }
- /* if frame contains time code, write directly */
- if (dsp->features.unordered) {
- dsp->rx_W = (hh->id & CMX_BUFF_MASK);
- /* printk(KERN_DEBUG "%s %08x\n", dsp->name, hh->id); */
- }
- /*
- * if we underrun (or maybe overrun),
- * we set our new read pointer, and write silence to buffer
- */
- if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) {
- if (dsp_debug & DEBUG_DSP_CLOCK)
- printk(KERN_DEBUG
- "cmx_receive(dsp=%lx): UNDERRUN (or overrun the "
- "maximum delay), adjusting read pointer! "
- "(inst %s)\n", (u_long)dsp, dsp->name);
- /* flush rx buffer and set delay to dsp_poll / 2 */
- if (dsp->features.unordered) {
- dsp->rx_R = (hh->id & CMX_BUFF_MASK);
- if (dsp->cmx_delay)
- dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)
- & CMX_BUFF_MASK;
- else
- dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1))
- & CMX_BUFF_MASK;
- } else {
- dsp->rx_R = 0;
- if (dsp->cmx_delay)
- dsp->rx_W = dsp->cmx_delay;
- else
- dsp->rx_W = dsp_poll >> 1;
- }
- memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));
- }
- /* if we have reached double delay, jump back to middle */
- if (dsp->cmx_delay)
- if (((dsp->rx_W - dsp->rx_R) & CMX_BUFF_MASK) >=
- (dsp->cmx_delay << 1)) {
- if (dsp_debug & DEBUG_DSP_CLOCK)
- printk(KERN_DEBUG
- "cmx_receive(dsp=%lx): OVERRUN (because "
- "twice the delay is reached), adjusting "
- "read pointer! (inst %s)\n",
- (u_long)dsp, dsp->name);
- /* flush buffer */
- if (dsp->features.unordered) {
- dsp->rx_R = (hh->id & CMX_BUFF_MASK);
- dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)
- & CMX_BUFF_MASK;
- } else {
- dsp->rx_R = 0;
- dsp->rx_W = dsp->cmx_delay;
- }
- memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));
- }
-
- /* show where to write */
-#ifdef CMX_DEBUG
- printk(KERN_DEBUG
- "cmx_receive(dsp=%lx): rx_R(dsp)=%05x rx_W(dsp)=%05x len=%d %s\n",
- (u_long)dsp, dsp->rx_R, dsp->rx_W, len, dsp->name);
-#endif
-
- /* write data into rx_buffer */
- p = skb->data;
- d = dsp->rx_buff;
- w = dsp->rx_W;
- i = 0;
- ii = len;
- while (i < ii) {
- d[w++ & CMX_BUFF_MASK] = *p++;
- i++;
- }
-
- /* increase write-pointer */
- dsp->rx_W = ((dsp->rx_W + len) & CMX_BUFF_MASK);
-#ifdef CMX_DELAY_DEBUG
- showdelay(dsp, len, (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK);
-#endif
-}
-
-
-/*
- * send (mixed) audio data to card and control jitter
- */
-static void
-dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
-{
- struct dsp_conf *conf = dsp->conf;
- struct dsp *member, *other;
- register s32 sample;
- u8 *d, *p, *q, *o_q;
- struct sk_buff *nskb, *txskb;
- int r, rr, t, tt, o_r, o_rr;
- int preload = 0;
- struct mISDNhead *hh, *thh;
- int tx_data_only = 0;
-
- /* don't process if: */
- if (!dsp->b_active) { /* if not active */
- dsp->last_tx = 0;
- return;
- }
- if (((dsp->conf && dsp->conf->hardware) || /* hardware conf */
- dsp->echo.hardware) && /* OR hardware echo */
- dsp->tx_R == dsp->tx_W && /* AND no tx-data */
- !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */
- if (!dsp->tx_data) { /* no tx_data for user space required */
- dsp->last_tx = 0;
- return;
- }
- if (dsp->conf && dsp->conf->software && dsp->conf->hardware)
- tx_data_only = 1;
- if (dsp->echo.software && dsp->echo.hardware)
- tx_data_only = 1;
- }
-
-#ifdef CMX_DEBUG
- printk(KERN_DEBUG
- "SEND members=%d dsp=%s, conf=%p, rx_R=%05x rx_W=%05x\n",
- members, dsp->name, conf, dsp->rx_R, dsp->rx_W);
-#endif
-
- /* preload if we have delay set */
- if (dsp->cmx_delay && !dsp->last_tx) {
- preload = len;
- if (preload < 128)
- preload = 128;
- }
-
- /* PREPARE RESULT */
- nskb = mI_alloc_skb(len + preload, GFP_ATOMIC);
- if (!nskb) {
- printk(KERN_ERR
- "FATAL ERROR in mISDN_dsp.o: cannot alloc %d bytes\n",
- len + preload);
- return;
- }
- hh = mISDN_HEAD_P(nskb);
- hh->prim = PH_DATA_REQ;
- hh->id = 0;
- dsp->last_tx = 1;
-
- /* set pointers, indexes and stuff */
- member = dsp;
- p = dsp->tx_buff; /* transmit data */
- q = dsp->rx_buff; /* received data */
- d = skb_put(nskb, preload + len); /* result */
- t = dsp->tx_R; /* tx-pointers */
- tt = dsp->tx_W;
- r = dsp->rx_R; /* rx-pointers */
- rr = (r + len) & CMX_BUFF_MASK;
-
- /* preload with silence, if required */
- if (preload) {
- memset(d, dsp_silence, preload);
- d += preload;
- }
-
- /* PROCESS TONES/TX-DATA ONLY */
- if (dsp->tone.tone && dsp->tone.software) {
- /* -> copy tone */
- dsp_tone_copy(dsp, d, len);
- dsp->tx_R = 0; /* clear tx buffer */
- dsp->tx_W = 0;
- goto send_packet;
- }
- /* if we have tx-data but do not use mixing */
- if (!dsp->tx_mix && t != tt) {
- /* -> send tx-data and continue when not enough */
-#ifdef CMX_TX_DEBUG
- sprintf(debugbuf, "TX sending (%04x-%04x)%p: ", t, tt, p);
-#endif
- while (r != rr && t != tt) {
-#ifdef CMX_TX_DEBUG
- if (strlen(debugbuf) < 48)
- sprintf(debugbuf + strlen(debugbuf), " %02x",
- p[t]);
-#endif
- *d++ = p[t]; /* write tx_buff */
- t = (t + 1) & CMX_BUFF_MASK;
- r = (r + 1) & CMX_BUFF_MASK;
- }
- if (r == rr) {
- dsp->tx_R = t;
-#ifdef CMX_TX_DEBUG
- printk(KERN_DEBUG "%s\n", debugbuf);
-#endif
- goto send_packet;
- }
- }
-#ifdef CMX_TX_DEBUG
- printk(KERN_DEBUG "%s\n", debugbuf);
-#endif
-
- /* PROCESS DATA (one member / no conf) */
- if (!conf || members <= 1) {
- /* -> if echo is NOT enabled */
- if (!dsp->echo.software) {
- /* -> send tx-data if available or use 0-volume */
- while (r != rr && t != tt) {
- *d++ = p[t]; /* write tx_buff */
- t = (t + 1) & CMX_BUFF_MASK;
- r = (r + 1) & CMX_BUFF_MASK;
- }
- if (r != rr) {
- if (dsp_debug & DEBUG_DSP_CLOCK)
- printk(KERN_DEBUG "%s: RX empty\n",
- __func__);
- memset(d, dsp_silence, (rr - r) & CMX_BUFF_MASK);
- }
- /* -> if echo is enabled */
- } else {
- /*
- * -> mix tx-data with echo if available,
- * or use echo only
- */
- while (r != rr && t != tt) {
- *d++ = dsp_audio_mix_law[(p[t] << 8) | q[r]];
- t = (t + 1) & CMX_BUFF_MASK;
- r = (r + 1) & CMX_BUFF_MASK;
- }
- while (r != rr) {
- *d++ = q[r]; /* echo */
- r = (r + 1) & CMX_BUFF_MASK;
- }
- }
- dsp->tx_R = t;
- goto send_packet;
- }
- /* PROCESS DATA (two members) */
-#ifdef CMX_CONF_DEBUG
- if (0) {
-#else
- if (members == 2) {
-#endif
- /* "other" becomes other party */
- other = (list_entry(conf->mlist.next,
- struct dsp_conf_member, list))->dsp;
- if (other == member)
- other = (list_entry(conf->mlist.prev,
- struct dsp_conf_member, list))->dsp;
- o_q = other->rx_buff; /* received data */
- o_rr = (other->rx_R + len) & CMX_BUFF_MASK;
- /* end of rx-pointer */
- o_r = (o_rr - rr + r) & CMX_BUFF_MASK;
- /* start rx-pointer at current read position*/
- /* -> if echo is NOT enabled */
- if (!dsp->echo.software) {
- /*
- * -> copy other member's rx-data,
- * if tx-data is available, mix
- */
- while (o_r != o_rr && t != tt) {
- *d++ = dsp_audio_mix_law[(p[t] << 8) | o_q[o_r]];
- t = (t + 1) & CMX_BUFF_MASK;
- o_r = (o_r + 1) & CMX_BUFF_MASK;
- }
- while (o_r != o_rr) {
- *d++ = o_q[o_r];
- o_r = (o_r + 1) & CMX_BUFF_MASK;
- }
- /* -> if echo is enabled */
- } else {
- /*
- * -> mix other member's rx-data with echo,
- * if tx-data is available, mix
- */
- while (r != rr && t != tt) {
- sample = dsp_audio_law_to_s32[p[t]] +
- dsp_audio_law_to_s32[q[r]] +
- dsp_audio_law_to_s32[o_q[o_r]];
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- *d++ = dsp_audio_s16_to_law[sample & 0xffff];
- /* tx-data + rx_data + echo */
- t = (t + 1) & CMX_BUFF_MASK;
- r = (r + 1) & CMX_BUFF_MASK;
- o_r = (o_r + 1) & CMX_BUFF_MASK;
- }
- while (r != rr) {
- *d++ = dsp_audio_mix_law[(q[r] << 8) | o_q[o_r]];
- r = (r + 1) & CMX_BUFF_MASK;
- o_r = (o_r + 1) & CMX_BUFF_MASK;
- }
- }
- dsp->tx_R = t;
- goto send_packet;
- }
- /* PROCESS DATA (three or more members) */
- /* -> if echo is NOT enabled */
- if (!dsp->echo.software) {
- /*
- * -> subtract rx-data from conf-data,
- * if tx-data is available, mix
- */
- while (r != rr && t != tt) {
- sample = dsp_audio_law_to_s32[p[t]] + *c++ -
- dsp_audio_law_to_s32[q[r]];
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- *d++ = dsp_audio_s16_to_law[sample & 0xffff];
- /* conf-rx+tx */
- r = (r + 1) & CMX_BUFF_MASK;
- t = (t + 1) & CMX_BUFF_MASK;
- }
- while (r != rr) {
- sample = *c++ - dsp_audio_law_to_s32[q[r]];
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- *d++ = dsp_audio_s16_to_law[sample & 0xffff];
- /* conf-rx */
- r = (r + 1) & CMX_BUFF_MASK;
- }
- /* -> if echo is enabled */
- } else {
- /*
- * -> encode conf-data, if tx-data
- * is available, mix
- */
- while (r != rr && t != tt) {
- sample = dsp_audio_law_to_s32[p[t]] + *c++;
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- *d++ = dsp_audio_s16_to_law[sample & 0xffff];
- /* conf(echo)+tx */
- t = (t + 1) & CMX_BUFF_MASK;
- r = (r + 1) & CMX_BUFF_MASK;
- }
- while (r != rr) {
- sample = *c++;
- if (sample < -32768)
- sample = -32768;
- else if (sample > 32767)
- sample = 32767;
- *d++ = dsp_audio_s16_to_law[sample & 0xffff];
- /* conf(echo) */
- r = (r + 1) & CMX_BUFF_MASK;
- }
- }
- dsp->tx_R = t;
- goto send_packet;
-
-send_packet:
- /*
- * send tx-data if enabled - don't filter,
- * because we want what we send, not what we filtered
- */
- if (dsp->tx_data) {
- if (tx_data_only) {
- hh->prim = DL_DATA_REQ;
- hh->id = 0;
- /* queue and trigger */
- skb_queue_tail(&dsp->sendq, nskb);
- schedule_work(&dsp->workq);
- /* exit because only tx_data is used */
- return;
- } else {
- txskb = mI_alloc_skb(len, GFP_ATOMIC);
- if (!txskb) {
- printk(KERN_ERR
- "FATAL ERROR in mISDN_dsp.o: "
- "cannot alloc %d bytes\n", len);
- } else {
- thh = mISDN_HEAD_P(txskb);
- thh->prim = DL_DATA_REQ;
- thh->id = 0;
- skb_put_data(txskb, nskb->data + preload, len);
- /* queue (trigger later) */
- skb_queue_tail(&dsp->sendq, txskb);
- }
- }
- }
-
- /* send data only to card, if we don't just calculated tx_data */
- /* adjust volume */
- if (dsp->tx_volume)
- dsp_change_volume(nskb, dsp->tx_volume);
- /* pipeline */
- if (dsp->pipeline.inuse)
- dsp_pipeline_process_tx(&dsp->pipeline, nskb->data,
- nskb->len);
- /* crypt */
- if (dsp->bf_enable)
- dsp_bf_encrypt(dsp, nskb->data, nskb->len);
- /* queue and trigger */
- skb_queue_tail(&dsp->sendq, nskb);
- schedule_work(&dsp->workq);
-}
-
-static u32 jittercount; /* counter for jitter check */
-struct timer_list dsp_spl_tl;
-unsigned long dsp_spl_jiffies; /* calculate the next time to fire */
-static u16 dsp_count; /* last sample count */
-static int dsp_count_valid; /* if we have last sample count */
-
-void
-dsp_cmx_send(struct timer_list *arg)
-{
- struct dsp_conf *conf;
- struct dsp_conf_member *member;
- struct dsp *dsp;
- int mustmix, members;
- static s32 mixbuffer[MAX_POLL + 100];
- s32 *c;
- u8 *p, *q;
- int r, rr;
- int jittercheck = 0, delay, i;
- u_long flags;
- u16 length, count;
-
- /* lock */
- spin_lock_irqsave(&dsp_lock, flags);
-
- if (!dsp_count_valid) {
- dsp_count = mISDN_clock_get();
- length = dsp_poll;
- dsp_count_valid = 1;
- } else {
- count = mISDN_clock_get();
- length = count - dsp_count;
- dsp_count = count;
- }
- if (length > MAX_POLL + 100)
- length = MAX_POLL + 100;
- /* printk(KERN_DEBUG "len=%d dsp_count=0x%x\n", length, dsp_count); */
-
- /*
- * check if jitter needs to be checked (this is every second)
- */
- jittercount += length;
- if (jittercount >= 8000) {
- jittercount -= 8000;
- jittercheck = 1;
- }
-
- /* loop all members that do not require conference mixing */
- list_for_each_entry(dsp, &dsp_ilist, list) {
- if (dsp->hdlc)
- continue;
- conf = dsp->conf;
- mustmix = 0;
- members = 0;
- if (conf) {
- members = list_count_nodes(&conf->mlist);
-#ifdef CMX_CONF_DEBUG
- if (conf->software && members > 1)
-#else
- if (conf->software && members > 2)
-#endif
- mustmix = 1;
- }
-
- /* transmission required */
- if (!mustmix) {
- dsp_cmx_send_member(dsp, length, mixbuffer, members);
-
- /*
- * unused mixbuffer is given to prevent a
- * potential null-pointer-bug
- */
- }
- }
-
- /* loop all members that require conference mixing */
- list_for_each_entry(conf, &conf_ilist, list) {
- /* count members and check hardware */
- members = list_count_nodes(&conf->mlist);
-#ifdef CMX_CONF_DEBUG
- if (conf->software && members > 1) {
-#else
- if (conf->software && members > 2) {
-#endif
- /* check for hdlc conf */
- member = list_entry(conf->mlist.next,
- struct dsp_conf_member, list);
- if (member->dsp->hdlc)
- continue;
- /* mix all data */
- memset(mixbuffer, 0, length * sizeof(s32));
- list_for_each_entry(member, &conf->mlist, list) {
- dsp = member->dsp;
- /* get range of data to mix */
- c = mixbuffer;
- q = dsp->rx_buff;
- r = dsp->rx_R;
- rr = (r + length) & CMX_BUFF_MASK;
- /* add member's data */
- while (r != rr) {
- *c++ += dsp_audio_law_to_s32[q[r]];
- r = (r + 1) & CMX_BUFF_MASK;
- }
- }
-
- /* process each member */
- list_for_each_entry(member, &conf->mlist, list) {
- /* transmission */
- dsp_cmx_send_member(member->dsp, length,
- mixbuffer, members);
- }
- }
- }
-
- /* delete rx-data, increment buffers, change pointers */
- list_for_each_entry(dsp, &dsp_ilist, list) {
- if (dsp->hdlc)
- continue;
- p = dsp->rx_buff;
- q = dsp->tx_buff;
- r = dsp->rx_R;
- /* move receive pointer when receiving */
- if (!dsp->rx_is_off) {
- rr = (r + length) & CMX_BUFF_MASK;
- /* delete rx-data */
- while (r != rr) {
- p[r] = dsp_silence;
- r = (r + 1) & CMX_BUFF_MASK;
- }
- /* increment rx-buffer pointer */
- dsp->rx_R = r; /* write incremented read pointer */
- }
-
- /* check current rx_delay */
- delay = (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK;
- if (delay >= CMX_BUFF_HALF)
- delay = 0; /* will be the delay before next write */
- /* check for lower delay */
- if (delay < dsp->rx_delay[0])
- dsp->rx_delay[0] = delay;
- /* check current tx_delay */
- delay = (dsp->tx_W-dsp->tx_R) & CMX_BUFF_MASK;
- if (delay >= CMX_BUFF_HALF)
- delay = 0; /* will be the delay before next write */
- /* check for lower delay */
- if (delay < dsp->tx_delay[0])
- dsp->tx_delay[0] = delay;
- if (jittercheck) {
- /* find the lowest of all rx_delays */
- delay = dsp->rx_delay[0];
- i = 1;
- while (i < MAX_SECONDS_JITTER_CHECK) {
- if (delay > dsp->rx_delay[i])
- delay = dsp->rx_delay[i];
- i++;
- }
- /*
- * remove rx_delay only if we have delay AND we
- * have not preset cmx_delay AND
- * the delay is greater dsp_poll
- */
- if (delay > dsp_poll && !dsp->cmx_delay) {
- if (dsp_debug & DEBUG_DSP_CLOCK)
- printk(KERN_DEBUG
- "%s lowest rx_delay of %d bytes for"
- " dsp %s are now removed.\n",
- __func__, delay,
- dsp->name);
- r = dsp->rx_R;
- rr = (r + delay - (dsp_poll >> 1))
- & CMX_BUFF_MASK;
- /* delete rx-data */
- while (r != rr) {
- p[r] = dsp_silence;
- r = (r + 1) & CMX_BUFF_MASK;
- }
- /* increment rx-buffer pointer */
- dsp->rx_R = r;
- /* write incremented read pointer */
- }
- /* find the lowest of all tx_delays */
- delay = dsp->tx_delay[0];
- i = 1;
- while (i < MAX_SECONDS_JITTER_CHECK) {
- if (delay > dsp->tx_delay[i])
- delay = dsp->tx_delay[i];
- i++;
- }
- /*
- * remove delay only if we have delay AND we
- * have enabled tx_dejitter
- */
- if (delay > dsp_poll && dsp->tx_dejitter) {
- if (dsp_debug & DEBUG_DSP_CLOCK)
- printk(KERN_DEBUG
- "%s lowest tx_delay of %d bytes for"
- " dsp %s are now removed.\n",
- __func__, delay,
- dsp->name);
- r = dsp->tx_R;
- rr = (r + delay - (dsp_poll >> 1))
- & CMX_BUFF_MASK;
- /* delete tx-data */
- while (r != rr) {
- q[r] = dsp_silence;
- r = (r + 1) & CMX_BUFF_MASK;
- }
- /* increment rx-buffer pointer */
- dsp->tx_R = r;
- /* write incremented read pointer */
- }
- /* scroll up delays */
- i = MAX_SECONDS_JITTER_CHECK - 1;
- while (i) {
- dsp->rx_delay[i] = dsp->rx_delay[i - 1];
- dsp->tx_delay[i] = dsp->tx_delay[i - 1];
- i--;
- }
- dsp->tx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */
- dsp->rx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */
- }
- }
-
- /* if next event would be in the past ... */
- if ((s32)(dsp_spl_jiffies + dsp_tics-jiffies) <= 0)
- dsp_spl_jiffies = jiffies + 1;
- else
- dsp_spl_jiffies += dsp_tics;
-
- dsp_spl_tl.expires = dsp_spl_jiffies;
- add_timer(&dsp_spl_tl);
-
- /* unlock */
- spin_unlock_irqrestore(&dsp_lock, flags);
-}
-
-/*
- * audio data is transmitted from upper layer to the dsp
- */
-void
-dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb)
-{
- u_int w, ww;
- u8 *d, *p;
- int space; /* todo: , l = skb->len; */
-#ifdef CMX_TX_DEBUG
- char debugbuf[256] = "";
-#endif
-
- /* check if there is enough space, and then copy */
- w = dsp->tx_W;
- ww = dsp->tx_R;
- p = dsp->tx_buff;
- d = skb->data;
- space = (ww - w - 1) & CMX_BUFF_MASK;
- /* write-pointer should not overrun nor reach read pointer */
- if (space < skb->len) {
- /* write to the space we have left */
- ww = (ww - 1) & CMX_BUFF_MASK; /* end one byte prior tx_R */
- if (dsp_debug & DEBUG_DSP_CLOCK)
- printk(KERN_DEBUG "%s: TX overflow space=%d skb->len="
- "%d, w=0x%04x, ww=0x%04x\n", __func__, space,
- skb->len, w, ww);
- } else
- /* write until all byte are copied */
- ww = (w + skb->len) & CMX_BUFF_MASK;
- dsp->tx_W = ww;
- /* show current buffer */
-#ifdef CMX_DEBUG
- printk(KERN_DEBUG
- "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n",
- (u_long)dsp, (ww - w) & CMX_BUFF_MASK, w, ww, dsp->name);
-#endif
-
- /* copy transmit data to tx-buffer */
-#ifdef CMX_TX_DEBUG
- sprintf(debugbuf, "TX getting (%04x-%04x)%p: ", w, ww, p);
-#endif
- while (w != ww) {
-#ifdef CMX_TX_DEBUG
- if (strlen(debugbuf) < 48)
- sprintf(debugbuf + strlen(debugbuf), " %02x", *d);
-#endif
- p[w] = *d++;
- w = (w + 1) & CMX_BUFF_MASK;
- }
-#ifdef CMX_TX_DEBUG
- printk(KERN_DEBUG "%s\n", debugbuf);
-#endif
-
-}
-
-/*
- * hdlc data is received from card and sent to all members.
- */
-void
-dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb)
-{
- struct sk_buff *nskb = NULL;
- struct dsp_conf_member *member;
- struct mISDNhead *hh;
-
- /* not if not active */
- if (!dsp->b_active)
- return;
-
- /* check if we have sompen */
- if (skb->len < 1)
- return;
-
- /* no conf */
- if (!dsp->conf) {
- /* in case of software echo */
- if (dsp->echo.software) {
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (nskb) {
- hh = mISDN_HEAD_P(nskb);
- hh->prim = PH_DATA_REQ;
- hh->id = 0;
- skb_queue_tail(&dsp->sendq, nskb);
- schedule_work(&dsp->workq);
- }
- }
- return;
- }
- /* in case of hardware conference */
- if (dsp->conf->hardware)
- return;
- list_for_each_entry(member, &dsp->conf->mlist, list) {
- if (dsp->echo.software || member->dsp != dsp) {
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (nskb) {
- hh = mISDN_HEAD_P(nskb);
- hh->prim = PH_DATA_REQ;
- hh->id = 0;
- skb_queue_tail(&member->dsp->sendq, nskb);
- schedule_work(&member->dsp->workq);
- }
- }
- }
-}
+++ /dev/null
-/*
- * Author Andreas Eversberg (jolly@eversberg.eu)
- * Based on source code structure by
- * Karsten Keil (keil@isdn4linux.de)
- *
- * This file is (c) under GNU PUBLIC LICENSE
- *
- * Thanks to Karsten Keil (great drivers)
- * Cologne Chip (great chips)
- *
- * This module does:
- * Real-time tone generation
- * DTMF detection
- * Real-time cross-connection and conferrence
- * Compensate jitter due to system load and hardware fault.
- * All features are done in kernel space and will be realized
- * using hardware, if available and supported by chip set.
- * Blowfish encryption/decryption
- */
-
-/* STRUCTURE:
- *
- * The dsp module provides layer 2 for b-channels (64kbit). It provides
- * transparent audio forwarding with special digital signal processing:
- *
- * - (1) generation of tones
- * - (2) detection of dtmf tones
- * - (3) crossconnecting and conferences (clocking)
- * - (4) echo generation for delay test
- * - (5) volume control
- * - (6) disable receive data
- * - (7) pipeline
- * - (8) encryption/decryption
- *
- * Look:
- * TX RX
- * ------upper layer------
- * | ^
- * | |(6)
- * v |
- * +-----+-------------+-----+
- * |(3)(4) |
- * | CMX |
- * | |
- * | +-------------+
- * | | ^
- * | | |
- * |+---------+| +----+----+
- * ||(1) || |(2) |
- * || || | |
- * || Tones || | DTMF |
- * || || | |
- * || || | |
- * |+----+----+| +----+----+
- * +-----+-----+ ^
- * | |
- * v |
- * +----+----+ +----+----+
- * |(5) | |(5) |
- * | | | |
- * |TX Volume| |RX Volume|
- * | | | |
- * | | | |
- * +----+----+ +----+----+
- * | ^
- * | |
- * v |
- * +----+-------------+----+
- * |(7) |
- * | |
- * | Pipeline Processing |
- * | |
- * | |
- * +----+-------------+----+
- * | ^
- * | |
- * v |
- * +----+----+ +----+----+
- * |(8) | |(8) |
- * | | | |
- * | Encrypt | | Decrypt |
- * | | | |
- * | | | |
- * +----+----+ +----+----+
- * | ^
- * | |
- * v |
- * ------card layer------
- * TX RX
- *
- * Above you can see the logical data flow. If software is used to do the
- * process, it is actually the real data flow. If hardware is used, data
- * may not flow, but hardware commands to the card, to provide the data flow
- * as shown.
- *
- * NOTE: The channel must be activated in order to make dsp work, even if
- * no data flow to the upper layer is intended. Activation can be done
- * after and before controlling the setting using PH_CONTROL requests.
- *
- * DTMF: Will be detected by hardware if possible. It is done before CMX
- * processing.
- *
- * Tones: Will be generated via software if endless looped audio fifos are
- * not supported by hardware. Tones will override all data from CMX.
- * It is not required to join a conference to use tones at any time.
- *
- * CMX: Is transparent when not used. When it is used, it will do
- * crossconnections and conferences via software if not possible through
- * hardware. If hardware capability is available, hardware is used.
- *
- * Echo: Is generated by CMX and is used to check performance of hard and
- * software CMX.
- *
- * The CMX has special functions for conferences with one, two and more
- * members. It will allow different types of data flow. Receive and transmit
- * data to/form upper layer may be switched on/off individually without losing
- * features of CMX, Tones and DTMF.
- *
- * Echo Cancellation: Sometimes we like to cancel echo from the interface.
- * Note that a VoIP call may not have echo caused by the IP phone. The echo
- * is generated by the telephone line connected to it. Because the delay
- * is high, it becomes an echo. RESULT: Echo Cachelation is required if
- * both echo AND delay is applied to an interface.
- * Remember that software CMX always generates a more or less delay.
- *
- * If all used features can be realized in hardware, and if transmit and/or
- * receive data ist disabled, the card may not send/receive any data at all.
- * Not receiving is useful if only announcements are played. Not sending is
- * useful if an answering machine records audio. Not sending and receiving is
- * useful during most states of the call. If supported by hardware, tones
- * will be played without cpu load. Small PBXs and NT-Mode applications will
- * not need expensive hardware when processing calls.
- *
- *
- * LOCKING:
- *
- * When data is received from upper or lower layer (card), the complete dsp
- * module is locked by a global lock. This lock MUST lock irq, because it
- * must lock timer events by DSP poll timer.
- * When data is ready to be transmitted down, the data is queued and sent
- * outside lock and timer event.
- * PH_CONTROL must not change any settings, join or split conference members
- * during process of data.
- *
- * HDLC:
- *
- * It works quite the same as transparent, except that HDLC data is forwarded
- * to all other conference members if no hardware bridging is possible.
- * Send data will be writte to sendq. Sendq will be sent if confirm is received.
- * Conference cannot join, if one member is not hdlc.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/gfp.h>
-#include <linux/mISDNif.h>
-#include <linux/mISDNdsp.h>
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include "core.h"
-#include "dsp.h"
-
-static const char *mISDN_dsp_revision = "2.0";
-
-static int debug;
-static int options;
-static int poll;
-static int dtmfthreshold = 100;
-
-MODULE_AUTHOR("Andreas Eversberg");
-module_param(debug, uint, S_IRUGO | S_IWUSR);
-module_param(options, uint, S_IRUGO | S_IWUSR);
-module_param(poll, uint, S_IRUGO | S_IWUSR);
-module_param(dtmfthreshold, uint, S_IRUGO | S_IWUSR);
-MODULE_DESCRIPTION("mISDN driver for Digital Audio Processing of transparent data");
-MODULE_LICENSE("GPL");
-
-/*int spinnest = 0;*/
-
-DEFINE_SPINLOCK(dsp_lock); /* global dsp lock */
-LIST_HEAD(dsp_ilist);
-LIST_HEAD(conf_ilist);
-int dsp_debug;
-int dsp_options;
-int dsp_poll, dsp_tics;
-
-/* check if rx may be turned off or must be turned on */
-static void
-dsp_rx_off_member(struct dsp *dsp)
-{
- struct mISDN_ctrl_req cq;
- int rx_off = 1;
-
- memset(&cq, 0, sizeof(cq));
-
- if (!dsp->features_rx_off)
- return;
-
- /* not disabled */
- if (!dsp->rx_disabled)
- rx_off = 0;
- /* software dtmf */
- else if (dsp->dtmf.software)
- rx_off = 0;
- /* echo in software */
- else if (dsp->echo.software)
- rx_off = 0;
- /* bridge in software */
- else if (dsp->conf && dsp->conf->software)
- rx_off = 0;
- /* data is not required by user space and not required
- * for echo dtmf detection, soft-echo, soft-bridging */
-
- if (rx_off == dsp->rx_is_off)
- return;
-
- if (!dsp->ch.peer) {
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: no peer, no rx_off\n",
- __func__);
- return;
- }
- cq.op = MISDN_CTRL_RX_OFF;
- cq.p1 = rx_off;
- if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) {
- printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n",
- __func__);
- return;
- }
- dsp->rx_is_off = rx_off;
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: %s set rx_off = %d\n",
- __func__, dsp->name, rx_off);
-}
-static void
-dsp_rx_off(struct dsp *dsp)
-{
- struct dsp_conf_member *member;
-
- if (dsp_options & DSP_OPT_NOHARDWARE)
- return;
-
- /* no conf */
- if (!dsp->conf) {
- dsp_rx_off_member(dsp);
- return;
- }
- /* check all members in conf */
- list_for_each_entry(member, &dsp->conf->mlist, list) {
- dsp_rx_off_member(member->dsp);
- }
-}
-
-/* enable "fill empty" feature */
-static void
-dsp_fill_empty(struct dsp *dsp)
-{
- struct mISDN_ctrl_req cq;
-
- memset(&cq, 0, sizeof(cq));
-
- if (!dsp->ch.peer) {
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: no peer, no fill_empty\n",
- __func__);
- return;
- }
- cq.op = MISDN_CTRL_FILL_EMPTY;
- cq.p1 = 1;
- cq.p2 = dsp_silence;
- if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) {
- printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n",
- __func__);
- return;
- }
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: %s set fill_empty = 1\n",
- __func__, dsp->name);
-}
-
-static int
-dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb)
-{
- struct sk_buff *nskb;
- int ret = 0;
- int cont;
- u8 *data;
- int len;
-
- if (skb->len < sizeof(int)) {
- printk(KERN_ERR "%s: PH_CONTROL message too short\n", __func__);
- return -EINVAL;
- }
- cont = *((int *)skb->data);
- len = skb->len - sizeof(int);
- data = skb->data + sizeof(int);
-
- switch (cont) {
- case DTMF_TONE_START: /* turn on DTMF */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: start dtmf\n", __func__);
- if (len == sizeof(int)) {
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_NOTICE "changing DTMF Threshold "
- "to %d\n", *((int *)data));
- dsp->dtmf.treshold = (*(int *)data) * 10000;
- }
- dsp->dtmf.enable = 1;
- /* init goertzel */
- dsp_dtmf_goertzel_init(dsp);
-
- /* check dtmf hardware */
- dsp_dtmf_hardware(dsp);
- dsp_rx_off(dsp);
- break;
- case DTMF_TONE_STOP: /* turn off DTMF */
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: stop dtmf\n", __func__);
- dsp->dtmf.enable = 0;
- dsp->dtmf.hardware = 0;
- dsp->dtmf.software = 0;
- break;
- case DSP_CONF_JOIN: /* join / update conference */
- if (len < sizeof(int)) {
- ret = -EINVAL;
- break;
- }
- if (*((u32 *)data) == 0)
- goto conf_split;
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: join conference %d\n",
- __func__, *((u32 *)data));
- ret = dsp_cmx_conf(dsp, *((u32 *)data));
- /* dsp_cmx_hardware will also be called here */
- dsp_rx_off(dsp);
- if (dsp_debug & DEBUG_DSP_CMX)
- dsp_cmx_debug(dsp);
- break;
- case DSP_CONF_SPLIT: /* remove from conference */
- conf_split:
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: release conference\n", __func__);
- ret = dsp_cmx_conf(dsp, 0);
- /* dsp_cmx_hardware will also be called here */
- if (dsp_debug & DEBUG_DSP_CMX)
- dsp_cmx_debug(dsp);
- dsp_rx_off(dsp);
- break;
- case DSP_TONE_PATT_ON: /* play tone */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- if (len < sizeof(int)) {
- ret = -EINVAL;
- break;
- }
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: turn tone 0x%x on\n",
- __func__, *((int *)skb->data));
- ret = dsp_tone(dsp, *((int *)data));
- if (!ret) {
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_rx_off(dsp);
- }
- if (!dsp->tone.tone)
- goto tone_off;
- break;
- case DSP_TONE_PATT_OFF: /* stop tone */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: turn tone off\n", __func__);
- dsp_tone(dsp, 0);
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_rx_off(dsp);
- /* reset tx buffers (user space data) */
- tone_off:
- dsp->rx_W = 0;
- dsp->rx_R = 0;
- break;
- case DSP_VOL_CHANGE_TX: /* change volume */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- if (len < sizeof(int)) {
- ret = -EINVAL;
- break;
- }
- dsp->tx_volume = *((int *)data);
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: change tx vol to %d\n",
- __func__, dsp->tx_volume);
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_dtmf_hardware(dsp);
- dsp_rx_off(dsp);
- break;
- case DSP_VOL_CHANGE_RX: /* change volume */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- if (len < sizeof(int)) {
- ret = -EINVAL;
- break;
- }
- dsp->rx_volume = *((int *)data);
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: change rx vol to %d\n",
- __func__, dsp->tx_volume);
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_dtmf_hardware(dsp);
- dsp_rx_off(dsp);
- break;
- case DSP_ECHO_ON: /* enable echo */
- dsp->echo.software = 1; /* soft echo */
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__);
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_rx_off(dsp);
- if (dsp_debug & DEBUG_DSP_CMX)
- dsp_cmx_debug(dsp);
- break;
- case DSP_ECHO_OFF: /* disable echo */
- dsp->echo.software = 0;
- dsp->echo.hardware = 0;
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__);
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_rx_off(dsp);
- if (dsp_debug & DEBUG_DSP_CMX)
- dsp_cmx_debug(dsp);
- break;
- case DSP_RECEIVE_ON: /* enable receive to user space */
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: enable receive to user "
- "space\n", __func__);
- dsp->rx_disabled = 0;
- dsp_rx_off(dsp);
- break;
- case DSP_RECEIVE_OFF: /* disable receive to user space */
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: disable receive to "
- "user space\n", __func__);
- dsp->rx_disabled = 1;
- dsp_rx_off(dsp);
- break;
- case DSP_MIX_ON: /* enable mixing of tx data */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: enable mixing of "
- "tx-data with conf members\n", __func__);
- dsp->tx_mix = 1;
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_rx_off(dsp);
- if (dsp_debug & DEBUG_DSP_CMX)
- dsp_cmx_debug(dsp);
- break;
- case DSP_MIX_OFF: /* disable mixing of tx data */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: disable mixing of "
- "tx-data with conf members\n", __func__);
- dsp->tx_mix = 0;
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_rx_off(dsp);
- if (dsp_debug & DEBUG_DSP_CMX)
- dsp_cmx_debug(dsp);
- break;
- case DSP_TXDATA_ON: /* enable txdata */
- dsp->tx_data = 1;
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: enable tx-data\n", __func__);
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_rx_off(dsp);
- if (dsp_debug & DEBUG_DSP_CMX)
- dsp_cmx_debug(dsp);
- break;
- case DSP_TXDATA_OFF: /* disable txdata */
- dsp->tx_data = 0;
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: disable tx-data\n", __func__);
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_rx_off(dsp);
- if (dsp_debug & DEBUG_DSP_CMX)
- dsp_cmx_debug(dsp);
- break;
- case DSP_DELAY: /* use delay algorithm instead of dynamic
- jitter algorithm */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- if (len < sizeof(int)) {
- ret = -EINVAL;
- break;
- }
- dsp->cmx_delay = (*((int *)data)) << 3;
- /* milliseconds to samples */
- if (dsp->cmx_delay >= (CMX_BUFF_HALF >> 1))
- /* clip to half of maximum usable buffer
- (half of half buffer) */
- dsp->cmx_delay = (CMX_BUFF_HALF >> 1) - 1;
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: use delay algorithm to "
- "compensate jitter (%d samples)\n",
- __func__, dsp->cmx_delay);
- break;
- case DSP_JITTER: /* use dynamic jitter algorithm instead of
- delay algorithm */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- dsp->cmx_delay = 0;
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: use jitter algorithm to "
- "compensate jitter\n", __func__);
- break;
- case DSP_TX_DEJITTER: /* use dynamic jitter algorithm for tx-buffer */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- dsp->tx_dejitter = 1;
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: use dejitter on TX "
- "buffer\n", __func__);
- break;
- case DSP_TX_DEJ_OFF: /* use tx-buffer without dejittering*/
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- dsp->tx_dejitter = 0;
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: use TX buffer without "
- "dejittering\n", __func__);
- break;
- case DSP_PIPELINE_CFG:
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- if (len > 0 && ((char *)data)[len - 1]) {
- printk(KERN_DEBUG "%s: pipeline config string "
- "is not NULL terminated!\n", __func__);
- ret = -EINVAL;
- } else {
- dsp->pipeline.inuse = 1;
- dsp_cmx_hardware(dsp->conf, dsp);
- ret = dsp_pipeline_build(&dsp->pipeline,
- len > 0 ? data : NULL);
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_rx_off(dsp);
- }
- break;
- case DSP_BF_ENABLE_KEY: /* turn blowfish on */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- if (len < 4 || len > 56) {
- ret = -EINVAL;
- break;
- }
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: turn blowfish on (key "
- "not shown)\n", __func__);
- ret = dsp_bf_init(dsp, (u8 *)data, len);
- /* set new cont */
- if (!ret)
- cont = DSP_BF_ACCEPT;
- else
- cont = DSP_BF_REJECT;
- /* send indication if it worked to set it */
- nskb = _alloc_mISDN_skb(PH_CONTROL_IND, MISDN_ID_ANY,
- sizeof(int), &cont, GFP_ATOMIC);
- if (nskb) {
- if (dsp->up) {
- if (dsp->up->send(dsp->up, nskb))
- dev_kfree_skb(nskb);
- } else
- dev_kfree_skb(nskb);
- }
- if (!ret) {
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_dtmf_hardware(dsp);
- dsp_rx_off(dsp);
- }
- break;
- case DSP_BF_DISABLE: /* turn blowfish off */
- if (dsp->hdlc) {
- ret = -EINVAL;
- break;
- }
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: turn blowfish off\n", __func__);
- dsp_bf_cleanup(dsp);
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_dtmf_hardware(dsp);
- dsp_rx_off(dsp);
- break;
- default:
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: ctrl req %x unhandled\n",
- __func__, cont);
- ret = -EINVAL;
- }
- return ret;
-}
-
-static void
-get_features(struct mISDNchannel *ch)
-{
- struct dsp *dsp = container_of(ch, struct dsp, ch);
- struct mISDN_ctrl_req cq;
-
- if (!ch->peer) {
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: no peer, no features\n",
- __func__);
- return;
- }
- memset(&cq, 0, sizeof(cq));
- cq.op = MISDN_CTRL_GETOP;
- if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq) < 0) {
- printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n",
- __func__);
- return;
- }
- if (cq.op & MISDN_CTRL_RX_OFF)
- dsp->features_rx_off = 1;
- if (cq.op & MISDN_CTRL_FILL_EMPTY)
- dsp->features_fill_empty = 1;
- if (dsp_options & DSP_OPT_NOHARDWARE)
- return;
- if ((cq.op & MISDN_CTRL_HW_FEATURES_OP)) {
- cq.op = MISDN_CTRL_HW_FEATURES;
- *((u_long *)&cq.p1) = (u_long)&dsp->features;
- if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq)) {
- printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n",
- __func__);
- }
- } else
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: features not supported for %s\n",
- __func__, dsp->name);
-}
-
-static int
-dsp_function(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct dsp *dsp = container_of(ch, struct dsp, ch);
- struct mISDNhead *hh;
- int ret = 0;
- u8 *digits = NULL;
- u_long flags;
-
- hh = mISDN_HEAD_P(skb);
- switch (hh->prim) {
- /* FROM DOWN */
- case (PH_DATA_CNF):
- dsp->data_pending = 0;
- /* trigger next hdlc frame, if any */
- if (dsp->hdlc) {
- spin_lock_irqsave(&dsp_lock, flags);
- if (dsp->b_active)
- schedule_work(&dsp->workq);
- spin_unlock_irqrestore(&dsp_lock, flags);
- }
- break;
- case (PH_DATA_IND):
- case (DL_DATA_IND):
- if (skb->len < 1) {
- ret = -EINVAL;
- break;
- }
- if (dsp->rx_is_off) {
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: rx-data during rx_off"
- " for %s\n",
- __func__, dsp->name);
- }
- if (dsp->hdlc) {
- /* hdlc */
- spin_lock_irqsave(&dsp_lock, flags);
- dsp_cmx_hdlc(dsp, skb);
- spin_unlock_irqrestore(&dsp_lock, flags);
- if (dsp->rx_disabled) {
- /* if receive is not allowed */
- break;
- }
- hh->prim = DL_DATA_IND;
- if (dsp->up)
- return dsp->up->send(dsp->up, skb);
- break;
- }
-
- spin_lock_irqsave(&dsp_lock, flags);
-
- /* decrypt if enabled */
- if (dsp->bf_enable)
- dsp_bf_decrypt(dsp, skb->data, skb->len);
- /* pipeline */
- if (dsp->pipeline.inuse)
- dsp_pipeline_process_rx(&dsp->pipeline, skb->data,
- skb->len, hh->id);
- /* change volume if requested */
- if (dsp->rx_volume)
- dsp_change_volume(skb, dsp->rx_volume);
- /* check if dtmf soft decoding is turned on */
- if (dsp->dtmf.software) {
- digits = dsp_dtmf_goertzel_decode(dsp, skb->data,
- skb->len, (dsp_options & DSP_OPT_ULAW) ? 1 : 0);
- }
- /* we need to process receive data if software */
- if (dsp->conf && dsp->conf->software) {
- /* process data from card at cmx */
- dsp_cmx_receive(dsp, skb);
- }
-
- spin_unlock_irqrestore(&dsp_lock, flags);
-
- /* send dtmf result, if any */
- if (digits) {
- while (*digits) {
- int k;
- struct sk_buff *nskb;
- if (dsp_debug & DEBUG_DSP_DTMF)
- printk(KERN_DEBUG "%s: digit"
- "(%c) to layer %s\n",
- __func__, *digits, dsp->name);
- k = *digits | DTMF_TONE_VAL;
- nskb = _alloc_mISDN_skb(PH_CONTROL_IND,
- MISDN_ID_ANY, sizeof(int), &k,
- GFP_ATOMIC);
- if (nskb) {
- if (dsp->up) {
- if (dsp->up->send(
- dsp->up, nskb))
- dev_kfree_skb(nskb);
- } else
- dev_kfree_skb(nskb);
- }
- digits++;
- }
- }
- if (dsp->rx_disabled) {
- /* if receive is not allowed */
- break;
- }
- hh->prim = DL_DATA_IND;
- if (dsp->up)
- return dsp->up->send(dsp->up, skb);
- break;
- case (PH_CONTROL_IND):
- if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
- printk(KERN_DEBUG "%s: PH_CONTROL INDICATION "
- "received: %x (len %d) %s\n", __func__,
- hh->id, skb->len, dsp->name);
- switch (hh->id) {
- case (DTMF_HFC_COEF): /* getting coefficients */
- if (!dsp->dtmf.hardware) {
- if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
- printk(KERN_DEBUG "%s: ignoring DTMF "
- "coefficients from HFC\n",
- __func__);
- break;
- }
- digits = dsp_dtmf_goertzel_decode(dsp, skb->data,
- skb->len, 2);
- while (*digits) {
- int k;
- struct sk_buff *nskb;
- if (dsp_debug & DEBUG_DSP_DTMF)
- printk(KERN_DEBUG "%s: digit"
- "(%c) to layer %s\n",
- __func__, *digits, dsp->name);
- k = *digits | DTMF_TONE_VAL;
- nskb = _alloc_mISDN_skb(PH_CONTROL_IND,
- MISDN_ID_ANY, sizeof(int), &k,
- GFP_ATOMIC);
- if (nskb) {
- if (dsp->up) {
- if (dsp->up->send(
- dsp->up, nskb))
- dev_kfree_skb(nskb);
- } else
- dev_kfree_skb(nskb);
- }
- digits++;
- }
- break;
- case (HFC_VOL_CHANGE_TX): /* change volume */
- if (skb->len != sizeof(int)) {
- ret = -EINVAL;
- break;
- }
- spin_lock_irqsave(&dsp_lock, flags);
- dsp->tx_volume = *((int *)skb->data);
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: change tx volume to "
- "%d\n", __func__, dsp->tx_volume);
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_dtmf_hardware(dsp);
- dsp_rx_off(dsp);
- spin_unlock_irqrestore(&dsp_lock, flags);
- break;
- default:
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: ctrl ind %x unhandled "
- "%s\n", __func__, hh->id, dsp->name);
- ret = -EINVAL;
- }
- break;
- case (PH_ACTIVATE_IND):
- case (PH_ACTIVATE_CNF):
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: b_channel is now active %s\n",
- __func__, dsp->name);
- /* bchannel now active */
- spin_lock_irqsave(&dsp_lock, flags);
- dsp->b_active = 1;
- dsp->data_pending = 0;
- dsp->rx_init = 1;
- /* rx_W and rx_R will be adjusted on first frame */
- dsp->rx_W = 0;
- dsp->rx_R = 0;
- memset(dsp->rx_buff, 0, sizeof(dsp->rx_buff));
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_dtmf_hardware(dsp);
- dsp_rx_off(dsp);
- spin_unlock_irqrestore(&dsp_lock, flags);
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: done with activation, sending "
- "confirm to user space. %s\n", __func__,
- dsp->name);
- /* send activation to upper layer */
- hh->prim = DL_ESTABLISH_CNF;
- if (dsp->up)
- return dsp->up->send(dsp->up, skb);
- break;
- case (PH_DEACTIVATE_IND):
- case (PH_DEACTIVATE_CNF):
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: b_channel is now inactive %s\n",
- __func__, dsp->name);
- /* bchannel now inactive */
- spin_lock_irqsave(&dsp_lock, flags);
- dsp->b_active = 0;
- dsp->data_pending = 0;
- dsp_cmx_hardware(dsp->conf, dsp);
- dsp_rx_off(dsp);
- spin_unlock_irqrestore(&dsp_lock, flags);
- hh->prim = DL_RELEASE_CNF;
- if (dsp->up)
- return dsp->up->send(dsp->up, skb);
- break;
- /* FROM UP */
- case (DL_DATA_REQ):
- case (PH_DATA_REQ):
- if (skb->len < 1) {
- ret = -EINVAL;
- break;
- }
- if (dsp->hdlc) {
- /* hdlc */
- if (!dsp->b_active) {
- ret = -EIO;
- break;
- }
- hh->prim = PH_DATA_REQ;
- spin_lock_irqsave(&dsp_lock, flags);
- skb_queue_tail(&dsp->sendq, skb);
- schedule_work(&dsp->workq);
- spin_unlock_irqrestore(&dsp_lock, flags);
- return 0;
- }
- /* send data to tx-buffer (if no tone is played) */
- if (!dsp->tone.tone) {
- spin_lock_irqsave(&dsp_lock, flags);
- dsp_cmx_transmit(dsp, skb);
- spin_unlock_irqrestore(&dsp_lock, flags);
- }
- break;
- case (PH_CONTROL_REQ):
- spin_lock_irqsave(&dsp_lock, flags);
- ret = dsp_control_req(dsp, hh, skb);
- spin_unlock_irqrestore(&dsp_lock, flags);
- break;
- case (DL_ESTABLISH_REQ):
- case (PH_ACTIVATE_REQ):
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: activating b_channel %s\n",
- __func__, dsp->name);
- if (dsp->dtmf.hardware || dsp->dtmf.software)
- dsp_dtmf_goertzel_init(dsp);
- get_features(ch);
- /* enable fill_empty feature */
- if (dsp->features_fill_empty)
- dsp_fill_empty(dsp);
- /* send ph_activate */
- hh->prim = PH_ACTIVATE_REQ;
- if (ch->peer)
- return ch->recv(ch->peer, skb);
- break;
- case (DL_RELEASE_REQ):
- case (PH_DEACTIVATE_REQ):
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: releasing b_channel %s\n",
- __func__, dsp->name);
- spin_lock_irqsave(&dsp_lock, flags);
- dsp->tone.tone = 0;
- dsp->tone.hardware = 0;
- dsp->tone.software = 0;
- if (timer_pending(&dsp->tone.tl))
- timer_delete(&dsp->tone.tl);
- if (dsp->conf)
- dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be
- called here */
- skb_queue_purge(&dsp->sendq);
- spin_unlock_irqrestore(&dsp_lock, flags);
- hh->prim = PH_DEACTIVATE_REQ;
- if (ch->peer)
- return ch->recv(ch->peer, skb);
- break;
- default:
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: msg %x unhandled %s\n",
- __func__, hh->prim, dsp->name);
- ret = -EINVAL;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static int
-dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct dsp *dsp = container_of(ch, struct dsp, ch);
- u_long flags;
-
- if (debug & DEBUG_DSP_CTRL)
- printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd);
-
- switch (cmd) {
- case OPEN_CHANNEL:
- break;
- case CLOSE_CHANNEL:
- if (dsp->ch.peer)
- dsp->ch.peer->ctrl(dsp->ch.peer, CLOSE_CHANNEL, NULL);
-
- /* wait until workqueue has finished,
- * must lock here, or we may hit send-process currently
- * queueing. */
- spin_lock_irqsave(&dsp_lock, flags);
- dsp->b_active = 0;
- spin_unlock_irqrestore(&dsp_lock, flags);
- /* MUST not be locked, because it waits until queue is done. */
- cancel_work_sync(&dsp->workq);
- spin_lock_irqsave(&dsp_lock, flags);
- if (timer_pending(&dsp->tone.tl))
- timer_delete(&dsp->tone.tl);
- skb_queue_purge(&dsp->sendq);
- if (dsp_debug & DEBUG_DSP_CTRL)
- printk(KERN_DEBUG "%s: releasing member %s\n",
- __func__, dsp->name);
- dsp->b_active = 0;
- dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be called
- here */
- dsp_pipeline_destroy(&dsp->pipeline);
-
- if (dsp_debug & DEBUG_DSP_CTRL)
- printk(KERN_DEBUG "%s: remove & destroy object %s\n",
- __func__, dsp->name);
- list_del(&dsp->list);
- spin_unlock_irqrestore(&dsp_lock, flags);
-
- if (dsp_debug & DEBUG_DSP_CTRL)
- printk(KERN_DEBUG "%s: dsp instance released\n",
- __func__);
- vfree(dsp);
- module_put(THIS_MODULE);
- break;
- }
- return 0;
-}
-
-static void
-dsp_send_bh(struct work_struct *work)
-{
- struct dsp *dsp = container_of(work, struct dsp, workq);
- struct sk_buff *skb;
- struct mISDNhead *hh;
-
- if (dsp->hdlc && dsp->data_pending)
- return; /* wait until data has been acknowledged */
-
- /* send queued data */
- while ((skb = skb_dequeue(&dsp->sendq))) {
- /* in locked date, we must have still data in queue */
- if (dsp->data_pending) {
- if (dsp_debug & DEBUG_DSP_CORE)
- printk(KERN_DEBUG "%s: fifo full %s, this is "
- "no bug!\n", __func__, dsp->name);
- /* flush transparent data, if not acked */
- dev_kfree_skb(skb);
- continue;
- }
- hh = mISDN_HEAD_P(skb);
- if (hh->prim == DL_DATA_REQ) {
- /* send packet up */
- if (dsp->up) {
- if (dsp->up->send(dsp->up, skb))
- dev_kfree_skb(skb);
- } else
- dev_kfree_skb(skb);
- } else {
- /* send packet down */
- if (dsp->ch.peer) {
- dsp->data_pending = 1;
- if (dsp->ch.recv(dsp->ch.peer, skb)) {
- dev_kfree_skb(skb);
- dsp->data_pending = 0;
- }
- } else
- dev_kfree_skb(skb);
- }
- }
-}
-
-static int
-dspcreate(struct channel_req *crq)
-{
- struct dsp *ndsp;
- u_long flags;
-
- if (crq->protocol != ISDN_P_B_L2DSP
- && crq->protocol != ISDN_P_B_L2DSPHDLC)
- return -EPROTONOSUPPORT;
- ndsp = vzalloc(sizeof(struct dsp));
- if (!ndsp) {
- printk(KERN_ERR "%s: vmalloc struct dsp failed\n", __func__);
- return -ENOMEM;
- }
- if (dsp_debug & DEBUG_DSP_CTRL)
- printk(KERN_DEBUG "%s: creating new dsp instance\n", __func__);
-
- /* default enabled */
- INIT_WORK(&ndsp->workq, (void *)dsp_send_bh);
- skb_queue_head_init(&ndsp->sendq);
- ndsp->ch.send = dsp_function;
- ndsp->ch.ctrl = dsp_ctrl;
- ndsp->up = crq->ch;
- crq->ch = &ndsp->ch;
- if (crq->protocol == ISDN_P_B_L2DSP) {
- crq->protocol = ISDN_P_B_RAW;
- ndsp->hdlc = 0;
- } else {
- crq->protocol = ISDN_P_B_HDLC;
- ndsp->hdlc = 1;
- }
- if (!try_module_get(THIS_MODULE))
- printk(KERN_WARNING "%s:cannot get module\n",
- __func__);
-
- sprintf(ndsp->name, "DSP_C%x(0x%p)",
- ndsp->up->st->dev->id + 1, ndsp);
- /* set frame size to start */
- ndsp->features.hfc_id = -1; /* current PCM id */
- ndsp->features.pcm_id = -1; /* current PCM id */
- ndsp->pcm_slot_rx = -1; /* current CPM slot */
- ndsp->pcm_slot_tx = -1;
- ndsp->pcm_bank_rx = -1;
- ndsp->pcm_bank_tx = -1;
- ndsp->hfc_conf = -1; /* current conference number */
- /* set tone timer */
- timer_setup(&ndsp->tone.tl, dsp_tone_timeout, 0);
-
- if (dtmfthreshold < 20 || dtmfthreshold > 500)
- dtmfthreshold = 200;
- ndsp->dtmf.treshold = dtmfthreshold * 10000;
-
- /* init pipeline append to list */
- spin_lock_irqsave(&dsp_lock, flags);
- dsp_pipeline_init(&ndsp->pipeline);
- list_add_tail(&ndsp->list, &dsp_ilist);
- spin_unlock_irqrestore(&dsp_lock, flags);
-
- return 0;
-}
-
-
-static struct Bprotocol DSP = {
- .Bprotocols = (1 << (ISDN_P_B_L2DSP & ISDN_P_B_MASK))
- | (1 << (ISDN_P_B_L2DSPHDLC & ISDN_P_B_MASK)),
- .name = "dsp",
- .create = dspcreate
-};
-
-static int __init dsp_init(void)
-{
- int err;
- int tics;
-
- printk(KERN_INFO "DSP module %s\n", mISDN_dsp_revision);
-
- dsp_options = options;
- dsp_debug = debug;
-
- /* set packet size */
- dsp_poll = poll;
- if (dsp_poll) {
- if (dsp_poll > MAX_POLL) {
- printk(KERN_ERR "%s: Wrong poll value (%d), use %d "
- "maximum.\n", __func__, poll, MAX_POLL);
- err = -EINVAL;
- return err;
- }
- if (dsp_poll < 8) {
- printk(KERN_ERR "%s: Wrong poll value (%d), use 8 "
- "minimum.\n", __func__, dsp_poll);
- err = -EINVAL;
- return err;
- }
- dsp_tics = poll * HZ / 8000;
- if (dsp_tics * 8000 != poll * HZ) {
- printk(KERN_INFO "mISDN_dsp: Cannot clock every %d "
- "samples (0,125 ms). It is not a multiple of "
- "%d HZ.\n", poll, HZ);
- err = -EINVAL;
- return err;
- }
- } else {
- poll = 8;
- while (poll <= MAX_POLL) {
- tics = (poll * HZ) / 8000;
- if (tics * 8000 == poll * HZ) {
- dsp_tics = tics;
- dsp_poll = poll;
- if (poll >= 64)
- break;
- }
- poll++;
- }
- }
- if (dsp_poll == 0) {
- printk(KERN_INFO "mISDN_dsp: There is no multiple of kernel "
- "clock that equals exactly the duration of 8-256 "
- "samples. (Choose kernel clock speed like 100, 250, "
- "300, 1000)\n");
- err = -EINVAL;
- return err;
- }
- printk(KERN_INFO "mISDN_dsp: DSP clocks every %d samples. This equals "
- "%d jiffies.\n", dsp_poll, dsp_tics);
-
- /* init conversion tables */
- dsp_audio_generate_law_tables();
- dsp_silence = (dsp_options & DSP_OPT_ULAW) ? 0xff : 0x2a;
- dsp_audio_law_to_s32 = (dsp_options & DSP_OPT_ULAW) ?
- dsp_audio_ulaw_to_s32 : dsp_audio_alaw_to_s32;
- dsp_audio_generate_s2law_table();
- dsp_audio_generate_seven();
- dsp_audio_generate_mix_table();
- if (dsp_options & DSP_OPT_ULAW)
- dsp_audio_generate_ulaw_samples();
- dsp_audio_generate_volume_changes();
-
- err = dsp_pipeline_module_init();
- if (err) {
- printk(KERN_ERR "mISDN_dsp: Can't initialize pipeline, "
- "error(%d)\n", err);
- return err;
- }
-
- err = mISDN_register_Bprotocol(&DSP);
- if (err) {
- printk(KERN_ERR "Can't register %s error(%d)\n", DSP.name, err);
- return err;
- }
-
- /* set sample timer */
- timer_setup(&dsp_spl_tl, dsp_cmx_send, 0);
- dsp_spl_tl.expires = jiffies + dsp_tics;
- dsp_spl_jiffies = dsp_spl_tl.expires;
- add_timer(&dsp_spl_tl);
-
- return 0;
-}
-
-
-static void __exit dsp_cleanup(void)
-{
- mISDN_unregister_Bprotocol(&DSP);
-
- timer_delete_sync(&dsp_spl_tl);
-
- if (!list_empty(&dsp_ilist)) {
- printk(KERN_ERR "mISDN_dsp: Audio DSP object inst list not "
- "empty.\n");
- }
- if (!list_empty(&conf_ilist)) {
- printk(KERN_ERR "mISDN_dsp: Conference list not empty. Not "
- "all memory freed.\n");
- }
-
- dsp_pipeline_module_exit();
-}
-
-module_init(dsp_init);
-module_exit(dsp_cleanup);
+++ /dev/null
-/*
- * DTMF decoder.
- *
- * Copyright by Andreas Eversberg (jolly@eversberg.eu)
- * based on different decoders such as ISDN4Linux
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/mISDNif.h>
-#include <linux/mISDNdsp.h>
-#include "core.h"
-#include "dsp.h"
-
-#define NCOEFF 8 /* number of frequencies to be analyzed */
-
-/* For DTMF recognition:
- * 2 * cos(2 * PI * k / N) precalculated for all k
- */
-static u64 cos2pik[NCOEFF] =
-{
- /* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */
- 55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630
-};
-
-/* digit matrix */
-static char dtmf_matrix[4][4] =
-{
- {'1', '2', '3', 'A'},
- {'4', '5', '6', 'B'},
- {'7', '8', '9', 'C'},
- {'*', '0', '#', 'D'}
-};
-
-/* dtmf detection using goertzel algorithm
- * init function
- */
-void dsp_dtmf_goertzel_init(struct dsp *dsp)
-{
- dsp->dtmf.size = 0;
- dsp->dtmf.lastwhat = '\0';
- dsp->dtmf.lastdigit = '\0';
- dsp->dtmf.count = 0;
-}
-
-/* check for hardware or software features
- */
-void dsp_dtmf_hardware(struct dsp *dsp)
-{
- int hardware = 1;
-
- if (!dsp->dtmf.enable)
- return;
-
- if (!dsp->features.hfc_dtmf)
- hardware = 0;
-
- /* check for volume change */
- if (dsp->tx_volume) {
- if (dsp_debug & DEBUG_DSP_DTMF)
- printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
- "because tx_volume is changed\n",
- __func__, dsp->name);
- hardware = 0;
- }
- if (dsp->rx_volume) {
- if (dsp_debug & DEBUG_DSP_DTMF)
- printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
- "because rx_volume is changed\n",
- __func__, dsp->name);
- hardware = 0;
- }
- /* check if encryption is enabled */
- if (dsp->bf_enable) {
- if (dsp_debug & DEBUG_DSP_DTMF)
- printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
- "because encryption is enabled\n",
- __func__, dsp->name);
- hardware = 0;
- }
- /* check if pipeline exists */
- if (dsp->pipeline.inuse) {
- if (dsp_debug & DEBUG_DSP_DTMF)
- printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
- "because pipeline exists.\n",
- __func__, dsp->name);
- hardware = 0;
- }
-
- dsp->dtmf.hardware = hardware;
- dsp->dtmf.software = !hardware;
-}
-
-
-/*************************************************************
- * calculate the coefficients of the given sample and decode *
- *************************************************************/
-
-/* the given sample is decoded. if the sample is not long enough for a
- * complete frame, the decoding is finished and continued with the next
- * call of this function.
- *
- * the algorithm is very good for detection with a minimum of errors. i
- * tested it allot. it even works with very short tones (40ms). the only
- * disadvantage is, that it doesn't work good with different volumes of both
- * tones. this will happen, if accoustically coupled dialers are used.
- * it sometimes detects tones during speech, which is normal for decoders.
- * use sequences to given commands during calls.
- *
- * dtmf - points to a structure of the current dtmf state
- * spl and len - the sample
- * fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder
- */
-
-u8
-*dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, int fmt)
-{
- u8 what;
- int size;
- signed short *buf;
- s32 sk, sk1, sk2;
- int k, n, i;
- s32 *hfccoeff;
- s32 result[NCOEFF], tresh, treshl;
- int lowgroup, highgroup;
- s64 cos2pik_;
-
- dsp->dtmf.digits[0] = '\0';
-
- /* Note: The function will loop until the buffer has not enough samples
- * left to decode a full frame.
- */
-again:
- /* convert samples */
- size = dsp->dtmf.size;
- buf = dsp->dtmf.buffer;
- switch (fmt) {
- case 0: /* alaw */
- case 1: /* ulaw */
- while (size < DSP_DTMF_NPOINTS && len) {
- buf[size++] = dsp_audio_law_to_s32[*data++];
- len--;
- }
- break;
-
- case 2: /* HFC coefficients */
- default:
- if (len < 64) {
- if (len > 0)
- printk(KERN_ERR "%s: coefficients have invalid "
- "size. (is=%d < must=%d)\n",
- __func__, len, 64);
- return dsp->dtmf.digits;
- }
- hfccoeff = (s32 *)data;
- for (k = 0; k < NCOEFF; k++) {
- sk2 = (*hfccoeff++) >> 4;
- sk = (*hfccoeff++) >> 4;
- if (sk > 32767 || sk < -32767 || sk2 > 32767
- || sk2 < -32767)
- printk(KERN_WARNING
- "DTMF-Detection overflow\n");
- /* compute |X(k)|**2 */
- result[k] =
- (sk * sk) -
- (((cos2pik[k] * sk) >> 15) * sk2) +
- (sk2 * sk2);
- }
- data += 64;
- len -= 64;
- goto coefficients;
- break;
- }
- dsp->dtmf.size = size;
-
- if (size < DSP_DTMF_NPOINTS)
- return dsp->dtmf.digits;
-
- dsp->dtmf.size = 0;
-
- /* now we have a full buffer of signed long samples - we do goertzel */
- for (k = 0; k < NCOEFF; k++) {
- sk = 0;
- sk1 = 0;
- sk2 = 0;
- buf = dsp->dtmf.buffer;
- cos2pik_ = cos2pik[k];
- for (n = 0; n < DSP_DTMF_NPOINTS; n++) {
- sk = ((cos2pik_ * sk1) >> 15) - sk2 + (*buf++);
- sk2 = sk1;
- sk1 = sk;
- }
- sk >>= 8;
- sk2 >>= 8;
- if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767)
- printk(KERN_WARNING "DTMF-Detection overflow\n");
- /* compute |X(k)|**2 */
- result[k] =
- (sk * sk) -
- (((cos2pik[k] * sk) >> 15) * sk2) +
- (sk2 * sk2);
- }
-
- /* our (squared) coefficients have been calculated, we need to process
- * them.
- */
-coefficients:
- tresh = 0;
- for (i = 0; i < NCOEFF; i++) {
- if (result[i] < 0)
- result[i] = 0;
- if (result[i] > dsp->dtmf.treshold) {
- if (result[i] > tresh)
- tresh = result[i];
- }
- }
-
- if (tresh == 0) {
- what = 0;
- goto storedigit;
- }
-
- if (dsp_debug & DEBUG_DSP_DTMFCOEFF) {
- s32 tresh_100 = tresh/100;
-
- if (tresh_100 == 0) {
- tresh_100 = 1;
- printk(KERN_DEBUG
- "tresh(%d) too small set tresh/100 to 1\n",
- tresh);
- }
- printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d"
- " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n",
- result[0] / 10000, result[1] / 10000, result[2] / 10000,
- result[3] / 10000, result[4] / 10000, result[5] / 10000,
- result[6] / 10000, result[7] / 10000, tresh / 10000,
- result[0] / (tresh_100), result[1] / (tresh_100),
- result[2] / (tresh_100), result[3] / (tresh_100),
- result[4] / (tresh_100), result[5] / (tresh_100),
- result[6] / (tresh_100), result[7] / (tresh_100));
- }
-
- /* calc digit (lowgroup/highgroup) */
- lowgroup = -1;
- highgroup = -1;
- treshl = tresh >> 3; /* tones which are not on, must be below 9 dB */
- tresh = tresh >> 2; /* touchtones must match within 6 dB */
- for (i = 0; i < NCOEFF; i++) {
- if (result[i] < treshl)
- continue; /* ignore */
- if (result[i] < tresh) {
- lowgroup = -1;
- highgroup = -1;
- break; /* noise in between */
- }
- /* good level found. This is allowed only one time per group */
- if (i < NCOEFF / 2) {
- /* lowgroup */
- if (lowgroup >= 0) {
- /* Bad. Another tone found. */
- lowgroup = -1;
- break;
- } else
- lowgroup = i;
- } else {
- /* higroup */
- if (highgroup >= 0) {
- /* Bad. Another tone found. */
- highgroup = -1;
- break;
- } else
- highgroup = i - (NCOEFF / 2);
- }
- }
-
- /* get digit or null */
- what = 0;
- if (lowgroup >= 0 && highgroup >= 0)
- what = dtmf_matrix[lowgroup][highgroup];
-
-storedigit:
- if (what && (dsp_debug & DEBUG_DSP_DTMF))
- printk(KERN_DEBUG "DTMF what: %c\n", what);
-
- if (dsp->dtmf.lastwhat != what)
- dsp->dtmf.count = 0;
-
- /* the tone (or no tone) must remain 3 times without change */
- if (dsp->dtmf.count == 2) {
- if (dsp->dtmf.lastdigit != what) {
- dsp->dtmf.lastdigit = what;
- if (what) {
- if (dsp_debug & DEBUG_DSP_DTMF)
- printk(KERN_DEBUG "DTMF digit: %c\n",
- what);
- if ((strlen(dsp->dtmf.digits) + 1)
- < sizeof(dsp->dtmf.digits)) {
- dsp->dtmf.digits[strlen(
- dsp->dtmf.digits) + 1] = '\0';
- dsp->dtmf.digits[strlen(
- dsp->dtmf.digits)] = what;
- }
- }
- }
- } else
- dsp->dtmf.count++;
-
- dsp->dtmf.lastwhat = what;
-
- goto again;
-}
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * ec_disable_detector.h - A detector which should eventually meet the
- * G.164/G.165 requirements for detecting the
- * 2100Hz echo cancellor disable tone.
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2001 Steve Underwood
- *
- * All rights reserved.
- */
-
-#include "dsp_biquad.h"
-
-struct ec_disable_detector_state {
- struct biquad2_state notch;
- int notch_level;
- int channel_level;
- int tone_present;
- int tone_cycle_duration;
- int good_cycles;
- int hit;
-};
-
-
-#define FALSE 0
-#define TRUE (!FALSE)
-
-static inline void
-echo_can_disable_detector_init(struct ec_disable_detector_state *det)
-{
- /* Elliptic notch */
- /* This is actually centred at 2095Hz, but gets the balance we want, due
- to the asymmetric walls of the notch */
- biquad2_init(&det->notch,
- (int32_t)(-0.7600000 * 32768.0),
- (int32_t)(-0.1183852 * 32768.0),
- (int32_t)(-0.5104039 * 32768.0),
- (int32_t)(0.1567596 * 32768.0),
- (int32_t)(1.0000000 * 32768.0));
-
- det->channel_level = 0;
- det->notch_level = 0;
- det->tone_present = FALSE;
- det->tone_cycle_duration = 0;
- det->good_cycles = 0;
- det->hit = 0;
-}
-/*- End of function --------------------------------------------------------*/
-
-static inline int
-echo_can_disable_detector_update(struct ec_disable_detector_state *det,
- int16_t amp)
-{
- int16_t notched;
-
- notched = biquad2(&det->notch, amp);
- /* Estimate the overall energy in the channel, and the energy in
- the notch (i.e. overall channel energy - tone energy => noise).
- Use abs instead of multiply for speed (is it really faster?).
- Damp the overall energy a little more for a stable result.
- Damp the notch energy a little less, so we don't damp out the
- blip every time the phase reverses */
- det->channel_level += ((abs(amp) - det->channel_level) >> 5);
- det->notch_level += ((abs(notched) - det->notch_level) >> 4);
- if (det->channel_level > 280) {
- /* There is adequate energy in the channel.
- Is it mostly at 2100Hz? */
- if (det->notch_level * 6 < det->channel_level) {
- /* The notch says yes, so we have the tone. */
- if (!det->tone_present) {
- /* Do we get a kick every 450+-25ms? */
- if (det->tone_cycle_duration >= 425 * 8
- && det->tone_cycle_duration <= 475 * 8) {
- det->good_cycles++;
- if (det->good_cycles > 2)
- det->hit = TRUE;
- }
- det->tone_cycle_duration = 0;
- }
- det->tone_present = TRUE;
- } else
- det->tone_present = FALSE;
- det->tone_cycle_duration++;
- } else {
- det->tone_present = FALSE;
- det->tone_cycle_duration = 0;
- det->good_cycles = 0;
- }
- return det->hit;
-}
-/*- End of function --------------------------------------------------------*/
-/*- End of file ------------------------------------------------------------*/
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * dsp_hwec.c:
- * builtin mISDN dsp pipeline element for enabling the hw echocanceller
- *
- * Copyright (C) 2007, Nadi Sarrar
- *
- * Nadi Sarrar <nadi@beronet.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/mISDNdsp.h>
-#include <linux/mISDNif.h>
-#include "core.h"
-#include "dsp.h"
-#include "dsp_hwec.h"
-
-static struct mISDN_dsp_element_arg args[] = {
- { "deftaps", "128", "Set the number of taps of cancellation." },
-};
-
-static struct mISDN_dsp_element dsp_hwec_p = {
- .name = "hwec",
- .new = NULL,
- .free = NULL,
- .process_tx = NULL,
- .process_rx = NULL,
- .num_args = ARRAY_SIZE(args),
- .args = args,
-};
-struct mISDN_dsp_element *dsp_hwec = &dsp_hwec_p;
-
-void dsp_hwec_enable(struct dsp *dsp, const char *arg)
-{
- int deftaps = 128,
- len;
- struct mISDN_ctrl_req cq;
-
- if (!dsp) {
- printk(KERN_ERR "%s: failed to enable hwec: dsp is NULL\n",
- __func__);
- return;
- }
-
- if (!arg)
- goto _do;
-
- len = strlen(arg);
- if (!len)
- goto _do;
-
- {
- char *dup, *next, *tok, *name, *val;
- int tmp;
-
- dup = next = kstrdup(arg, GFP_ATOMIC);
- if (!dup)
- return;
-
- while ((tok = strsep(&next, ","))) {
- if (!strlen(tok))
- continue;
- name = strsep(&tok, "=");
- val = tok;
-
- if (!val)
- continue;
-
- if (!strcmp(name, "deftaps")) {
- if (sscanf(val, "%d", &tmp) == 1)
- deftaps = tmp;
- }
- }
-
- kfree(dup);
- }
-
-_do:
- printk(KERN_DEBUG "%s: enabling hwec with deftaps=%d\n",
- __func__, deftaps);
- memset(&cq, 0, sizeof(cq));
- cq.op = MISDN_CTRL_HFC_ECHOCAN_ON;
- cq.p1 = deftaps;
- if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) {
- printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n",
- __func__);
- return;
- }
-}
-
-void dsp_hwec_disable(struct dsp *dsp)
-{
- struct mISDN_ctrl_req cq;
-
- if (!dsp) {
- printk(KERN_ERR "%s: failed to disable hwec: dsp is NULL\n",
- __func__);
- return;
- }
-
- printk(KERN_DEBUG "%s: disabling hwec\n", __func__);
- memset(&cq, 0, sizeof(cq));
- cq.op = MISDN_CTRL_HFC_ECHOCAN_OFF;
- if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) {
- printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n",
- __func__);
- return;
- }
-}
-
-int dsp_hwec_init(void)
-{
- mISDN_dsp_element_register(dsp_hwec);
-
- return 0;
-}
-
-void dsp_hwec_exit(void)
-{
- mISDN_dsp_element_unregister(dsp_hwec);
-}
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * dsp_hwec.h
- */
-
-extern struct mISDN_dsp_element *dsp_hwec;
-extern void dsp_hwec_enable(struct dsp *dsp, const char *arg);
-extern void dsp_hwec_disable(struct dsp *dsp);
-extern int dsp_hwec_init(void);
-extern void dsp_hwec_exit(void);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * dsp_pipeline.c: pipelined audio processing
- *
- * Copyright (C) 2007, Nadi Sarrar
- *
- * Nadi Sarrar <nadi@beronet.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/string.h>
-#include <linux/mISDNif.h>
-#include <linux/mISDNdsp.h>
-#include <linux/export.h>
-#include "dsp.h"
-#include "dsp_hwec.h"
-
-struct dsp_pipeline_entry {
- struct mISDN_dsp_element *elem;
- void *p;
- struct list_head list;
-};
-struct dsp_element_entry {
- struct mISDN_dsp_element *elem;
- struct device dev;
- struct list_head list;
-};
-
-static LIST_HEAD(dsp_elements);
-
-/* sysfs */
-static const struct class elements_class = {
- .name = "dsp_pipeline",
-};
-
-static ssize_t
-attr_show_args(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct mISDN_dsp_element *elem = dev_get_drvdata(dev);
- int i;
- char *p = buf;
-
- *buf = 0;
- for (i = 0; i < elem->num_args; i++)
- p += sprintf(p, "Name: %s\n%s%s%sDescription: %s\n\n",
- elem->args[i].name,
- elem->args[i].def ? "Default: " : "",
- elem->args[i].def ? elem->args[i].def : "",
- elem->args[i].def ? "\n" : "",
- elem->args[i].desc);
-
- return p - buf;
-}
-
-static struct device_attribute element_attributes[] = {
- __ATTR(args, 0444, attr_show_args, NULL),
-};
-
-static void
-mISDN_dsp_dev_release(struct device *dev)
-{
- struct dsp_element_entry *entry =
- container_of(dev, struct dsp_element_entry, dev);
- list_del(&entry->list);
- kfree(entry);
-}
-
-int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
-{
- struct dsp_element_entry *entry;
- int ret, i;
-
- if (!elem)
- return -EINVAL;
-
- entry = kzalloc_obj(struct dsp_element_entry, GFP_ATOMIC);
- if (!entry)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&entry->list);
- entry->elem = elem;
-
- entry->dev.class = &elements_class;
- entry->dev.release = mISDN_dsp_dev_release;
- dev_set_drvdata(&entry->dev, elem);
- dev_set_name(&entry->dev, "%s", elem->name);
- ret = device_register(&entry->dev);
- if (ret) {
- printk(KERN_ERR "%s: failed to register %s\n",
- __func__, elem->name);
- goto err1;
- }
- list_add_tail(&entry->list, &dsp_elements);
-
- for (i = 0; i < ARRAY_SIZE(element_attributes); ++i) {
- ret = device_create_file(&entry->dev,
- &element_attributes[i]);
- if (ret) {
- printk(KERN_ERR "%s: failed to create device file\n",
- __func__);
- goto err2;
- }
- }
-
- return 0;
-
-err2:
- device_unregister(&entry->dev);
- return ret;
-err1:
- put_device(&entry->dev);
- return ret;
-}
-EXPORT_SYMBOL(mISDN_dsp_element_register);
-
-void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem)
-{
- struct dsp_element_entry *entry, *n;
-
- if (!elem)
- return;
-
- list_for_each_entry_safe(entry, n, &dsp_elements, list)
- if (entry->elem == elem) {
- device_unregister(&entry->dev);
- return;
- }
- printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name);
-}
-EXPORT_SYMBOL(mISDN_dsp_element_unregister);
-
-int dsp_pipeline_module_init(void)
-{
- int err;
-
- err = class_register(&elements_class);
- if (err)
- return err;
-
- dsp_hwec_init();
-
- return 0;
-}
-
-void dsp_pipeline_module_exit(void)
-{
- struct dsp_element_entry *entry, *n;
-
- dsp_hwec_exit();
-
- class_unregister(&elements_class);
-
- list_for_each_entry_safe(entry, n, &dsp_elements, list) {
- list_del(&entry->list);
- printk(KERN_WARNING "%s: element was still registered: %s\n",
- __func__, entry->elem->name);
- kfree(entry);
- }
-}
-
-int dsp_pipeline_init(struct dsp_pipeline *pipeline)
-{
- if (!pipeline)
- return -EINVAL;
-
- INIT_LIST_HEAD(&pipeline->list);
-
- return 0;
-}
-
-static inline void _dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
-{
- struct dsp_pipeline_entry *entry, *n;
-
- list_for_each_entry_safe(entry, n, &pipeline->list, list) {
- list_del(&entry->list);
- if (entry->elem == dsp_hwec)
- dsp_hwec_disable(container_of(pipeline, struct dsp,
- pipeline));
- else
- entry->elem->free(entry->p);
- kfree(entry);
- }
-}
-
-void dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
-{
-
- if (!pipeline)
- return;
-
- _dsp_pipeline_destroy(pipeline);
-}
-
-int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
-{
- int found = 0;
- char *dup, *next, *tok, *name, *args;
- struct dsp_element_entry *entry, *n;
- struct dsp_pipeline_entry *pipeline_entry;
- struct mISDN_dsp_element *elem;
-
- if (!pipeline)
- return -EINVAL;
-
- if (!list_empty(&pipeline->list))
- _dsp_pipeline_destroy(pipeline);
-
- dup = next = kstrdup(cfg, GFP_ATOMIC);
- if (!dup)
- return 0;
- while ((tok = strsep(&next, "|"))) {
- if (!strlen(tok))
- continue;
- name = strsep(&tok, "(");
- args = strsep(&tok, ")");
- if (args && !*args)
- args = NULL;
-
- list_for_each_entry_safe(entry, n, &dsp_elements, list)
- if (!strcmp(entry->elem->name, name)) {
- elem = entry->elem;
-
- pipeline_entry = kmalloc_obj(struct dsp_pipeline_entry,
- GFP_ATOMIC);
- if (!pipeline_entry) {
- printk(KERN_ERR "%s: failed to add "
- "entry to pipeline: %s (out of "
- "memory)\n", __func__, elem->name);
- goto _out;
- }
- pipeline_entry->elem = elem;
-
- if (elem == dsp_hwec) {
- /* This is a hack to make the hwec
- available as a pipeline module */
- dsp_hwec_enable(container_of(pipeline,
- struct dsp, pipeline), args);
- list_add_tail(&pipeline_entry->list,
- &pipeline->list);
- } else {
- pipeline_entry->p = elem->new(args);
- if (pipeline_entry->p) {
- list_add_tail(&pipeline_entry->
- list, &pipeline->list);
- } else {
- printk(KERN_ERR "%s: failed "
- "to add entry to pipeline: "
- "%s (new() returned NULL)\n",
- __func__, elem->name);
- kfree(pipeline_entry);
- }
- }
- found = 1;
- break;
- }
-
- if (found)
- found = 0;
- else
- printk(KERN_ERR "%s: element not found, skipping: "
- "%s\n", __func__, name);
- }
-
-_out:
- if (!list_empty(&pipeline->list))
- pipeline->inuse = 1;
- else
- pipeline->inuse = 0;
-
- kfree(dup);
- return 0;
-}
-
-void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len)
-{
- struct dsp_pipeline_entry *entry;
-
- if (!pipeline)
- return;
-
- list_for_each_entry(entry, &pipeline->list, list)
- if (entry->elem->process_tx)
- entry->elem->process_tx(entry->p, data, len);
-}
-
-void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len,
- unsigned int txlen)
-{
- struct dsp_pipeline_entry *entry;
-
- if (!pipeline)
- return;
-
- list_for_each_entry_reverse(entry, &pipeline->list, list)
- if (entry->elem->process_rx)
- entry->elem->process_rx(entry->p, data, len, txlen);
-}
+++ /dev/null
-/*
- * Audio support data for ISDN4Linux.
- *
- * Copyright Andreas Eversberg (jolly@eversberg.eu)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/gfp.h>
-#include <linux/mISDNif.h>
-#include <linux/mISDNdsp.h>
-#include "core.h"
-#include "dsp.h"
-
-
-#define DATA_S sample_silence
-#define SIZE_S (&sizeof_silence)
-#define DATA_GA sample_german_all
-#define SIZE_GA (&sizeof_german_all)
-#define DATA_GO sample_german_old
-#define SIZE_GO (&sizeof_german_old)
-#define DATA_DT sample_american_dialtone
-#define SIZE_DT (&sizeof_american_dialtone)
-#define DATA_RI sample_american_ringing
-#define SIZE_RI (&sizeof_american_ringing)
-#define DATA_BU sample_american_busy
-#define SIZE_BU (&sizeof_american_busy)
-#define DATA_S1 sample_special1
-#define SIZE_S1 (&sizeof_special1)
-#define DATA_S2 sample_special2
-#define SIZE_S2 (&sizeof_special2)
-#define DATA_S3 sample_special3
-#define SIZE_S3 (&sizeof_special3)
-
-/***************/
-/* tones loops */
-/***************/
-
-/* all tones are alaw encoded */
-/* the last sample+1 is in phase with the first sample. the error is low */
-
-static u8 sample_german_all[] = {
- 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d,
- 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c,
- 0xdc, 0xfc, 0x6c,
- 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d,
- 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c,
- 0xdc, 0xfc, 0x6c,
- 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d,
- 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c,
- 0xdc, 0xfc, 0x6c,
- 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d,
- 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c,
- 0xdc, 0xfc, 0x6c,
-};
-static u32 sizeof_german_all = sizeof(sample_german_all);
-
-static u8 sample_german_old[] = {
- 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed,
- 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70,
- 0x8c,
- 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed,
- 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70,
- 0x8c,
- 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed,
- 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70,
- 0x8c,
- 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed,
- 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70,
- 0x8c,
-};
-static u32 sizeof_german_old = sizeof(sample_german_old);
-
-static u8 sample_american_dialtone[] = {
- 0x2a, 0x18, 0x90, 0x6c, 0x4c, 0xbc, 0x4c, 0x6c,
- 0x10, 0x58, 0x32, 0xb9, 0x31, 0x2d, 0x8d, 0x0d,
- 0x8d, 0x2d, 0x31, 0x99, 0x0f, 0x28, 0x60, 0xf0,
- 0xd0, 0x50, 0xd0, 0x30, 0x60, 0x08, 0x8e, 0x67,
- 0x09, 0x19, 0x21, 0xe1, 0xd9, 0xb9, 0x29, 0x67,
- 0x83, 0x02, 0xce, 0xbe, 0xee, 0x1a, 0x1b, 0xef,
- 0xbf, 0xcf, 0x03, 0x82, 0x66, 0x28, 0xb8, 0xd8,
- 0xe0, 0x20, 0x18, 0x08, 0x66, 0x8f, 0x09, 0x61,
- 0x31, 0xd1, 0x51, 0xd1, 0xf1, 0x61, 0x29, 0x0e,
- 0x98, 0x30, 0x2c, 0x8c, 0x0c, 0x8c, 0x2c, 0x30,
- 0xb8, 0x33, 0x59, 0x11, 0x6d, 0x4d, 0xbd, 0x4d,
- 0x6d, 0x91, 0x19,
-};
-static u32 sizeof_american_dialtone = sizeof(sample_american_dialtone);
-
-static u8 sample_american_ringing[] = {
- 0x2a, 0xe0, 0xac, 0x0c, 0xbc, 0x4c, 0x8c, 0x90,
- 0x48, 0xc7, 0xc1, 0xed, 0xcd, 0x4d, 0xcd, 0xed,
- 0xc1, 0xb7, 0x08, 0x30, 0xec, 0xcc, 0xcc, 0x8c,
- 0x10, 0x58, 0x1a, 0x99, 0x71, 0xed, 0x8d, 0x8d,
- 0x2d, 0x41, 0x89, 0x9e, 0x20, 0x70, 0x2c, 0xec,
- 0x2c, 0x70, 0x20, 0x86, 0x77, 0xe1, 0x31, 0x11,
- 0xd1, 0xf1, 0x81, 0x09, 0xa3, 0x56, 0x58, 0x00,
- 0x40, 0xc0, 0x60, 0x38, 0x46, 0x43, 0x57, 0x39,
- 0xd9, 0x59, 0x99, 0xc9, 0x77, 0x2f, 0x2e, 0xc6,
- 0xd6, 0x28, 0xd6, 0x36, 0x26, 0x2e, 0x8a, 0xa3,
- 0x43, 0x63, 0x4b, 0x4a, 0x62, 0x42, 0xa2, 0x8b,
- 0x2f, 0x27, 0x37, 0xd7, 0x29, 0xd7, 0xc7, 0x2f,
- 0x2e, 0x76, 0xc8, 0x98, 0x58, 0xd8, 0x38, 0x56,
- 0x42, 0x47, 0x39, 0x61, 0xc1, 0x41, 0x01, 0x59,
- 0x57, 0xa2, 0x08, 0x80, 0xf0, 0xd0, 0x10, 0x30,
- 0xe0, 0x76, 0x87, 0x21, 0x71, 0x2d, 0xed, 0x2d,
- 0x71, 0x21, 0x9f, 0x88, 0x40, 0x2c, 0x8c, 0x8c,
- 0xec, 0x70, 0x98, 0x1b, 0x59, 0x11, 0x8d, 0xcd,
- 0xcd, 0xed, 0x31, 0x09, 0xb6, 0xc0, 0xec, 0xcc,
- 0x4c, 0xcc, 0xec, 0xc0, 0xc6, 0x49, 0x91, 0x8d,
- 0x4d, 0xbd, 0x0d, 0xad, 0xe1,
-};
-static u32 sizeof_american_ringing = sizeof(sample_american_ringing);
-
-static u8 sample_american_busy[] = {
- 0x2a, 0x00, 0x6c, 0x4c, 0x4c, 0x6c, 0xb0, 0x66,
- 0x99, 0x11, 0x6d, 0x8d, 0x2d, 0x41, 0xd7, 0x96,
- 0x60, 0xf0, 0x70, 0x40, 0x58, 0xf6, 0x53, 0x57,
- 0x09, 0x89, 0xd7, 0x5f, 0xe3, 0x2a, 0xe3, 0x5f,
- 0xd7, 0x89, 0x09, 0x57, 0x53, 0xf6, 0x58, 0x40,
- 0x70, 0xf0, 0x60, 0x96, 0xd7, 0x41, 0x2d, 0x8d,
- 0x6d, 0x11, 0x99, 0x66, 0xb0, 0x6c, 0x4c, 0x4c,
- 0x6c, 0x00, 0x2a, 0x01, 0x6d, 0x4d, 0x4d, 0x6d,
- 0xb1, 0x67, 0x98, 0x10, 0x6c, 0x8c, 0x2c, 0x40,
- 0xd6, 0x97, 0x61, 0xf1, 0x71, 0x41, 0x59, 0xf7,
- 0x52, 0x56, 0x08, 0x88, 0xd6, 0x5e, 0xe2, 0x2a,
- 0xe2, 0x5e, 0xd6, 0x88, 0x08, 0x56, 0x52, 0xf7,
- 0x59, 0x41, 0x71, 0xf1, 0x61, 0x97, 0xd6, 0x40,
- 0x2c, 0x8c, 0x6c, 0x10, 0x98, 0x67, 0xb1, 0x6d,
- 0x4d, 0x4d, 0x6d, 0x01,
-};
-static u32 sizeof_american_busy = sizeof(sample_american_busy);
-
-static u8 sample_special1[] = {
- 0x2a, 0x2c, 0xbc, 0x6c, 0xd6, 0x71, 0xbd, 0x0d,
- 0xd9, 0x80, 0xcc, 0x4c, 0x40, 0x39, 0x0d, 0xbd,
- 0x11, 0x86, 0xec, 0xbc, 0xec, 0x0e, 0x51, 0xbd,
- 0x8d, 0x89, 0x30, 0x4c, 0xcc, 0xe0, 0xe1, 0xcd,
- 0x4d, 0x31, 0x88, 0x8c, 0xbc, 0x50, 0x0f, 0xed,
- 0xbd, 0xed, 0x87, 0x10, 0xbc, 0x0c, 0x38, 0x41,
- 0x4d, 0xcd, 0x81, 0xd8, 0x0c, 0xbc, 0x70, 0xd7,
- 0x6d, 0xbd, 0x2d,
-};
-static u32 sizeof_special1 = sizeof(sample_special1);
-
-static u8 sample_special2[] = {
- 0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc,
- 0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d,
- 0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6,
- 0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0,
- 0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd,
- 0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc,
- 0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d,
- 0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6,
- 0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0,
- 0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd,
-};
-static u32 sizeof_special2 = sizeof(sample_special2);
-
-static u8 sample_special3[] = {
- 0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1,
- 0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c,
- 0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc,
- 0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7,
- 0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd,
- 0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1,
- 0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c,
- 0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc,
- 0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7,
- 0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd,
-};
-static u32 sizeof_special3 = sizeof(sample_special3);
-
-static u8 sample_silence[] = {
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
- 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
-};
-static u32 sizeof_silence = sizeof(sample_silence);
-
-struct tones_samples {
- u32 *len;
- u8 *data;
-};
-static struct
-tones_samples samples[] = {
- {&sizeof_german_all, sample_german_all},
- {&sizeof_german_old, sample_german_old},
- {&sizeof_american_dialtone, sample_american_dialtone},
- {&sizeof_american_ringing, sample_american_ringing},
- {&sizeof_american_busy, sample_american_busy},
- {&sizeof_special1, sample_special1},
- {&sizeof_special2, sample_special2},
- {&sizeof_special3, sample_special3},
- {NULL, NULL},
-};
-
-/***********************************
- * generate ulaw from alaw samples *
- ***********************************/
-
-void
-dsp_audio_generate_ulaw_samples(void)
-{
- int i, j;
-
- i = 0;
- while (samples[i].len) {
- j = 0;
- while (j < (*samples[i].len)) {
- samples[i].data[j] =
- dsp_audio_alaw_to_ulaw[samples[i].data[j]];
- j++;
- }
- i++;
- }
-}
-
-
-/****************************
- * tone sequence definition *
- ****************************/
-
-static struct pattern {
- int tone;
- u8 *data[10];
- u32 *siz[10];
- u32 seq[10];
-} pattern[] = {
- {TONE_GERMAN_DIALTONE,
- {DATA_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {1900, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_GERMAN_OLDDIALTONE,
- {DATA_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {1998, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_AMERICAN_DIALTONE,
- {DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_GERMAN_DIALPBX,
- {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL,
- NULL},
- {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL,
- NULL},
- {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
-
- {TONE_GERMAN_OLDDIALPBX,
- {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL,
- NULL},
- {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL,
- NULL},
- {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
-
- {TONE_AMERICAN_DIALPBX,
- {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL,
- NULL},
- {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL,
- NULL},
- {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
-
- {TONE_GERMAN_RINGING,
- {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_GERMAN_OLDRINGING,
- {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {8000, 40000, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_AMERICAN_RINGING,
- {DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_GERMAN_RINGPBX,
- {DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
- {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} },
-
- {TONE_GERMAN_OLDRINGPBX,
- {DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
- {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} },
-
- {TONE_AMERICAN_RINGPBX,
- {DATA_RI, DATA_S, DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
- {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} },
-
- {TONE_GERMAN_BUSY,
- {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_GERMAN_OLDBUSY,
- {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_AMERICAN_BUSY,
- {DATA_BU, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_BU, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_GERMAN_HANGUP,
- {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_GERMAN_OLDHANGUP,
- {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_AMERICAN_HANGUP,
- {DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_SPECIAL_INFO,
- {DATA_S1, DATA_S2, DATA_S3, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
- {2666, 2666, 2666, 8002, 0, 0, 0, 0, 0, 0} },
-
- {TONE_GERMAN_GASSENBESETZT,
- {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {2000, 2000, 0, 0, 0, 0, 0, 0, 0, 0} },
-
- {TONE_GERMAN_AUFSCHALTTON,
- {DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
- {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
- {1000, 5000, 1000, 17000, 0, 0, 0, 0, 0, 0} },
-
- {0,
- {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-};
-
-/******************
- * copy tone data *
- ******************/
-
-/* an sk_buff is generated from the number of samples needed.
- * the count will be changed and may begin from 0 each pattern period.
- * the clue is to precalculate the pointers and legths to use only one
- * memcpy per function call, or two memcpy if the tone sequence changes.
- *
- * pattern - the type of the pattern
- * count - the sample from the beginning of the pattern (phase)
- * len - the number of bytes
- *
- * return - the sk_buff with the sample
- *
- * if tones has finished (e.g. knocking tone), dsp->tones is turned off
- */
-void dsp_tone_copy(struct dsp *dsp, u8 *data, int len)
-{
- int index, count, start, num;
- struct pattern *pat;
- struct dsp_tone *tone = &dsp->tone;
-
- /* if we have no tone, we copy silence */
- if (!tone->tone) {
- memset(data, dsp_silence, len);
- return;
- }
-
- /* process pattern */
- pat = (struct pattern *)tone->pattern;
- /* points to the current pattern */
- index = tone->index; /* gives current sequence index */
- count = tone->count; /* gives current sample */
-
- /* copy sample */
- while (len) {
- /* find sample to start with */
- while (42) {
- /* wrap around */
- if (!pat->seq[index]) {
- count = 0;
- index = 0;
- }
- /* check if we are currently playing this tone */
- if (count < pat->seq[index])
- break;
- if (dsp_debug & DEBUG_DSP_TONE)
- printk(KERN_DEBUG "%s: reaching next sequence "
- "(index=%d)\n", __func__, index);
- count -= pat->seq[index];
- index++;
- }
- /* calculate start and number of samples */
- start = count % (*(pat->siz[index]));
- num = len;
- if (num + count > pat->seq[index])
- num = pat->seq[index] - count;
- if (num + start > (*(pat->siz[index])))
- num = (*(pat->siz[index])) - start;
- /* copy memory */
- memcpy(data, pat->data[index] + start, num);
- /* reduce length */
- data += num;
- count += num;
- len -= num;
- }
- tone->index = index;
- tone->count = count;
-
- /* return sk_buff */
- return;
-}
-
-
-/*******************************
- * send HW message to hfc card *
- *******************************/
-
-static void
-dsp_tone_hw_message(struct dsp *dsp, u8 *sample, int len)
-{
- struct sk_buff *nskb;
-
- /* unlocking is not required, because we don't expect a response */
- nskb = _alloc_mISDN_skb(PH_CONTROL_REQ,
- (len) ? HFC_SPL_LOOP_ON : HFC_SPL_LOOP_OFF, len, sample,
- GFP_ATOMIC);
- if (nskb) {
- if (dsp->ch.peer) {
- if (dsp->ch.recv(dsp->ch.peer, nskb))
- dev_kfree_skb(nskb);
- } else
- dev_kfree_skb(nskb);
- }
-}
-
-
-/*****************
- * timer expires *
- *****************/
-void
-dsp_tone_timeout(struct timer_list *t)
-{
- struct dsp *dsp = timer_container_of(dsp, t, tone.tl);
- struct dsp_tone *tone = &dsp->tone;
- struct pattern *pat = (struct pattern *)tone->pattern;
- int index = tone->index;
-
- if (!tone->tone)
- return;
-
- index++;
- if (!pat->seq[index])
- index = 0;
- tone->index = index;
-
- /* set next tone */
- if (pat->data[index] == DATA_S)
- dsp_tone_hw_message(dsp, NULL, 0);
- else
- dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index]));
- /* set timer */
- tone->tl.expires = jiffies + (pat->seq[index] * HZ) / 8000;
- add_timer(&tone->tl);
-}
-
-
-/********************
- * set/release tone *
- ********************/
-
-/*
- * tones are relaized by streaming or by special loop commands if supported
- * by hardware. when hardware is used, the patterns will be controlled by
- * timers.
- */
-int
-dsp_tone(struct dsp *dsp, int tone)
-{
- struct pattern *pat;
- int i;
- struct dsp_tone *tonet = &dsp->tone;
-
- tonet->software = 0;
- tonet->hardware = 0;
-
- /* we turn off the tone */
- if (!tone) {
- if (dsp->features.hfc_loops && timer_pending(&tonet->tl))
- timer_delete(&tonet->tl);
- if (dsp->features.hfc_loops)
- dsp_tone_hw_message(dsp, NULL, 0);
- tonet->tone = 0;
- return 0;
- }
-
- pat = NULL;
- i = 0;
- while (pattern[i].tone) {
- if (pattern[i].tone == tone) {
- pat = &pattern[i];
- break;
- }
- i++;
- }
- if (!pat) {
- printk(KERN_WARNING "dsp: given tone 0x%x is invalid\n", tone);
- return -EINVAL;
- }
- if (dsp_debug & DEBUG_DSP_TONE)
- printk(KERN_DEBUG "%s: now starting tone %d (index=%d)\n",
- __func__, tone, 0);
- tonet->tone = tone;
- tonet->pattern = pat;
- tonet->index = 0;
- tonet->count = 0;
-
- if (dsp->features.hfc_loops) {
- tonet->hardware = 1;
- /* set first tone */
- dsp_tone_hw_message(dsp, pat->data[0], *(pat->siz[0]));
- /* set timer */
- if (timer_pending(&tonet->tl))
- timer_delete(&tonet->tl);
- tonet->tl.expires = jiffies + (pat->seq[0] * HZ) / 8000;
- add_timer(&tonet->tl);
- } else {
- tonet->software = 1;
- }
-
- return 0;
-}
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * finite state machine implementation
- *
- * Author Karsten Keil <kkeil@novell.com>
- *
- * Thanks to Jan den Ouden
- * Fritz Elfert
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include "fsm.h"
-
-#define FSM_TIMER_DEBUG 0
-
-int
-mISDN_FsmNew(struct Fsm *fsm,
- struct FsmNode *fnlist, int fncount)
-{
- int i;
-
- fsm->jumpmatrix =
- kzalloc(array3_size(sizeof(FSMFNPTR), fsm->state_count,
- fsm->event_count),
- GFP_KERNEL);
- if (fsm->jumpmatrix == NULL)
- return -ENOMEM;
-
- for (i = 0; i < fncount; i++)
- if ((fnlist[i].state >= fsm->state_count) ||
- (fnlist[i].event >= fsm->event_count)) {
- printk(KERN_ERR
- "mISDN_FsmNew Error: %d st(%ld/%ld) ev(%ld/%ld)\n",
- i, (long)fnlist[i].state, (long)fsm->state_count,
- (long)fnlist[i].event, (long)fsm->event_count);
- } else
- fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
- fnlist[i].state] = (FSMFNPTR) fnlist[i].routine;
- return 0;
-}
-EXPORT_SYMBOL(mISDN_FsmNew);
-
-void
-mISDN_FsmFree(struct Fsm *fsm)
-{
- kfree((void *) fsm->jumpmatrix);
-}
-EXPORT_SYMBOL(mISDN_FsmFree);
-
-int
-mISDN_FsmEvent(struct FsmInst *fi, int event, void *arg)
-{
- FSMFNPTR r;
-
- if ((fi->state >= fi->fsm->state_count) ||
- (event >= fi->fsm->event_count)) {
- printk(KERN_ERR
- "mISDN_FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
- (long)fi->state, (long)fi->fsm->state_count, event,
- (long)fi->fsm->event_count);
- return 1;
- }
- r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
- if (r) {
- if (fi->debug)
- fi->printdebug(fi, "State %s Event %s",
- fi->fsm->strState[fi->state],
- fi->fsm->strEvent[event]);
- r(fi, event, arg);
- return 0;
- } else {
- if (fi->debug)
- fi->printdebug(fi, "State %s Event %s no action",
- fi->fsm->strState[fi->state],
- fi->fsm->strEvent[event]);
- return 1;
- }
-}
-EXPORT_SYMBOL(mISDN_FsmEvent);
-
-void
-mISDN_FsmChangeState(struct FsmInst *fi, int newstate)
-{
- fi->state = newstate;
- if (fi->debug)
- fi->printdebug(fi, "ChangeState %s",
- fi->fsm->strState[newstate]);
-}
-EXPORT_SYMBOL(mISDN_FsmChangeState);
-
-static void
-FsmExpireTimer(struct timer_list *t)
-{
- struct FsmTimer *ft = timer_container_of(ft, t, tl);
-#if FSM_TIMER_DEBUG
- if (ft->fi->debug)
- ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
-#endif
- mISDN_FsmEvent(ft->fi, ft->event, ft->arg);
-}
-
-void
-mISDN_FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
-{
- ft->fi = fi;
-#if FSM_TIMER_DEBUG
- if (ft->fi->debug)
- ft->fi->printdebug(ft->fi, "mISDN_FsmInitTimer %lx", (long) ft);
-#endif
- timer_setup(&ft->tl, FsmExpireTimer, 0);
-}
-EXPORT_SYMBOL(mISDN_FsmInitTimer);
-
-void
-mISDN_FsmDelTimer(struct FsmTimer *ft, int where)
-{
-#if FSM_TIMER_DEBUG
- if (ft->fi->debug)
- ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d",
- (long) ft, where);
-#endif
- timer_delete(&ft->tl);
-}
-EXPORT_SYMBOL(mISDN_FsmDelTimer);
-
-int
-mISDN_FsmAddTimer(struct FsmTimer *ft,
- int millisec, int event, void *arg, int where)
-{
-
-#if FSM_TIMER_DEBUG
- if (ft->fi->debug)
- ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d",
- (long) ft, millisec, where);
-#endif
-
- if (timer_pending(&ft->tl)) {
- if (ft->fi->debug) {
- printk(KERN_WARNING
- "mISDN_FsmAddTimer: timer already active!\n");
- ft->fi->printdebug(ft->fi,
- "mISDN_FsmAddTimer already active!");
- }
- return -1;
- }
- ft->event = event;
- ft->arg = arg;
- ft->tl.expires = jiffies + (millisec * HZ) / 1000;
- add_timer(&ft->tl);
- return 0;
-}
-EXPORT_SYMBOL(mISDN_FsmAddTimer);
-
-void
-mISDN_FsmRestartTimer(struct FsmTimer *ft,
- int millisec, int event, void *arg, int where)
-{
-
-#if FSM_TIMER_DEBUG
- if (ft->fi->debug)
- ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d",
- (long) ft, millisec, where);
-#endif
-
- if (timer_pending(&ft->tl))
- timer_delete(&ft->tl);
- ft->event = event;
- ft->arg = arg;
- ft->tl.expires = jiffies + (millisec * HZ) / 1000;
- add_timer(&ft->tl);
-}
-EXPORT_SYMBOL(mISDN_FsmRestartTimer);
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- *
- * Author Karsten Keil <kkeil@novell.com>
- *
- * Thanks to Jan den Ouden
- * Fritz Elfert
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#ifndef _MISDN_FSM_H
-#define _MISDN_FSM_H
-
-#include <linux/timer.h>
-
-/* Statemachine */
-
-struct FsmInst;
-
-typedef void (*FSMFNPTR)(struct FsmInst *, int, void *);
-
-struct Fsm {
- FSMFNPTR *jumpmatrix;
- int state_count, event_count;
- char **strEvent, **strState;
-};
-
-struct FsmInst {
- struct Fsm *fsm;
- int state;
- int debug;
- void *userdata;
- int userint;
- void (*printdebug) (struct FsmInst *, char *, ...);
-};
-
-struct FsmNode {
- int state, event;
- void (*routine) (struct FsmInst *, int, void *);
-};
-
-struct FsmTimer {
- struct FsmInst *fi;
- struct timer_list tl;
- int event;
- void *arg;
-};
-
-extern int mISDN_FsmNew(struct Fsm *, struct FsmNode *, int);
-extern void mISDN_FsmFree(struct Fsm *);
-extern int mISDN_FsmEvent(struct FsmInst *, int , void *);
-extern void mISDN_FsmChangeState(struct FsmInst *, int);
-extern void mISDN_FsmInitTimer(struct FsmInst *, struct FsmTimer *);
-extern int mISDN_FsmAddTimer(struct FsmTimer *, int, int, void *, int);
-extern void mISDN_FsmRestartTimer(struct FsmTimer *, int, int, void *, int);
-extern void mISDN_FsmDelTimer(struct FsmTimer *, int);
-
-#endif
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *
- * Author Karsten Keil <kkeil@novell.com>
- *
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#include <linux/gfp.h>
-#include <linux/module.h>
-#include <linux/mISDNhw.h>
-
-static void
-dchannel_bh(struct work_struct *ws)
-{
- struct dchannel *dch = container_of(ws, struct dchannel, workq);
- struct sk_buff *skb;
- int err;
-
- if (test_and_clear_bit(FLG_RECVQUEUE, &dch->Flags)) {
- while ((skb = skb_dequeue(&dch->rqueue))) {
- if (likely(dch->dev.D.peer)) {
- err = dch->dev.D.recv(dch->dev.D.peer, skb);
- if (err)
- dev_kfree_skb(skb);
- } else
- dev_kfree_skb(skb);
- }
- }
- if (test_and_clear_bit(FLG_PHCHANGE, &dch->Flags)) {
- if (dch->phfunc)
- dch->phfunc(dch);
- }
-}
-
-static void
-bchannel_bh(struct work_struct *ws)
-{
- struct bchannel *bch = container_of(ws, struct bchannel, workq);
- struct sk_buff *skb;
- int err;
-
- if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) {
- while ((skb = skb_dequeue(&bch->rqueue))) {
- bch->rcount--;
- if (likely(bch->ch.peer)) {
- err = bch->ch.recv(bch->ch.peer, skb);
- if (err)
- dev_kfree_skb(skb);
- } else
- dev_kfree_skb(skb);
- }
- }
-}
-
-int
-mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf)
-{
- test_and_set_bit(FLG_HDLC, &ch->Flags);
- ch->maxlen = maxlen;
- ch->hw = NULL;
- ch->rx_skb = NULL;
- ch->tx_skb = NULL;
- ch->tx_idx = 0;
- ch->phfunc = phf;
- skb_queue_head_init(&ch->squeue);
- skb_queue_head_init(&ch->rqueue);
- INIT_LIST_HEAD(&ch->dev.bchannels);
- INIT_WORK(&ch->workq, dchannel_bh);
- return 0;
-}
-EXPORT_SYMBOL(mISDN_initdchannel);
-
-int
-mISDN_initbchannel(struct bchannel *ch, unsigned short maxlen,
- unsigned short minlen)
-{
- ch->Flags = 0;
- ch->minlen = minlen;
- ch->next_minlen = minlen;
- ch->init_minlen = minlen;
- ch->maxlen = maxlen;
- ch->next_maxlen = maxlen;
- ch->init_maxlen = maxlen;
- ch->hw = NULL;
- ch->rx_skb = NULL;
- ch->tx_skb = NULL;
- ch->tx_idx = 0;
- skb_queue_head_init(&ch->rqueue);
- ch->rcount = 0;
- ch->next_skb = NULL;
- INIT_WORK(&ch->workq, bchannel_bh);
- return 0;
-}
-EXPORT_SYMBOL(mISDN_initbchannel);
-
-int
-mISDN_freedchannel(struct dchannel *ch)
-{
- if (ch->tx_skb) {
- dev_kfree_skb(ch->tx_skb);
- ch->tx_skb = NULL;
- }
- if (ch->rx_skb) {
- dev_kfree_skb(ch->rx_skb);
- ch->rx_skb = NULL;
- }
- skb_queue_purge(&ch->squeue);
- skb_queue_purge(&ch->rqueue);
- flush_work(&ch->workq);
- return 0;
-}
-EXPORT_SYMBOL(mISDN_freedchannel);
-
-void
-mISDN_clear_bchannel(struct bchannel *ch)
-{
- if (ch->tx_skb) {
- dev_kfree_skb(ch->tx_skb);
- ch->tx_skb = NULL;
- }
- ch->tx_idx = 0;
- if (ch->rx_skb) {
- dev_kfree_skb(ch->rx_skb);
- ch->rx_skb = NULL;
- }
- if (ch->next_skb) {
- dev_kfree_skb(ch->next_skb);
- ch->next_skb = NULL;
- }
- test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
- test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
- test_and_clear_bit(FLG_ACTIVE, &ch->Flags);
- test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags);
- test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags);
- test_and_clear_bit(FLG_RX_OFF, &ch->Flags);
- ch->dropcnt = 0;
- ch->minlen = ch->init_minlen;
- ch->next_minlen = ch->init_minlen;
- ch->maxlen = ch->init_maxlen;
- ch->next_maxlen = ch->init_maxlen;
- skb_queue_purge(&ch->rqueue);
- ch->rcount = 0;
-}
-EXPORT_SYMBOL(mISDN_clear_bchannel);
-
-void
-mISDN_freebchannel(struct bchannel *ch)
-{
- cancel_work_sync(&ch->workq);
- mISDN_clear_bchannel(ch);
-}
-EXPORT_SYMBOL(mISDN_freebchannel);
-
-int
-mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq)
-{
- int ret = 0;
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY |
- MISDN_CTRL_RX_OFF;
- break;
- case MISDN_CTRL_FILL_EMPTY:
- if (cq->p1) {
- memset(bch->fill, cq->p2 & 0xff, MISDN_BCH_FILL_SIZE);
- test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
- } else {
- test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
- }
- break;
- case MISDN_CTRL_RX_OFF:
- /* read back dropped byte count */
- cq->p2 = bch->dropcnt;
- if (cq->p1)
- test_and_set_bit(FLG_RX_OFF, &bch->Flags);
- else
- test_and_clear_bit(FLG_RX_OFF, &bch->Flags);
- bch->dropcnt = 0;
- break;
- case MISDN_CTRL_RX_BUFFER:
- if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE)
- bch->next_maxlen = cq->p2;
- if (cq->p1 > MISDN_CTRL_RX_SIZE_IGNORE)
- bch->next_minlen = cq->p1;
- /* we return the old values */
- cq->p1 = bch->minlen;
- cq->p2 = bch->maxlen;
- break;
- default:
- pr_info("mISDN unhandled control %x operation\n", cq->op);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-EXPORT_SYMBOL(mISDN_ctrl_bchannel);
-
-static inline u_int
-get_sapi_tei(u_char *p)
-{
- u_int sapi, tei;
-
- sapi = *p >> 2;
- tei = p[1] >> 1;
- return sapi | (tei << 8);
-}
-
-void
-recv_Dchannel(struct dchannel *dch)
-{
- struct mISDNhead *hh;
-
- if (dch->rx_skb->len < 2) { /* at least 2 for sapi / tei */
- dev_kfree_skb(dch->rx_skb);
- dch->rx_skb = NULL;
- return;
- }
- hh = mISDN_HEAD_P(dch->rx_skb);
- hh->prim = PH_DATA_IND;
- hh->id = get_sapi_tei(dch->rx_skb->data);
- skb_queue_tail(&dch->rqueue, dch->rx_skb);
- dch->rx_skb = NULL;
- schedule_event(dch, FLG_RECVQUEUE);
-}
-EXPORT_SYMBOL(recv_Dchannel);
-
-void
-recv_Echannel(struct dchannel *ech, struct dchannel *dch)
-{
- struct mISDNhead *hh;
-
- if (ech->rx_skb->len < 2) { /* at least 2 for sapi / tei */
- dev_kfree_skb(ech->rx_skb);
- ech->rx_skb = NULL;
- return;
- }
- hh = mISDN_HEAD_P(ech->rx_skb);
- hh->prim = PH_DATA_E_IND;
- hh->id = get_sapi_tei(ech->rx_skb->data);
- skb_queue_tail(&dch->rqueue, ech->rx_skb);
- ech->rx_skb = NULL;
- schedule_event(dch, FLG_RECVQUEUE);
-}
-EXPORT_SYMBOL(recv_Echannel);
-
-void
-recv_Bchannel(struct bchannel *bch, unsigned int id, bool force)
-{
- struct mISDNhead *hh;
-
- /* if allocation did fail upper functions still may call us */
- if (unlikely(!bch->rx_skb))
- return;
- if (unlikely(!bch->rx_skb->len)) {
- /* we have no data to send - this may happen after recovery
- * from overflow or too small allocation.
- * We need to free the buffer here */
- dev_kfree_skb(bch->rx_skb);
- bch->rx_skb = NULL;
- } else {
- if (test_bit(FLG_TRANSPARENT, &bch->Flags) &&
- (bch->rx_skb->len < bch->minlen) && !force)
- return;
- hh = mISDN_HEAD_P(bch->rx_skb);
- hh->prim = PH_DATA_IND;
- hh->id = id;
- if (bch->rcount >= 64) {
- printk(KERN_WARNING
- "B%d receive queue overflow - flushing!\n",
- bch->nr);
- skb_queue_purge(&bch->rqueue);
- }
- bch->rcount++;
- skb_queue_tail(&bch->rqueue, bch->rx_skb);
- bch->rx_skb = NULL;
- schedule_event(bch, FLG_RECVQUEUE);
- }
-}
-EXPORT_SYMBOL(recv_Bchannel);
-
-void
-recv_Dchannel_skb(struct dchannel *dch, struct sk_buff *skb)
-{
- skb_queue_tail(&dch->rqueue, skb);
- schedule_event(dch, FLG_RECVQUEUE);
-}
-EXPORT_SYMBOL(recv_Dchannel_skb);
-
-void
-recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb)
-{
- if (bch->rcount >= 64) {
- printk(KERN_WARNING "B-channel %p receive queue overflow, "
- "flushing!\n", bch);
- skb_queue_purge(&bch->rqueue);
- bch->rcount = 0;
- }
- bch->rcount++;
- skb_queue_tail(&bch->rqueue, skb);
- schedule_event(bch, FLG_RECVQUEUE);
-}
-EXPORT_SYMBOL(recv_Bchannel_skb);
-
-static void
-confirm_Dsend(struct dchannel *dch)
-{
- struct sk_buff *skb;
-
- skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(dch->tx_skb),
- 0, NULL, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_ERR "%s: no skb id %x\n", __func__,
- mISDN_HEAD_ID(dch->tx_skb));
- return;
- }
- skb_queue_tail(&dch->rqueue, skb);
- schedule_event(dch, FLG_RECVQUEUE);
-}
-
-int
-get_next_dframe(struct dchannel *dch)
-{
- dch->tx_idx = 0;
- dch->tx_skb = skb_dequeue(&dch->squeue);
- if (dch->tx_skb) {
- confirm_Dsend(dch);
- return 1;
- }
- dch->tx_skb = NULL;
- test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
- return 0;
-}
-EXPORT_SYMBOL(get_next_dframe);
-
-static void
-confirm_Bsend(struct bchannel *bch)
-{
- struct sk_buff *skb;
-
- if (bch->rcount >= 64) {
- printk(KERN_WARNING "B-channel %p receive queue overflow, "
- "flushing!\n", bch);
- skb_queue_purge(&bch->rqueue);
- bch->rcount = 0;
- }
- skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb),
- 0, NULL, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_ERR "%s: no skb id %x\n", __func__,
- mISDN_HEAD_ID(bch->tx_skb));
- return;
- }
- bch->rcount++;
- skb_queue_tail(&bch->rqueue, skb);
- schedule_event(bch, FLG_RECVQUEUE);
-}
-
-int
-get_next_bframe(struct bchannel *bch)
-{
- bch->tx_idx = 0;
- if (test_bit(FLG_TX_NEXT, &bch->Flags)) {
- bch->tx_skb = bch->next_skb;
- if (bch->tx_skb) {
- bch->next_skb = NULL;
- test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
- /* confirm imediately to allow next data */
- confirm_Bsend(bch);
- return 1;
- } else {
- test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
- printk(KERN_WARNING "B TX_NEXT without skb\n");
- }
- }
- bch->tx_skb = NULL;
- test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
- return 0;
-}
-EXPORT_SYMBOL(get_next_bframe);
-
-void
-queue_ch_frame(struct mISDNchannel *ch, u_int pr, int id, struct sk_buff *skb)
-{
- struct mISDNhead *hh;
-
- if (!skb) {
- _queue_data(ch, pr, id, 0, NULL, GFP_ATOMIC);
- } else {
- if (ch->peer) {
- hh = mISDN_HEAD_P(skb);
- hh->prim = pr;
- hh->id = id;
- if (!ch->recv(ch->peer, skb))
- return;
- }
- dev_kfree_skb(skb);
- }
-}
-EXPORT_SYMBOL(queue_ch_frame);
-
-int
-dchannel_senddata(struct dchannel *ch, struct sk_buff *skb)
-{
- /* check oversize */
- if (skb->len <= 0) {
- printk(KERN_WARNING "%s: skb too small\n", __func__);
- return -EINVAL;
- }
- if (skb->len > ch->maxlen) {
- printk(KERN_WARNING "%s: skb too large(%d/%d)\n",
- __func__, skb->len, ch->maxlen);
- return -EINVAL;
- }
- /* HW lock must be obtained */
- if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) {
- skb_queue_tail(&ch->squeue, skb);
- return 0;
- } else {
- /* write to fifo */
- ch->tx_skb = skb;
- ch->tx_idx = 0;
- return 1;
- }
-}
-EXPORT_SYMBOL(dchannel_senddata);
-
-int
-bchannel_senddata(struct bchannel *ch, struct sk_buff *skb)
-{
-
- /* check oversize */
- if (skb->len <= 0) {
- printk(KERN_WARNING "%s: skb too small\n", __func__);
- return -EINVAL;
- }
- if (skb->len > ch->maxlen) {
- printk(KERN_WARNING "%s: skb too large(%d/%d)\n",
- __func__, skb->len, ch->maxlen);
- return -EINVAL;
- }
- /* HW lock must be obtained */
- /* check for pending next_skb */
- if (ch->next_skb) {
- printk(KERN_WARNING
- "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n",
- __func__, skb->len, ch->next_skb->len);
- return -EBUSY;
- }
- if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) {
- test_and_set_bit(FLG_TX_NEXT, &ch->Flags);
- ch->next_skb = skb;
- return 0;
- } else {
- /* write to fifo */
- ch->tx_skb = skb;
- ch->tx_idx = 0;
- confirm_Bsend(ch);
- return 1;
- }
-}
-EXPORT_SYMBOL(bchannel_senddata);
-
-/* The function allocates a new receive skb on demand with a size for the
- * requirements of the current protocol. It returns the tailroom of the
- * receive skb or an error.
- */
-int
-bchannel_get_rxbuf(struct bchannel *bch, int reqlen)
-{
- int len;
-
- if (bch->rx_skb) {
- len = skb_tailroom(bch->rx_skb);
- if (len < reqlen) {
- pr_warn("B%d no space for %d (only %d) bytes\n",
- bch->nr, reqlen, len);
- if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
- /* send what we have now and try a new buffer */
- recv_Bchannel(bch, 0, true);
- } else {
- /* on HDLC we have to drop too big frames */
- return -EMSGSIZE;
- }
- } else {
- return len;
- }
- }
- /* update current min/max length first */
- if (unlikely(bch->maxlen != bch->next_maxlen))
- bch->maxlen = bch->next_maxlen;
- if (unlikely(bch->minlen != bch->next_minlen))
- bch->minlen = bch->next_minlen;
- if (unlikely(reqlen > bch->maxlen))
- return -EMSGSIZE;
- if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
- if (reqlen >= bch->minlen) {
- len = reqlen;
- } else {
- len = 2 * bch->minlen;
- if (len > bch->maxlen)
- len = bch->maxlen;
- }
- } else {
- /* with HDLC we do not know the length yet */
- len = bch->maxlen;
- }
- bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC);
- if (!bch->rx_skb) {
- pr_warn("B%d receive no memory for %d bytes\n", bch->nr, len);
- len = -ENOMEM;
- }
- return len;
-}
-EXPORT_SYMBOL(bchannel_get_rxbuf);
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * see notice in l1oip.c
- */
-
-/* debugging */
-#define DEBUG_L1OIP_INIT 0x00010000
-#define DEBUG_L1OIP_SOCKET 0x00020000
-#define DEBUG_L1OIP_MGR 0x00040000
-#define DEBUG_L1OIP_MSG 0x00080000
-
-/* enable to disorder received bchannels by sequence 2143658798... */
-/*
- #define REORDER_DEBUG
-*/
-
-/* frames */
-#define L1OIP_MAX_LEN 2048 /* max packet size form l2 */
-#define L1OIP_MAX_PERFRAME 1400 /* max data size in one frame */
-
-
-/* timers */
-#define L1OIP_KEEPALIVE 15
-#define L1OIP_TIMEOUT 65
-
-
-/* socket */
-#define L1OIP_DEFAULTPORT 931
-
-
-/* channel structure */
-struct l1oip_chan {
- struct dchannel *dch;
- struct bchannel *bch;
- u32 tx_counter; /* counts xmit bytes/packets */
- u32 rx_counter; /* counts recv bytes/packets */
- u32 codecstate; /* used by codec to save data */
-#ifdef REORDER_DEBUG
- int disorder_flag;
- struct sk_buff *disorder_skb;
- u32 disorder_cnt;
-#endif
-};
-
-
-/* card structure */
-struct l1oip {
- struct list_head list;
-
- /* card */
- int registered; /* if registered with mISDN */
- char name[MISDN_MAX_IDLEN];
- int idx; /* card index */
- int pri; /* 1=pri, 0=bri */
- int d_idx; /* current dchannel number */
- int b_num; /* number of bchannels */
- u32 id; /* id of connection */
- int ondemand; /* if transmis. is on demand */
- int bundle; /* bundle channels in one frm */
- int codec; /* codec to use for transmis. */
- int limit; /* limit number of bchannels */
- bool shutdown; /* if card is released */
-
- /* timer */
- struct timer_list keep_tl;
- struct timer_list timeout_tl;
- int timeout_on;
- struct work_struct workq;
-
- /* socket */
- struct socket *socket; /* if set, socket is created */
- struct completion socket_complete;/* completion of sock thread */
- struct task_struct *socket_thread;
- spinlock_t socket_lock; /* access sock outside thread */
- u32 remoteip; /* if all set, ip is assigned */
- u16 localport; /* must always be set */
- u16 remoteport; /* must always be set */
- struct sockaddr_in sin_local; /* local socket name */
- struct sockaddr_in sin_remote; /* remote socket name */
- struct msghdr sendmsg; /* ip message to send */
- struct kvec sendiov; /* iov for message */
-
- /* frame */
- struct l1oip_chan chan[128]; /* channel instances */
-};
-
-extern int l1oip_law_to_4bit(u8 *data, int len, u8 *result, u32 *state);
-extern int l1oip_4bit_to_law(u8 *data, int len, u8 *result);
-extern int l1oip_alaw_to_ulaw(u8 *data, int len, u8 *result);
-extern int l1oip_ulaw_to_alaw(u8 *data, int len, u8 *result);
-extern void l1oip_4bit_free(void);
-extern int l1oip_4bit_alloc(int ulaw);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
-
- * l1oip_codec.c generic codec using lookup table
- * -> conversion from a-Law to u-Law
- * -> conversion from u-Law to a-Law
- * -> compression by reducing the number of sample resolution to 4
- *
- * NOTE: It is not compatible with any standard codec like ADPCM.
- *
- * Author Andreas Eversberg (jolly@eversberg.eu)
- *
-
- */
-
-/*
-
- How the codec works:
- --------------------
-
- The volume is increased to increase the dynamic range of the audio signal.
- Each sample is converted to a-LAW with only 16 steps of level resolution.
- A pair of two samples are stored in one byte.
-
- The first byte is stored in the upper bits, the second byte is stored in the
- lower bits.
-
- To speed up compression and decompression, two lookup tables are formed:
-
- - 16 bits index for two samples (law encoded) with 8 bit compressed result.
- - 8 bits index for one compressed data with 16 bits decompressed result.
-
- NOTE: The bytes are handled as they are law-encoded.
-
-*/
-
-#include <linux/vmalloc.h>
-#include <linux/mISDNif.h>
-#include <linux/in.h>
-#include "core.h"
-#include "l1oip.h"
-
-/* definitions of codec. don't use calculations, code may run slower. */
-
-static u8 *table_com;
-static u16 *table_dec;
-
-
-/* alaw -> ulaw */
-static u8 alaw_to_ulaw[256] =
-{
- 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 u8 ulaw_to_alaw[256] =
-{
- 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
-};
-
-/* alaw -> 4bit compression */
-static u8 alaw_to_4bit[256] = {
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0d, 0x02,
- 0x0e, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04,
- 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x01, 0x0a, 0x05,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x09, 0x07, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04,
- 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03,
- 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04,
-};
-
-/* 4bit -> alaw decompression */
-static u8 _4bit_to_alaw[16] = {
- 0x5d, 0x51, 0xd9, 0xd7, 0x5f, 0x53, 0xa3, 0x4b,
- 0x2a, 0x3a, 0x22, 0x2e, 0x26, 0x56, 0x20, 0x2c,
-};
-
-/* ulaw -> 4bit compression */
-static u8 ulaw_to_4bit[256] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08,
- 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
- 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
- 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
- 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
- 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
- 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
- 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
- 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b,
- 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
- 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a,
- 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
- 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
- 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
- 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
-};
-
-/* 4bit -> ulaw decompression */
-static u8 _4bit_to_ulaw[16] = {
- 0x11, 0x21, 0x31, 0x40, 0x4e, 0x5c, 0x68, 0x71,
- 0xfe, 0xef, 0xe7, 0xdb, 0xcd, 0xbf, 0xaf, 0x9f,
-};
-
-
-/*
- * Compresses data to the result buffer
- * The result size must be at least half of the input buffer.
- * The number of samples also must be even!
- */
-int
-l1oip_law_to_4bit(u8 *data, int len, u8 *result, u32 *state)
-{
- int ii, i = 0, o = 0;
-
- if (!len)
- return 0;
-
- /* send saved byte and first input byte */
- if (*state) {
- *result++ = table_com[(((*state) << 8) & 0xff00) | (*data++)];
- len--;
- o++;
- }
-
- ii = len >> 1;
-
- while (i < ii) {
- *result++ = table_com[(data[0]<<8) | (data[1])];
- data += 2;
- i++;
- o++;
- }
-
- /* if len has an odd number, we save byte for next call */
- if (len & 1)
- *state = 0x100 + *data;
- else
- *state = 0;
-
- return o;
-}
-
-/* Decompress data to the result buffer
- * The result size must be the number of sample in packet. (2 * input data)
- * The number of samples in the result are even!
- */
-int
-l1oip_4bit_to_law(u8 *data, int len, u8 *result)
-{
- int i = 0;
- u16 r;
-
- while (i < len) {
- r = table_dec[*data++];
- *result++ = r >> 8;
- *result++ = r;
- i++;
- }
-
- return len << 1;
-}
-
-
-/*
- * law conversion
- */
-int
-l1oip_alaw_to_ulaw(u8 *data, int len, u8 *result)
-{
- int i = 0;
-
- while (i < len) {
- *result++ = alaw_to_ulaw[*data++];
- i++;
- }
-
- return len;
-}
-
-int
-l1oip_ulaw_to_alaw(u8 *data, int len, u8 *result)
-{
- int i = 0;
-
- while (i < len) {
- *result++ = ulaw_to_alaw[*data++];
- i++;
- }
-
- return len;
-}
-
-
-/*
- * generate/free compression and decompression table
- */
-void
-l1oip_4bit_free(void)
-{
- vfree(table_dec);
- vfree(table_com);
- table_com = NULL;
- table_dec = NULL;
-}
-
-int
-l1oip_4bit_alloc(int ulaw)
-{
- int i1, i2, c, sample;
-
- /* in case, it is called again */
- if (table_dec)
- return 0;
-
- /* alloc conversion tables */
- table_com = vzalloc(65536);
- table_dec = vzalloc(512);
- if (!table_com || !table_dec) {
- l1oip_4bit_free();
- return -ENOMEM;
- }
- /* generate compression table */
- i1 = 0;
- while (i1 < 256) {
- if (ulaw)
- c = ulaw_to_4bit[i1];
- else
- c = alaw_to_4bit[i1];
- i2 = 0;
- while (i2 < 256) {
- table_com[(i1 << 8) | i2] |= (c << 4);
- table_com[(i2 << 8) | i1] |= c;
- i2++;
- }
- i1++;
- }
-
- /* generate decompression table */
- i1 = 0;
- while (i1 < 16) {
- if (ulaw)
- sample = _4bit_to_ulaw[i1];
- else
- sample = _4bit_to_alaw[i1];
- i2 = 0;
- while (i2 < 16) {
- table_dec[(i1 << 4) | i2] |= (sample << 8);
- table_dec[(i2 << 4) | i1] |= sample;
- i2++;
- }
- i1++;
- }
-
- return 0;
-}
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
-
- * l1oip.c low level driver for tunneling layer 1 over IP
- *
- * NOTE: It is not compatible with TDMoIP nor "ISDN over IP".
- *
- * Author Andreas Eversberg (jolly@eversberg.eu)
- */
-
-/* module parameters:
- * type:
- Value 1 = BRI
- Value 2 = PRI
- Value 3 = BRI (multi channel frame, not supported yet)
- Value 4 = PRI (multi channel frame, not supported yet)
- A multi channel frame reduces overhead to a single frame for all
- b-channels, but increases delay.
- (NOTE: Multi channel frames are not implemented yet.)
-
- * codec:
- Value 0 = transparent (default)
- Value 1 = transfer ALAW
- Value 2 = transfer ULAW
- Value 3 = transfer generic 4 bit compression.
-
- * ulaw:
- 0 = we use a-Law (default)
- 1 = we use u-Law
-
- * limit:
- limitation of B-channels to control bandwidth (1...126)
- BRI: 1 or 2
- PRI: 1-30, 31-126 (126, because dchannel ist not counted here)
- Also limited ressources are used for stack, resulting in less channels.
- It is possible to have more channels than 30 in PRI mode, this must
- be supported by the application.
-
- * ip:
- byte representation of remote ip address (127.0.0.1 -> 127,0,0,1)
- If not given or four 0, no remote address is set.
- For multiple interfaces, concat ip addresses. (127,0,0,1,127,0,0,1)
-
- * port:
- port number (local interface)
- If not given or 0, port 931 is used for fist instance, 932 for next...
- For multiple interfaces, different ports must be given.
-
- * remoteport:
- port number (remote interface)
- If not given or 0, remote port equals local port
- For multiple interfaces on equal sites, different ports must be given.
-
- * ondemand:
- 0 = fixed (always transmit packets, even when remote side timed out)
- 1 = on demand (only transmit packets, when remote side is detected)
- the default is 0
- NOTE: ID must also be set for on demand.
-
- * id:
- optional value to identify frames. This value must be equal on both
- peers and should be random. If omitted or 0, no ID is transmitted.
-
- * debug:
- NOTE: only one debug value must be given for all cards
- enable debugging (see l1oip.h for debug options)
-
-
- Special mISDN controls:
-
- op = MISDN_CTRL_SETPEER*
- p1 = bytes 0-3 : remote IP address in network order (left element first)
- p2 = bytes 1-2 : remote port in network order (high byte first)
- optional:
- p2 = bytes 3-4 : local port in network order (high byte first)
-
- op = MISDN_CTRL_UNSETPEER*
-
- * Use l1oipctrl for comfortable setting or removing ip address.
- (Layer 1 Over IP CTRL)
-
-
- L1oIP-Protocol
- --------------
-
- Frame Header:
-
- 7 6 5 4 3 2 1 0
- +---------------+
- |Ver|T|I|Coding |
- +---------------+
- | ID byte 3 * |
- +---------------+
- | ID byte 2 * |
- +---------------+
- | ID byte 1 * |
- +---------------+
- | ID byte 0 * |
- +---------------+
- |M| Channel |
- +---------------+
- | Length * |
- +---------------+
- | Time Base MSB |
- +---------------+
- | Time Base LSB |
- +---------------+
- | Data.... |
-
- ...
-
- | |
- +---------------+
- |M| Channel |
- +---------------+
- | Length * |
- +---------------+
- | Time Base MSB |
- +---------------+
- | Time Base LSB |
- +---------------+
- | Data.... |
-
- ...
-
-
- * Only included in some cases.
-
- - Ver = Version
- If version is missmatch, the frame must be ignored.
-
- - T = Type of interface
- Must be 0 for S0 or 1 for E1.
-
- - I = Id present
- If bit is set, four ID bytes are included in frame.
-
- - ID = Connection ID
- Additional ID to prevent Denial of Service attacs. Also it prevents hijacking
- connections with dynamic IP. The ID should be random and must not be 0.
-
- - Coding = Type of codec
- Must be 0 for no transcoding. Also for D-channel and other HDLC frames.
- 1 and 2 are reserved for explicitly use of a-LAW or u-LAW codec.
- 3 is used for generic table compressor.
-
- - M = More channels to come. If this flag is 1, the following byte contains
- the length of the channel data. After the data block, the next channel will
- be defined. The flag for the last channel block (or if only one channel is
- transmitted), must be 0 and no length is given.
-
- - Channel = Channel number
- 0 reserved
- 1-3 channel data for S0 (3 is D-channel)
- 1-31 channel data for E1 (16 is D-channel)
- 32-127 channel data for extended E1 (16 is D-channel)
-
- - The length is used if the M-flag is 1. It is used to find the next channel
- inside frame.
- NOTE: A value of 0 equals 256 bytes of data.
- -> For larger data blocks, a single frame must be used.
- -> For larger streams, a single frame or multiple blocks with same channel ID
- must be used.
-
- - Time Base = Timestamp of first sample in frame
- The "Time Base" is used to rearange packets and to detect packet loss.
- The 16 bits are sent in network order (MSB first) and count 1/8000 th of a
- second. This causes a wrap around each 8,192 seconds. There is no requirement
- for the initial "Time Base", but 0 should be used for the first packet.
- In case of HDLC data, this timestamp counts the packet or byte number.
-
-
- Two Timers:
-
- After initialisation, a timer of 15 seconds is started. Whenever a packet is
- transmitted, the timer is reset to 15 seconds again. If the timer expires, an
- empty packet is transmitted. This keep the connection alive.
-
- When a valid packet is received, a timer 65 seconds is started. The interface
- become ACTIVE. If the timer expires, the interface becomes INACTIVE.
-
-
- Dynamic IP handling:
-
- To allow dynamic IP, the ID must be non 0. In this case, any packet with the
- correct port number and ID will be accepted. If the remote side changes its IP
- the new IP is used for all transmitted packets until it changes again.
-
-
- On Demand:
-
- If the ondemand parameter is given, the remote IP is set to 0 on timeout.
- This will stop keepalive traffic to remote. If the remote is online again,
- traffic will continue to the remote address. This is useful for road warriors.
- This feature only works with ID set, otherwhise it is highly unsecure.
-
-
- Socket and Thread
- -----------------
-
- The complete socket opening and closing is done by a thread.
- When the thread opened a socket, the hc->socket descriptor is set. Whenever a
- packet shall be sent to the socket, the hc->socket must be checked whether not
- NULL. To prevent change in socket descriptor, the hc->socket_lock must be used.
- To change the socket, a recall of l1oip_socket_open() will safely kill the
- socket process and create a new one.
-
-*/
-
-#define L1OIP_VERSION 0 /* 0...3 */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mISDNif.h>
-#include <linux/mISDNhw.h>
-#include <linux/mISDNdsp.h>
-#include <linux/init.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/workqueue.h>
-#include <linux/kthread.h>
-#include <linux/slab.h>
-#include <linux/sched/signal.h>
-
-#include <net/sock.h>
-#include "core.h"
-#include "l1oip.h"
-
-static const char *l1oip_revision = "2.00";
-
-static int l1oip_cnt;
-static DEFINE_SPINLOCK(l1oip_lock);
-static LIST_HEAD(l1oip_ilist);
-
-#define MAX_CARDS 16
-static u_int type[MAX_CARDS];
-static u_int codec[MAX_CARDS];
-static u_int ip[MAX_CARDS * 4];
-static u_int port[MAX_CARDS];
-static u_int remoteport[MAX_CARDS];
-static u_int ondemand[MAX_CARDS];
-static u_int limit[MAX_CARDS];
-static u_int id[MAX_CARDS];
-static int debug;
-static int ulaw;
-
-MODULE_AUTHOR("Andreas Eversberg");
-MODULE_DESCRIPTION("mISDN driver for tunneling layer 1 over IP");
-MODULE_LICENSE("GPL");
-module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(codec, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(ip, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(remoteport, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(ondemand, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(limit, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(id, uint, NULL, S_IRUGO | S_IWUSR);
-module_param(ulaw, uint, S_IRUGO | S_IWUSR);
-module_param(debug, uint, S_IRUGO | S_IWUSR);
-
-/*
- * send a frame via socket, if open and restart timer
- */
-static int
-l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask,
- u16 timebase, u8 *buf, int len)
-{
- u8 *p;
- u8 frame[MAX_DFRAME_LEN_L1 + 32];
- struct socket *socket = NULL;
-
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: sending data to socket (len = %d)\n",
- __func__, len);
-
- p = frame;
-
- /* restart timer */
- if (time_before(hc->keep_tl.expires, jiffies + 5 * HZ) && !hc->shutdown)
- mod_timer(&hc->keep_tl, jiffies + L1OIP_KEEPALIVE * HZ);
- else
- hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE * HZ;
-
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: resetting timer\n", __func__);
-
- /* drop if we have no remote ip or port */
- if (!hc->sin_remote.sin_addr.s_addr || !hc->sin_remote.sin_port) {
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: dropping frame, because remote "
- "IP is not set.\n", __func__);
- return len;
- }
-
- /* assemble frame */
- *p++ = (L1OIP_VERSION << 6) /* version and coding */
- | (hc->pri ? 0x20 : 0x00) /* type */
- | (hc->id ? 0x10 : 0x00) /* id */
- | localcodec;
- if (hc->id) {
- *p++ = hc->id >> 24; /* id */
- *p++ = hc->id >> 16;
- *p++ = hc->id >> 8;
- *p++ = hc->id;
- }
- *p++ = 0x00 + channel; /* m-flag, channel */
- *p++ = timebase >> 8; /* time base */
- *p++ = timebase;
-
- if (buf && len) { /* add data to frame */
- if (localcodec == 1 && ulaw)
- l1oip_ulaw_to_alaw(buf, len, p);
- else if (localcodec == 2 && !ulaw)
- l1oip_alaw_to_ulaw(buf, len, p);
- else if (localcodec == 3)
- len = l1oip_law_to_4bit(buf, len, p,
- &hc->chan[channel].codecstate);
- else
- memcpy(p, buf, len);
- }
- len += p - frame;
-
- /* check for socket in safe condition */
- spin_lock(&hc->socket_lock);
- if (!hc->socket) {
- spin_unlock(&hc->socket_lock);
- return 0;
- }
- /* seize socket */
- socket = hc->socket;
- hc->socket = NULL;
- spin_unlock(&hc->socket_lock);
- /* send packet */
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: sending packet to socket (len "
- "= %d)\n", __func__, len);
- hc->sendiov.iov_base = frame;
- hc->sendiov.iov_len = len;
- len = kernel_sendmsg(socket, &hc->sendmsg, &hc->sendiov, 1, len);
- /* give socket back */
- hc->socket = socket; /* no locking required */
-
- return len;
-}
-
-
-/*
- * receive channel data from socket
- */
-static void
-l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase,
- u8 *buf, int len)
-{
- struct sk_buff *nskb;
- struct bchannel *bch;
- struct dchannel *dch;
- u8 *p;
- u32 rx_counter;
-
- if (len == 0) {
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: received empty keepalive data, "
- "ignoring\n", __func__);
- return;
- }
-
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: received data, sending to mISDN (%d)\n",
- __func__, len);
-
- if (channel < 1 || channel > 127) {
- printk(KERN_WARNING "%s: packet error - channel %d out of "
- "range\n", __func__, channel);
- return;
- }
- dch = hc->chan[channel].dch;
- bch = hc->chan[channel].bch;
- if (!dch && !bch) {
- printk(KERN_WARNING "%s: packet error - channel %d not in "
- "stack\n", __func__, channel);
- return;
- }
-
- /* prepare message */
- nskb = mI_alloc_skb((remotecodec == 3) ? (len << 1) : len, GFP_ATOMIC);
- if (!nskb) {
- printk(KERN_ERR "%s: No mem for skb.\n", __func__);
- return;
- }
- p = skb_put(nskb, (remotecodec == 3) ? (len << 1) : len);
-
- if (remotecodec == 1 && ulaw)
- l1oip_alaw_to_ulaw(buf, len, p);
- else if (remotecodec == 2 && !ulaw)
- l1oip_ulaw_to_alaw(buf, len, p);
- else if (remotecodec == 3)
- len = l1oip_4bit_to_law(buf, len, p);
- else
- memcpy(p, buf, len);
-
- /* send message up */
- if (dch && len >= 2) {
- dch->rx_skb = nskb;
- recv_Dchannel(dch);
- }
- if (bch) {
- /* expand 16 bit sequence number to 32 bit sequence number */
- rx_counter = hc->chan[channel].rx_counter;
- if (((s16)(timebase - rx_counter)) >= 0) {
- /* time has changed forward */
- if (timebase >= (rx_counter & 0xffff))
- rx_counter =
- (rx_counter & 0xffff0000) | timebase;
- else
- rx_counter = ((rx_counter & 0xffff0000) + 0x10000)
- | timebase;
- } else {
- /* time has changed backwards */
- if (timebase < (rx_counter & 0xffff))
- rx_counter =
- (rx_counter & 0xffff0000) | timebase;
- else
- rx_counter = ((rx_counter & 0xffff0000) - 0x10000)
- | timebase;
- }
- hc->chan[channel].rx_counter = rx_counter;
-
-#ifdef REORDER_DEBUG
- if (hc->chan[channel].disorder_flag) {
- swap(hc->chan[channel].disorder_skb, nskb);
- swap(hc->chan[channel].disorder_cnt, rx_counter);
- }
- hc->chan[channel].disorder_flag ^= 1;
- if (nskb)
-#endif
- queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb);
- }
-}
-
-
-/*
- * parse frame and extract channel data
- */
-static void
-l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len)
-{
- u32 packet_id;
- u8 channel;
- u8 remotecodec;
- u16 timebase;
- int m, mlen;
- int len_start = len; /* initial frame length */
- struct dchannel *dch = hc->chan[hc->d_idx].dch;
-
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: received frame, parsing... (%d)\n",
- __func__, len);
-
- /* check length */
- if (len < 1 + 1 + 2) {
- printk(KERN_WARNING "%s: packet error - length %d below "
- "4 bytes\n", __func__, len);
- return;
- }
-
- /* check version */
- if (((*buf) >> 6) != L1OIP_VERSION) {
- printk(KERN_WARNING "%s: packet error - unknown version %d\n",
- __func__, buf[0]>>6);
- return;
- }
-
- /* check type */
- if (((*buf) & 0x20) && !hc->pri) {
- printk(KERN_WARNING "%s: packet error - received E1 packet "
- "on S0 interface\n", __func__);
- return;
- }
- if (!((*buf) & 0x20) && hc->pri) {
- printk(KERN_WARNING "%s: packet error - received S0 packet "
- "on E1 interface\n", __func__);
- return;
- }
-
- /* get id flag */
- packet_id = (*buf >> 4) & 1;
-
- /* check coding */
- remotecodec = (*buf) & 0x0f;
- if (remotecodec > 3) {
- printk(KERN_WARNING "%s: packet error - remotecodec %d "
- "unsupported\n", __func__, remotecodec);
- return;
- }
- buf++;
- len--;
-
- /* check packet_id */
- if (packet_id) {
- if (!hc->id) {
- printk(KERN_WARNING "%s: packet error - packet has id "
- "0x%x, but we have not\n", __func__, packet_id);
- return;
- }
- if (len < 4) {
- printk(KERN_WARNING "%s: packet error - packet too "
- "short for ID value\n", __func__);
- return;
- }
- packet_id = (*buf++) << 24;
- packet_id += (*buf++) << 16;
- packet_id += (*buf++) << 8;
- packet_id += (*buf++);
- len -= 4;
-
- if (packet_id != hc->id) {
- printk(KERN_WARNING "%s: packet error - ID mismatch, "
- "got 0x%x, we 0x%x\n",
- __func__, packet_id, hc->id);
- return;
- }
- } else {
- if (hc->id) {
- printk(KERN_WARNING "%s: packet error - packet has no "
- "ID, but we have\n", __func__);
- return;
- }
- }
-
-multiframe:
- if (len < 1) {
- printk(KERN_WARNING "%s: packet error - packet too short, "
- "channel expected at position %d.\n",
- __func__, len-len_start + 1);
- return;
- }
-
- /* get channel and multiframe flag */
- channel = *buf & 0x7f;
- m = *buf >> 7;
- buf++;
- len--;
-
- /* check length on multiframe */
- if (m) {
- if (len < 1) {
- printk(KERN_WARNING "%s: packet error - packet too "
- "short, length expected at position %d.\n",
- __func__, len_start - len - 1);
- return;
- }
-
- mlen = *buf++;
- len--;
- if (mlen == 0)
- mlen = 256;
- if (len < mlen + 3) {
- printk(KERN_WARNING "%s: packet error - length %d at "
- "position %d exceeds total length %d.\n",
- __func__, mlen, len_start-len - 1, len_start);
- return;
- }
- if (len == mlen + 3) {
- printk(KERN_WARNING "%s: packet error - length %d at "
- "position %d will not allow additional "
- "packet.\n",
- __func__, mlen, len_start-len + 1);
- return;
- }
- } else
- mlen = len - 2; /* single frame, subtract timebase */
-
- if (len < 2) {
- printk(KERN_WARNING "%s: packet error - packet too short, time "
- "base expected at position %d.\n",
- __func__, len-len_start + 1);
- return;
- }
-
- /* get time base */
- timebase = (*buf++) << 8;
- timebase |= (*buf++);
- len -= 2;
-
- /* if inactive, we send up a PH_ACTIVATE and activate */
- if (!test_bit(FLG_ACTIVE, &dch->Flags)) {
- if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET))
- printk(KERN_DEBUG "%s: interface become active due to "
- "received packet\n", __func__);
- test_and_set_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_ATOMIC);
- }
-
- /* distribute packet */
- l1oip_socket_recv(hc, remotecodec, channel, timebase, buf, mlen);
- buf += mlen;
- len -= mlen;
-
- /* multiframe */
- if (m)
- goto multiframe;
-
- /* restart timer */
- if ((time_before(hc->timeout_tl.expires, jiffies + 5 * HZ) ||
- !hc->timeout_on) &&
- !hc->shutdown) {
- hc->timeout_on = 1;
- mod_timer(&hc->timeout_tl, jiffies + L1OIP_TIMEOUT * HZ);
- } else /* only adjust timer */
- hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT * HZ;
-
- /* if ip or source port changes */
- if ((hc->sin_remote.sin_addr.s_addr != sin->sin_addr.s_addr)
- || (hc->sin_remote.sin_port != sin->sin_port)) {
- if (debug & DEBUG_L1OIP_SOCKET)
- printk(KERN_DEBUG "%s: remote address changes from "
- "0x%08x to 0x%08x (port %d to %d)\n", __func__,
- ntohl(hc->sin_remote.sin_addr.s_addr),
- ntohl(sin->sin_addr.s_addr),
- ntohs(hc->sin_remote.sin_port),
- ntohs(sin->sin_port));
- hc->sin_remote.sin_addr.s_addr = sin->sin_addr.s_addr;
- hc->sin_remote.sin_port = sin->sin_port;
- }
-}
-
-
-/*
- * socket stuff
- */
-static int
-l1oip_socket_thread(void *data)
-{
- struct l1oip *hc = (struct l1oip *)data;
- int ret = 0;
- struct sockaddr_in sin_rx;
- struct kvec iov;
- struct msghdr msg = {.msg_name = &sin_rx,
- .msg_namelen = sizeof(sin_rx)};
- unsigned char *recvbuf;
- size_t recvbuf_size = 1500;
- int recvlen;
- struct socket *socket = NULL;
- DECLARE_COMPLETION_ONSTACK(wait);
-
- /* allocate buffer memory */
- recvbuf = kmalloc(recvbuf_size, GFP_KERNEL);
- if (!recvbuf) {
- printk(KERN_ERR "%s: Failed to alloc recvbuf.\n", __func__);
- ret = -ENOMEM;
- goto fail;
- }
-
- iov.iov_base = recvbuf;
- iov.iov_len = recvbuf_size;
-
- /* make daemon */
- allow_signal(SIGTERM);
-
- /* create socket */
- if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &socket)) {
- printk(KERN_ERR "%s: Failed to create socket.\n", __func__);
- ret = -EIO;
- goto fail;
- }
-
- /* set incoming address */
- hc->sin_local.sin_family = AF_INET;
- hc->sin_local.sin_addr.s_addr = INADDR_ANY;
- hc->sin_local.sin_port = htons((unsigned short)hc->localport);
-
- /* set outgoing address */
- hc->sin_remote.sin_family = AF_INET;
- hc->sin_remote.sin_addr.s_addr = htonl(hc->remoteip);
- hc->sin_remote.sin_port = htons((unsigned short)hc->remoteport);
-
- /* bind to incoming port */
- if (socket->ops->bind(socket, (struct sockaddr_unsized *)&hc->sin_local,
- sizeof(hc->sin_local))) {
- printk(KERN_ERR "%s: Failed to bind socket to port %d.\n",
- __func__, hc->localport);
- ret = -EINVAL;
- goto fail;
- }
-
- /* check sk */
- if (socket->sk == NULL) {
- printk(KERN_ERR "%s: socket->sk == NULL\n", __func__);
- ret = -EIO;
- goto fail;
- }
-
- /* build send message */
- hc->sendmsg.msg_name = &hc->sin_remote;
- hc->sendmsg.msg_namelen = sizeof(hc->sin_remote);
- hc->sendmsg.msg_control = NULL;
- hc->sendmsg.msg_controllen = 0;
-
- /* give away socket */
- spin_lock(&hc->socket_lock);
- hc->socket = socket;
- spin_unlock(&hc->socket_lock);
-
- /* read loop */
- if (debug & DEBUG_L1OIP_SOCKET)
- printk(KERN_DEBUG "%s: socket created and open\n",
- __func__);
- while (!signal_pending(current)) {
- iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, recvbuf_size);
- recvlen = sock_recvmsg(socket, &msg, 0);
- if (recvlen > 0) {
- l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen);
- } else {
- if (debug & DEBUG_L1OIP_SOCKET)
- printk(KERN_WARNING
- "%s: broken pipe on socket\n", __func__);
- }
- }
-
- /* get socket back, check first if in use, maybe by send function */
- spin_lock(&hc->socket_lock);
- /* if hc->socket is NULL, it is in use until it is given back */
- while (!hc->socket) {
- spin_unlock(&hc->socket_lock);
- schedule_timeout(HZ / 10);
- spin_lock(&hc->socket_lock);
- }
- hc->socket = NULL;
- spin_unlock(&hc->socket_lock);
-
- if (debug & DEBUG_L1OIP_SOCKET)
- printk(KERN_DEBUG "%s: socket thread terminating\n",
- __func__);
-
-fail:
- /* free recvbuf */
- kfree(recvbuf);
-
- /* close socket */
- if (socket)
- sock_release(socket);
-
- /* if we got killed, signal completion */
- complete(&hc->socket_complete);
- hc->socket_thread = NULL; /* show termination of thread */
-
- if (debug & DEBUG_L1OIP_SOCKET)
- printk(KERN_DEBUG "%s: socket thread terminated\n",
- __func__);
- return ret;
-}
-
-static void
-l1oip_socket_close(struct l1oip *hc)
-{
- struct dchannel *dch = hc->chan[hc->d_idx].dch;
-
- /* kill thread */
- if (hc->socket_thread) {
- if (debug & DEBUG_L1OIP_SOCKET)
- printk(KERN_DEBUG "%s: socket thread exists, "
- "killing...\n", __func__);
- send_sig(SIGTERM, hc->socket_thread, 0);
- wait_for_completion(&hc->socket_complete);
- }
-
- /* if active, we send up a PH_DEACTIVATE and deactivate */
- if (test_bit(FLG_ACTIVE, &dch->Flags)) {
- if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET))
- printk(KERN_DEBUG "%s: interface become deactivated "
- "due to timeout\n", __func__);
- test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_ATOMIC);
- }
-}
-
-static int
-l1oip_socket_open(struct l1oip *hc)
-{
- /* in case of reopen, we need to close first */
- l1oip_socket_close(hc);
-
- init_completion(&hc->socket_complete);
-
- /* create receive process */
- hc->socket_thread = kthread_run(l1oip_socket_thread, hc, "l1oip_%s",
- hc->name);
- if (IS_ERR(hc->socket_thread)) {
- int err = PTR_ERR(hc->socket_thread);
- printk(KERN_ERR "%s: Failed (%d) to create socket process.\n",
- __func__, err);
- hc->socket_thread = NULL;
- sock_release(hc->socket);
- return err;
- }
- if (debug & DEBUG_L1OIP_SOCKET)
- printk(KERN_DEBUG "%s: socket thread created\n", __func__);
-
- return 0;
-}
-
-
-static void
-l1oip_send_bh(struct work_struct *work)
-{
- struct l1oip *hc = container_of(work, struct l1oip, workq);
-
- if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET))
- printk(KERN_DEBUG "%s: keepalive timer expired, sending empty "
- "frame on dchannel\n", __func__);
-
- /* send an empty l1oip frame at D-channel */
- l1oip_socket_send(hc, 0, hc->d_idx, 0, 0, NULL, 0);
-}
-
-
-/*
- * timer stuff
- */
-static void
-l1oip_keepalive(struct timer_list *t)
-{
- struct l1oip *hc = timer_container_of(hc, t, keep_tl);
-
- schedule_work(&hc->workq);
-}
-
-static void
-l1oip_timeout(struct timer_list *t)
-{
- struct l1oip *hc = timer_container_of(hc, t,
- timeout_tl);
- struct dchannel *dch = hc->chan[hc->d_idx].dch;
-
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: timeout timer expired, turn layer one "
- "down.\n", __func__);
-
- hc->timeout_on = 0; /* state that timer must be initialized next time */
-
- /* if timeout, we send up a PH_DEACTIVATE and deactivate */
- if (test_bit(FLG_ACTIVE, &dch->Flags)) {
- if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET))
- printk(KERN_DEBUG "%s: interface become deactivated "
- "due to timeout\n", __func__);
- test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
- _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
- NULL, GFP_ATOMIC);
- }
-
- /* if we have ondemand set, we remove ip address */
- if (hc->ondemand) {
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: on demand causes ip address to "
- "be removed\n", __func__);
- hc->sin_remote.sin_addr.s_addr = 0;
- }
-}
-
-
-/*
- * message handling
- */
-static int
-handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct l1oip *hc = dch->hw;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- int ret = -EINVAL;
- int l, ll;
- unsigned char *p;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- if (skb->len < 1) {
- printk(KERN_WARNING "%s: skb too small\n",
- __func__);
- break;
- }
- if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) {
- printk(KERN_WARNING "%s: skb too large\n",
- __func__);
- break;
- }
- /* send frame */
- p = skb->data;
- l = skb->len;
- while (l) {
- /*
- * This is technically bounded by L1OIP_MAX_PERFRAME but
- * MAX_DFRAME_LEN_L1 < L1OIP_MAX_PERFRAME
- */
- ll = (l < MAX_DFRAME_LEN_L1) ? l : MAX_DFRAME_LEN_L1;
- l1oip_socket_send(hc, 0, dch->slot, 0,
- hc->chan[dch->slot].tx_counter++, p, ll);
- p += ll;
- l -= ll;
- }
- skb_trim(skb, 0);
- queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb);
- return 0;
- case PH_ACTIVATE_REQ:
- if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET))
- printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n"
- , __func__, dch->slot, hc->b_num + 1);
- skb_trim(skb, 0);
- if (test_bit(FLG_ACTIVE, &dch->Flags))
- queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb);
- else
- queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb);
- return 0;
- case PH_DEACTIVATE_REQ:
- if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET))
- printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d "
- "(1..%d)\n", __func__, dch->slot,
- hc->b_num + 1);
- skb_trim(skb, 0);
- if (test_bit(FLG_ACTIVE, &dch->Flags))
- queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb);
- else
- queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb);
- return 0;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static int
-channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
-{
- int ret = 0;
- struct l1oip *hc = dch->hw;
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_SETPEER | MISDN_CTRL_UNSETPEER
- | MISDN_CTRL_GETPEER;
- break;
- case MISDN_CTRL_SETPEER:
- hc->remoteip = (u32)cq->p1;
- hc->remoteport = cq->p2 & 0xffff;
- hc->localport = cq->p2 >> 16;
- if (!hc->remoteport)
- hc->remoteport = hc->localport;
- if (debug & DEBUG_L1OIP_SOCKET)
- printk(KERN_DEBUG "%s: got new ip address from user "
- "space.\n", __func__);
- l1oip_socket_open(hc);
- break;
- case MISDN_CTRL_UNSETPEER:
- if (debug & DEBUG_L1OIP_SOCKET)
- printk(KERN_DEBUG "%s: removing ip address.\n",
- __func__);
- hc->remoteip = 0;
- l1oip_socket_open(hc);
- break;
- case MISDN_CTRL_GETPEER:
- if (debug & DEBUG_L1OIP_SOCKET)
- printk(KERN_DEBUG "%s: getting ip address.\n",
- __func__);
- cq->p1 = hc->remoteip;
- cq->p2 = hc->remoteport | (hc->localport << 16);
- break;
- default:
- printk(KERN_WARNING "%s: unknown Op %x\n",
- __func__, cq->op);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int
-open_dchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq)
-{
- if (debug & DEBUG_HW_OPEN)
- printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__,
- dch->dev.id, __builtin_return_address(0));
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
- if ((dch->dev.D.protocol != ISDN_P_NONE) &&
- (dch->dev.D.protocol != rq->protocol)) {
- if (debug & DEBUG_HW_OPEN)
- printk(KERN_WARNING "%s: change protocol %x to %x\n",
- __func__, dch->dev.D.protocol, rq->protocol);
- }
- if (dch->dev.D.protocol != rq->protocol)
- dch->dev.D.protocol = rq->protocol;
-
- if (test_bit(FLG_ACTIVE, &dch->Flags)) {
- _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY,
- 0, NULL, GFP_KERNEL);
- }
- rq->ch = &dch->dev.D;
- if (!try_module_get(THIS_MODULE))
- printk(KERN_WARNING "%s:cannot get module\n", __func__);
- return 0;
-}
-
-static int
-open_bchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq)
-{
- struct bchannel *bch;
- int ch;
-
- if (!test_channelmap(rq->adr.channel, dch->dev.channelmap))
- return -EINVAL;
- if (rq->protocol == ISDN_P_NONE)
- return -EINVAL;
- ch = rq->adr.channel; /* BRI: 1=B1 2=B2 PRI: 1..15,17.. */
- bch = hc->chan[ch].bch;
- if (!bch) {
- printk(KERN_ERR "%s:internal error ch %d has no bch\n",
- __func__, ch);
- return -EINVAL;
- }
- if (test_and_set_bit(FLG_OPEN, &bch->Flags))
- return -EBUSY; /* b-channel can be only open once */
- bch->ch.protocol = rq->protocol;
- rq->ch = &bch->ch;
- if (!try_module_get(THIS_MODULE))
- printk(KERN_WARNING "%s:cannot get module\n", __func__);
- return 0;
-}
-
-static int
-l1oip_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
- struct dchannel *dch = container_of(dev, struct dchannel, dev);
- struct l1oip *hc = dch->hw;
- struct channel_req *rq;
- int err = 0;
-
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: cmd:%x %p\n",
- __func__, cmd, arg);
- switch (cmd) {
- case OPEN_CHANNEL:
- rq = arg;
- switch (rq->protocol) {
- case ISDN_P_TE_S0:
- case ISDN_P_NT_S0:
- if (hc->pri) {
- err = -EINVAL;
- break;
- }
- err = open_dchannel(hc, dch, rq);
- break;
- case ISDN_P_TE_E1:
- case ISDN_P_NT_E1:
- if (!hc->pri) {
- err = -EINVAL;
- break;
- }
- err = open_dchannel(hc, dch, rq);
- break;
- default:
- err = open_bchannel(hc, dch, rq);
- }
- break;
- case CLOSE_CHANNEL:
- if (debug & DEBUG_HW_OPEN)
- printk(KERN_DEBUG "%s: dev(%d) close from %p\n",
- __func__, dch->dev.id,
- __builtin_return_address(0));
- module_put(THIS_MODULE);
- break;
- case CONTROL_CHANNEL:
- err = channel_dctrl(dch, arg);
- break;
- default:
- if (dch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: unknown command %x\n",
- __func__, cmd);
- err = -EINVAL;
- }
- return err;
-}
-
-static int
-handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- struct l1oip *hc = bch->hw;
- int ret = -EINVAL;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- int l, ll;
- unsigned char *p;
-
- switch (hh->prim) {
- case PH_DATA_REQ:
- if (skb->len <= 0) {
- printk(KERN_WARNING "%s: skb too small\n",
- __func__);
- break;
- }
- if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) {
- printk(KERN_WARNING "%s: skb too large\n",
- __func__);
- break;
- }
- /* check for AIS / ulaw-silence */
- l = skb->len;
- if (!memchr_inv(skb->data, 0xff, l)) {
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: got AIS, not sending, "
- "but counting\n", __func__);
- hc->chan[bch->slot].tx_counter += l;
- skb_trim(skb, 0);
- queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb);
- return 0;
- }
- /* check for silence */
- l = skb->len;
- if (!memchr_inv(skb->data, 0x2a, l)) {
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: got silence, not sending"
- ", but counting\n", __func__);
- hc->chan[bch->slot].tx_counter += l;
- skb_trim(skb, 0);
- queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb);
- return 0;
- }
-
- /* send frame */
- p = skb->data;
- l = skb->len;
- while (l) {
- /*
- * This is technically bounded by L1OIP_MAX_PERFRAME but
- * MAX_DFRAME_LEN_L1 < L1OIP_MAX_PERFRAME
- */
- ll = (l < MAX_DFRAME_LEN_L1) ? l : MAX_DFRAME_LEN_L1;
- l1oip_socket_send(hc, hc->codec, bch->slot, 0,
- hc->chan[bch->slot].tx_counter, p, ll);
- hc->chan[bch->slot].tx_counter += ll;
- p += ll;
- l -= ll;
- }
- skb_trim(skb, 0);
- queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb);
- return 0;
- case PH_ACTIVATE_REQ:
- if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET))
- printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n"
- , __func__, bch->slot, hc->b_num + 1);
- hc->chan[bch->slot].codecstate = 0;
- test_and_set_bit(FLG_ACTIVE, &bch->Flags);
- skb_trim(skb, 0);
- queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb);
- return 0;
- case PH_DEACTIVATE_REQ:
- if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET))
- printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d "
- "(1..%d)\n", __func__, bch->slot,
- hc->b_num + 1);
- test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
- skb_trim(skb, 0);
- queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb);
- return 0;
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static int
-channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
-{
- int ret = 0;
- struct dsp_features *features =
- (struct dsp_features *)(*((u_long *)&cq->p1));
-
- switch (cq->op) {
- case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_HW_FEATURES_OP;
- break;
- case MISDN_CTRL_HW_FEATURES: /* fill features structure */
- if (debug & DEBUG_L1OIP_MSG)
- printk(KERN_DEBUG "%s: HW_FEATURE request\n",
- __func__);
- /* create confirm */
- features->unclocked = 1;
- features->unordered = 1;
- break;
- default:
- printk(KERN_WARNING "%s: unknown Op %x\n",
- __func__, cq->op);
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int
-l1oip_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct bchannel *bch = container_of(ch, struct bchannel, ch);
- int err = -EINVAL;
-
- if (bch->debug & DEBUG_HW)
- printk(KERN_DEBUG "%s: cmd:%x %p\n",
- __func__, cmd, arg);
- switch (cmd) {
- case CLOSE_CHANNEL:
- test_and_clear_bit(FLG_OPEN, &bch->Flags);
- test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
- ch->protocol = ISDN_P_NONE;
- ch->peer = NULL;
- module_put(THIS_MODULE);
- err = 0;
- break;
- case CONTROL_CHANNEL:
- err = channel_bctrl(bch, arg);
- break;
- default:
- printk(KERN_WARNING "%s: unknown prim(%x)\n",
- __func__, cmd);
- }
- return err;
-}
-
-
-/*
- * cleanup module and stack
- */
-static void
-release_card(struct l1oip *hc)
-{
- int ch;
-
- hc->shutdown = true;
-
- timer_shutdown_sync(&hc->keep_tl);
- timer_shutdown_sync(&hc->timeout_tl);
-
- cancel_work_sync(&hc->workq);
-
- if (hc->socket_thread)
- l1oip_socket_close(hc);
-
- if (hc->registered && hc->chan[hc->d_idx].dch)
- mISDN_unregister_device(&hc->chan[hc->d_idx].dch->dev);
- for (ch = 0; ch < 128; ch++) {
- if (hc->chan[ch].dch) {
- mISDN_freedchannel(hc->chan[ch].dch);
- kfree(hc->chan[ch].dch);
- }
- if (hc->chan[ch].bch) {
- mISDN_freebchannel(hc->chan[ch].bch);
- kfree(hc->chan[ch].bch);
-#ifdef REORDER_DEBUG
- dev_kfree_skb(hc->chan[ch].disorder_skb);
-#endif
- }
- }
-
- spin_lock(&l1oip_lock);
- list_del(&hc->list);
- spin_unlock(&l1oip_lock);
-
- kfree(hc);
-}
-
-static void
-l1oip_cleanup(void)
-{
- struct l1oip *hc, *next;
-
- list_for_each_entry_safe(hc, next, &l1oip_ilist, list)
- release_card(hc);
-
- l1oip_4bit_free();
-}
-
-
-/*
- * module and stack init
- */
-static int
-init_card(struct l1oip *hc, int pri, int bundle)
-{
- struct dchannel *dch;
- struct bchannel *bch;
- int ret;
- int i, ch;
-
- spin_lock_init(&hc->socket_lock);
- hc->idx = l1oip_cnt;
- hc->pri = pri;
- hc->d_idx = pri ? 16 : 3;
- hc->b_num = pri ? 30 : 2;
- hc->bundle = bundle;
- if (hc->pri)
- sprintf(hc->name, "l1oip-e1.%d", l1oip_cnt + 1);
- else
- sprintf(hc->name, "l1oip-s0.%d", l1oip_cnt + 1);
-
- switch (codec[l1oip_cnt]) {
- case 0: /* as is */
- case 1: /* alaw */
- case 2: /* ulaw */
- case 3: /* 4bit */
- break;
- default:
- printk(KERN_ERR "Codec(%d) not supported.\n",
- codec[l1oip_cnt]);
- return -EINVAL;
- }
- hc->codec = codec[l1oip_cnt];
- if (debug & DEBUG_L1OIP_INIT)
- printk(KERN_DEBUG "%s: using codec %d\n",
- __func__, hc->codec);
-
- if (id[l1oip_cnt] == 0) {
- printk(KERN_WARNING "Warning: No 'id' value given or "
- "0, this is highly unsecure. Please use 32 "
- "bit random number 0x...\n");
- }
- hc->id = id[l1oip_cnt];
- if (debug & DEBUG_L1OIP_INIT)
- printk(KERN_DEBUG "%s: using id 0x%x\n", __func__, hc->id);
-
- hc->ondemand = ondemand[l1oip_cnt];
- if (hc->ondemand && !hc->id) {
- printk(KERN_ERR "%s: ondemand option only allowed in "
- "conjunction with non 0 ID\n", __func__);
- return -EINVAL;
- }
-
- if (limit[l1oip_cnt])
- hc->b_num = limit[l1oip_cnt];
- if (!pri && hc->b_num > 2) {
- printk(KERN_ERR "Maximum limit for BRI interface is 2 "
- "channels.\n");
- return -EINVAL;
- }
- if (pri && hc->b_num > 126) {
- printk(KERN_ERR "Maximum limit for PRI interface is 126 "
- "channels.\n");
- return -EINVAL;
- }
- if (pri && hc->b_num > 30) {
- printk(KERN_WARNING "Maximum limit for BRI interface is 30 "
- "channels.\n");
- printk(KERN_WARNING "Your selection of %d channels must be "
- "supported by application.\n", hc->limit);
- }
-
- hc->remoteip = ip[l1oip_cnt << 2] << 24
- | ip[(l1oip_cnt << 2) + 1] << 16
- | ip[(l1oip_cnt << 2) + 2] << 8
- | ip[(l1oip_cnt << 2) + 3];
- hc->localport = port[l1oip_cnt]?:(L1OIP_DEFAULTPORT + l1oip_cnt);
- if (remoteport[l1oip_cnt])
- hc->remoteport = remoteport[l1oip_cnt];
- else
- hc->remoteport = hc->localport;
- if (debug & DEBUG_L1OIP_INIT)
- printk(KERN_DEBUG "%s: using local port %d remote ip "
- "%d.%d.%d.%d port %d ondemand %d\n", __func__,
- hc->localport, hc->remoteip >> 24,
- (hc->remoteip >> 16) & 0xff,
- (hc->remoteip >> 8) & 0xff, hc->remoteip & 0xff,
- hc->remoteport, hc->ondemand);
-
- dch = kzalloc_obj(struct dchannel);
- if (!dch)
- return -ENOMEM;
- dch->debug = debug;
- mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, NULL);
- dch->hw = hc;
- if (pri)
- dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1);
- else
- dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0);
- dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
- (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
- dch->dev.D.send = handle_dmsg;
- dch->dev.D.ctrl = l1oip_dctrl;
- dch->dev.nrbchan = hc->b_num;
- dch->slot = hc->d_idx;
- hc->chan[hc->d_idx].dch = dch;
- i = 1;
- for (ch = 0; ch < dch->dev.nrbchan; ch++) {
- if (ch == 15)
- i++;
- bch = kzalloc_obj(struct bchannel);
- if (!bch) {
- printk(KERN_ERR "%s: no memory for bchannel\n",
- __func__);
- return -ENOMEM;
- }
- bch->nr = i + ch;
- bch->slot = i + ch;
- bch->debug = debug;
- mISDN_initbchannel(bch, MAX_DATA_MEM, 0);
- bch->hw = hc;
- bch->ch.send = handle_bmsg;
- bch->ch.ctrl = l1oip_bctrl;
- bch->ch.nr = i + ch;
- list_add(&bch->ch.list, &dch->dev.bchannels);
- hc->chan[i + ch].bch = bch;
- set_channelmap(bch->nr, dch->dev.channelmap);
- }
- /* TODO: create a parent device for this driver */
- ret = mISDN_register_device(&dch->dev, NULL, hc->name);
- if (ret)
- return ret;
- hc->registered = 1;
-
- if (debug & DEBUG_L1OIP_INIT)
- printk(KERN_DEBUG "%s: Setting up network card(%d)\n",
- __func__, l1oip_cnt + 1);
- ret = l1oip_socket_open(hc);
- if (ret)
- return ret;
-
- timer_setup(&hc->keep_tl, l1oip_keepalive, 0);
- hc->keep_tl.expires = jiffies + 2 * HZ; /* two seconds first time */
- add_timer(&hc->keep_tl);
-
- timer_setup(&hc->timeout_tl, l1oip_timeout, 0);
- hc->timeout_on = 0; /* state that we have timer off */
-
- return 0;
-}
-
-static int __init
-l1oip_init(void)
-{
- int pri, bundle;
- struct l1oip *hc;
- int ret;
-
- printk(KERN_INFO "mISDN: Layer-1-over-IP driver Rev. %s\n",
- l1oip_revision);
-
- if (l1oip_4bit_alloc(ulaw))
- return -ENOMEM;
-
- l1oip_cnt = 0;
- while (l1oip_cnt < MAX_CARDS && type[l1oip_cnt]) {
- switch (type[l1oip_cnt] & 0xff) {
- case 1:
- pri = 0;
- bundle = 0;
- break;
- case 2:
- pri = 1;
- bundle = 0;
- break;
- case 3:
- pri = 0;
- bundle = 1;
- break;
- case 4:
- pri = 1;
- bundle = 1;
- break;
- default:
- printk(KERN_ERR "Card type(%d) not supported.\n",
- type[l1oip_cnt] & 0xff);
- l1oip_cleanup();
- return -EINVAL;
- }
-
- if (debug & DEBUG_L1OIP_INIT)
- printk(KERN_DEBUG "%s: interface %d is %s with %s.\n",
- __func__, l1oip_cnt, pri ? "PRI" : "BRI",
- bundle ? "bundled IP packet for all B-channels" :
- "separate IP packets for every B-channel");
-
- hc = kzalloc_obj(struct l1oip, GFP_ATOMIC);
- if (!hc) {
- printk(KERN_ERR "No kmem for L1-over-IP driver.\n");
- l1oip_cleanup();
- return -ENOMEM;
- }
- INIT_WORK(&hc->workq, (void *)l1oip_send_bh);
-
- spin_lock(&l1oip_lock);
- list_add_tail(&hc->list, &l1oip_ilist);
- spin_unlock(&l1oip_lock);
-
- ret = init_card(hc, pri, bundle);
- if (ret) {
- l1oip_cleanup();
- return ret;
- }
-
- l1oip_cnt++;
- }
- printk(KERN_INFO "%d virtual devices registered\n", l1oip_cnt);
- return 0;
-}
-
-module_init(l1oip_init);
-module_exit(l1oip_cleanup);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *
- * Author Karsten Keil <kkeil@novell.com>
- *
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mISDNhw.h>
-#include "core.h"
-#include "layer1.h"
-#include "fsm.h"
-
-static u_int *debug;
-
-struct layer1 {
- u_long Flags;
- struct FsmInst l1m;
- struct FsmTimer timer3;
- struct FsmTimer timerX;
- int delay;
- int t3_value;
- struct dchannel *dch;
- dchannel_l1callback *dcb;
-};
-
-#define TIMER3_DEFAULT_VALUE 7000
-
-static
-struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL};
-
-enum {
- ST_L1_F2,
- ST_L1_F3,
- ST_L1_F4,
- ST_L1_F5,
- ST_L1_F6,
- ST_L1_F7,
- ST_L1_F8,
-};
-
-#define L1S_STATE_COUNT (ST_L1_F8 + 1)
-
-static char *strL1SState[] =
-{
- "ST_L1_F2",
- "ST_L1_F3",
- "ST_L1_F4",
- "ST_L1_F5",
- "ST_L1_F6",
- "ST_L1_F7",
- "ST_L1_F8",
-};
-
-enum {
- EV_PH_ACTIVATE,
- EV_PH_DEACTIVATE,
- EV_RESET_IND,
- EV_DEACT_CNF,
- EV_DEACT_IND,
- EV_POWER_UP,
- EV_ANYSIG_IND,
- EV_INFO2_IND,
- EV_INFO4_IND,
- EV_TIMER_DEACT,
- EV_TIMER_ACT,
- EV_TIMER3,
-};
-
-#define L1_EVENT_COUNT (EV_TIMER3 + 1)
-
-static char *strL1Event[] =
-{
- "EV_PH_ACTIVATE",
- "EV_PH_DEACTIVATE",
- "EV_RESET_IND",
- "EV_DEACT_CNF",
- "EV_DEACT_IND",
- "EV_POWER_UP",
- "EV_ANYSIG_IND",
- "EV_INFO2_IND",
- "EV_INFO4_IND",
- "EV_TIMER_DEACT",
- "EV_TIMER_ACT",
- "EV_TIMER3",
-};
-
-static void
-l1m_debug(struct FsmInst *fi, char *fmt, ...)
-{
- struct layer1 *l1 = fi->userdata;
- struct va_format vaf;
- va_list va;
-
- va_start(va, fmt);
-
- vaf.fmt = fmt;
- vaf.va = &va;
-
- printk(KERN_DEBUG "%s: %pV\n", dev_name(&l1->dch->dev.dev), &vaf);
-
- va_end(va);
-}
-
-static void
-l1_reset(struct FsmInst *fi, int event, void *arg)
-{
- mISDN_FsmChangeState(fi, ST_L1_F3);
-}
-
-static void
-l1_deact_cnf(struct FsmInst *fi, int event, void *arg)
-{
- struct layer1 *l1 = fi->userdata;
-
- mISDN_FsmChangeState(fi, ST_L1_F3);
- if (test_bit(FLG_L1_ACTIVATING, &l1->Flags))
- l1->dcb(l1->dch, HW_POWERUP_REQ);
-}
-
-static void
-l1_deact_req_s(struct FsmInst *fi, int event, void *arg)
-{
- struct layer1 *l1 = fi->userdata;
-
- mISDN_FsmChangeState(fi, ST_L1_F3);
- mISDN_FsmRestartTimer(&l1->timerX, 550, EV_TIMER_DEACT, NULL, 2);
- test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags);
-}
-
-static void
-l1_power_up_s(struct FsmInst *fi, int event, void *arg)
-{
- struct layer1 *l1 = fi->userdata;
-
- if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) {
- mISDN_FsmChangeState(fi, ST_L1_F4);
- l1->dcb(l1->dch, INFO3_P8);
- } else
- mISDN_FsmChangeState(fi, ST_L1_F3);
-}
-
-static void
-l1_go_F5(struct FsmInst *fi, int event, void *arg)
-{
- mISDN_FsmChangeState(fi, ST_L1_F5);
-}
-
-static void
-l1_go_F8(struct FsmInst *fi, int event, void *arg)
-{
- mISDN_FsmChangeState(fi, ST_L1_F8);
-}
-
-static void
-l1_info2_ind(struct FsmInst *fi, int event, void *arg)
-{
- struct layer1 *l1 = fi->userdata;
-
- mISDN_FsmChangeState(fi, ST_L1_F6);
- l1->dcb(l1->dch, INFO3_P8);
-}
-
-static void
-l1_info4_ind(struct FsmInst *fi, int event, void *arg)
-{
- struct layer1 *l1 = fi->userdata;
-
- mISDN_FsmChangeState(fi, ST_L1_F7);
- l1->dcb(l1->dch, INFO3_P8);
- if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags))
- mISDN_FsmDelTimer(&l1->timerX, 4);
- if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) {
- if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags))
- mISDN_FsmDelTimer(&l1->timer3, 3);
- mISDN_FsmRestartTimer(&l1->timerX, 110, EV_TIMER_ACT, NULL, 2);
- test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags);
- }
-}
-
-static void
-l1_timer3(struct FsmInst *fi, int event, void *arg)
-{
- struct layer1 *l1 = fi->userdata;
-
- test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags);
- if (test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags)) {
- if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags))
- l1->dcb(l1->dch, HW_D_NOBLOCKED);
- l1->dcb(l1->dch, PH_DEACTIVATE_IND);
- }
- if (l1->l1m.state != ST_L1_F6) {
- mISDN_FsmChangeState(fi, ST_L1_F3);
- /* do not force anything here, we need send INFO 0 */
- }
-}
-
-static void
-l1_timer_act(struct FsmInst *fi, int event, void *arg)
-{
- struct layer1 *l1 = fi->userdata;
-
- test_and_clear_bit(FLG_L1_ACTTIMER, &l1->Flags);
- test_and_set_bit(FLG_L1_ACTIVATED, &l1->Flags);
- l1->dcb(l1->dch, PH_ACTIVATE_IND);
-}
-
-static void
-l1_timer_deact(struct FsmInst *fi, int event, void *arg)
-{
- struct layer1 *l1 = fi->userdata;
-
- test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags);
- test_and_clear_bit(FLG_L1_ACTIVATED, &l1->Flags);
- if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags))
- l1->dcb(l1->dch, HW_D_NOBLOCKED);
- l1->dcb(l1->dch, PH_DEACTIVATE_IND);
- l1->dcb(l1->dch, HW_DEACT_REQ);
-}
-
-static void
-l1_activate_s(struct FsmInst *fi, int event, void *arg)
-{
- struct layer1 *l1 = fi->userdata;
-
- mISDN_FsmRestartTimer(&l1->timer3, l1->t3_value, EV_TIMER3, NULL, 2);
- test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
- /* Tell HW to send INFO 1 */
- l1->dcb(l1->dch, HW_RESET_REQ);
-}
-
-static void
-l1_activate_no(struct FsmInst *fi, int event, void *arg)
-{
- struct layer1 *l1 = fi->userdata;
-
- if ((!test_bit(FLG_L1_DEACTTIMER, &l1->Flags)) &&
- (!test_bit(FLG_L1_T3RUN, &l1->Flags))) {
- test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags);
- if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags))
- l1->dcb(l1->dch, HW_D_NOBLOCKED);
- l1->dcb(l1->dch, PH_DEACTIVATE_IND);
- }
-}
-
-static struct FsmNode L1SFnList[] =
-{
- {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s},
- {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no},
- {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no},
- {ST_L1_F3, EV_RESET_IND, l1_reset},
- {ST_L1_F4, EV_RESET_IND, l1_reset},
- {ST_L1_F5, EV_RESET_IND, l1_reset},
- {ST_L1_F6, EV_RESET_IND, l1_reset},
- {ST_L1_F7, EV_RESET_IND, l1_reset},
- {ST_L1_F8, EV_RESET_IND, l1_reset},
- {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s},
- {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s},
- {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s},
- {ST_L1_F3, EV_POWER_UP, l1_power_up_s},
- {ST_L1_F4, EV_ANYSIG_IND, l1_go_F5},
- {ST_L1_F6, EV_ANYSIG_IND, l1_go_F8},
- {ST_L1_F7, EV_ANYSIG_IND, l1_go_F8},
- {ST_L1_F3, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_F4, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_F5, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_F7, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_F8, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_F3, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_F4, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_F5, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_F6, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_F8, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_F3, EV_TIMER3, l1_timer3},
- {ST_L1_F4, EV_TIMER3, l1_timer3},
- {ST_L1_F5, EV_TIMER3, l1_timer3},
- {ST_L1_F6, EV_TIMER3, l1_timer3},
- {ST_L1_F8, EV_TIMER3, l1_timer3},
- {ST_L1_F7, EV_TIMER_ACT, l1_timer_act},
- {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
-};
-
-static void
-release_l1(struct layer1 *l1) {
- mISDN_FsmDelTimer(&l1->timerX, 0);
- mISDN_FsmDelTimer(&l1->timer3, 0);
- if (l1->dch)
- l1->dch->l1 = NULL;
- module_put(THIS_MODULE);
- kfree(l1);
-}
-
-int
-l1_event(struct layer1 *l1, u_int event)
-{
- int err = 0;
-
- if (!l1)
- return -EINVAL;
- switch (event) {
- case HW_RESET_IND:
- mISDN_FsmEvent(&l1->l1m, EV_RESET_IND, NULL);
- break;
- case HW_DEACT_IND:
- mISDN_FsmEvent(&l1->l1m, EV_DEACT_IND, NULL);
- break;
- case HW_POWERUP_IND:
- mISDN_FsmEvent(&l1->l1m, EV_POWER_UP, NULL);
- break;
- case HW_DEACT_CNF:
- mISDN_FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL);
- break;
- case ANYSIGNAL:
- mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
- break;
- case LOSTFRAMING:
- mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
- break;
- case INFO2:
- mISDN_FsmEvent(&l1->l1m, EV_INFO2_IND, NULL);
- break;
- case INFO4_P8:
- mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
- break;
- case INFO4_P10:
- mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
- break;
- case PH_ACTIVATE_REQ:
- if (test_bit(FLG_L1_ACTIVATED, &l1->Flags))
- l1->dcb(l1->dch, PH_ACTIVATE_IND);
- else {
- test_and_set_bit(FLG_L1_ACTIVATING, &l1->Flags);
- mISDN_FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL);
- }
- break;
- case CLOSE_CHANNEL:
- release_l1(l1);
- break;
- default:
- if ((event & ~HW_TIMER3_VMASK) == HW_TIMER3_VALUE) {
- int val = event & HW_TIMER3_VMASK;
-
- if (val < 5)
- val = 5;
- if (val > 30)
- val = 30;
- l1->t3_value = val;
- break;
- }
- if (*debug & DEBUG_L1)
- printk(KERN_DEBUG "%s %x unhandled\n",
- __func__, event);
- err = -EINVAL;
- }
- return err;
-}
-EXPORT_SYMBOL(l1_event);
-
-int
-create_l1(struct dchannel *dch, dchannel_l1callback *dcb) {
- struct layer1 *nl1;
-
- nl1 = kzalloc_obj(struct layer1, GFP_ATOMIC);
- if (!nl1) {
- printk(KERN_ERR "kmalloc struct layer1 failed\n");
- return -ENOMEM;
- }
- nl1->l1m.fsm = &l1fsm_s;
- nl1->l1m.state = ST_L1_F3;
- nl1->Flags = 0;
- nl1->t3_value = TIMER3_DEFAULT_VALUE;
- nl1->l1m.debug = *debug & DEBUG_L1_FSM;
- nl1->l1m.userdata = nl1;
- nl1->l1m.userint = 0;
- nl1->l1m.printdebug = l1m_debug;
- nl1->dch = dch;
- nl1->dcb = dcb;
- mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer3);
- mISDN_FsmInitTimer(&nl1->l1m, &nl1->timerX);
- __module_get(THIS_MODULE);
- dch->l1 = nl1;
- return 0;
-}
-EXPORT_SYMBOL(create_l1);
-
-int
-Isdnl1_Init(u_int *deb)
-{
- debug = deb;
- l1fsm_s.state_count = L1S_STATE_COUNT;
- l1fsm_s.event_count = L1_EVENT_COUNT;
- l1fsm_s.strEvent = strL1Event;
- l1fsm_s.strState = strL1SState;
- return mISDN_FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList));
-}
-
-void
-Isdnl1_cleanup(void)
-{
- mISDN_FsmFree(&l1fsm_s);
-}
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- *
- * Layer 1 defines
- *
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#define FLG_L1_ACTIVATING 1
-#define FLG_L1_ACTIVATED 2
-#define FLG_L1_DEACTTIMER 3
-#define FLG_L1_ACTTIMER 4
-#define FLG_L1_T3RUN 5
-#define FLG_L1_PULL_REQ 6
-#define FLG_L1_UINT 7
-#define FLG_L1_DBLOCKED 8
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *
- * Author Karsten Keil <kkeil@novell.com>
- *
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#include <linux/mISDNif.h>
-#include <linux/slab.h>
-#include "core.h"
-#include "fsm.h"
-#include "layer2.h"
-
-static u_int *debug;
-
-static
-struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL};
-
-static char *strL2State[] =
-{
- "ST_L2_1",
- "ST_L2_2",
- "ST_L2_3",
- "ST_L2_4",
- "ST_L2_5",
- "ST_L2_6",
- "ST_L2_7",
- "ST_L2_8",
-};
-
-enum {
- EV_L2_UI,
- EV_L2_SABME,
- EV_L2_DISC,
- EV_L2_DM,
- EV_L2_UA,
- EV_L2_FRMR,
- EV_L2_SUPER,
- EV_L2_I,
- EV_L2_DL_DATA,
- EV_L2_ACK_PULL,
- EV_L2_DL_UNITDATA,
- EV_L2_DL_ESTABLISH_REQ,
- EV_L2_DL_RELEASE_REQ,
- EV_L2_MDL_ASSIGN,
- EV_L2_MDL_REMOVE,
- EV_L2_MDL_ERROR,
- EV_L1_DEACTIVATE,
- EV_L2_T200,
- EV_L2_T203,
- EV_L2_T200I,
- EV_L2_T203I,
- EV_L2_SET_OWN_BUSY,
- EV_L2_CLEAR_OWN_BUSY,
- EV_L2_FRAME_ERROR,
-};
-
-#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR + 1)
-
-static char *strL2Event[] =
-{
- "EV_L2_UI",
- "EV_L2_SABME",
- "EV_L2_DISC",
- "EV_L2_DM",
- "EV_L2_UA",
- "EV_L2_FRMR",
- "EV_L2_SUPER",
- "EV_L2_I",
- "EV_L2_DL_DATA",
- "EV_L2_ACK_PULL",
- "EV_L2_DL_UNITDATA",
- "EV_L2_DL_ESTABLISH_REQ",
- "EV_L2_DL_RELEASE_REQ",
- "EV_L2_MDL_ASSIGN",
- "EV_L2_MDL_REMOVE",
- "EV_L2_MDL_ERROR",
- "EV_L1_DEACTIVATE",
- "EV_L2_T200",
- "EV_L2_T203",
- "EV_L2_T200I",
- "EV_L2_T203I",
- "EV_L2_SET_OWN_BUSY",
- "EV_L2_CLEAR_OWN_BUSY",
- "EV_L2_FRAME_ERROR",
-};
-
-static void
-l2m_debug(struct FsmInst *fi, char *fmt, ...)
-{
- struct layer2 *l2 = fi->userdata;
- struct va_format vaf;
- va_list va;
-
- if (!(*debug & DEBUG_L2_FSM))
- return;
-
- va_start(va, fmt);
-
- vaf.fmt = fmt;
- vaf.va = &va;
-
- printk(KERN_DEBUG "%s l2 (sapi %d tei %d): %pV\n",
- mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, &vaf);
-
- va_end(va);
-}
-
-inline u_int
-l2headersize(struct layer2 *l2, int ui)
-{
- return ((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
- (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1);
-}
-
-inline u_int
-l2addrsize(struct layer2 *l2)
-{
- return test_bit(FLG_LAPD, &l2->flag) ? 2 : 1;
-}
-
-static u_int
-l2_newid(struct layer2 *l2)
-{
- u_int id;
-
- id = l2->next_id++;
- if (id == 0x7fff)
- l2->next_id = 1;
- id <<= 16;
- id |= l2->tei << 8;
- id |= l2->sapi;
- return id;
-}
-
-static void
-l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb)
-{
- int err;
-
- if (!l2->up)
- return;
- mISDN_HEAD_PRIM(skb) = prim;
- mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr;
- err = l2->up->send(l2->up, skb);
- if (err) {
- printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
- mISDNDevName4ch(&l2->ch), err);
- dev_kfree_skb(skb);
- }
-}
-
-static void
-l2up_create(struct layer2 *l2, u_int prim, int len, void *arg)
-{
- struct sk_buff *skb;
- struct mISDNhead *hh;
- int err;
-
- if (!l2->up)
- return;
- skb = mI_alloc_skb(len, GFP_ATOMIC);
- if (!skb)
- return;
- hh = mISDN_HEAD_P(skb);
- hh->prim = prim;
- hh->id = (l2->ch.nr << 16) | l2->ch.addr;
- if (len)
- skb_put_data(skb, arg, len);
- err = l2->up->send(l2->up, skb);
- if (err) {
- printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
- mISDNDevName4ch(&l2->ch), err);
- dev_kfree_skb(skb);
- }
-}
-
-static int
-l2down_skb(struct layer2 *l2, struct sk_buff *skb) {
- int ret;
-
- ret = l2->ch.recv(l2->ch.peer, skb);
- if (ret && (*debug & DEBUG_L2_RECV))
- printk(KERN_DEBUG "l2down_skb: dev %s ret(%d)\n",
- mISDNDevName4ch(&l2->ch), ret);
- return ret;
-}
-
-static int
-l2down_raw(struct layer2 *l2, struct sk_buff *skb)
-{
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
-
- if (hh->prim == PH_DATA_REQ) {
- if (test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) {
- skb_queue_tail(&l2->down_queue, skb);
- return 0;
- }
- l2->down_id = mISDN_HEAD_ID(skb);
- }
- return l2down_skb(l2, skb);
-}
-
-static int
-l2down(struct layer2 *l2, u_int prim, u_int id, struct sk_buff *skb)
-{
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
-
- hh->prim = prim;
- hh->id = id;
- return l2down_raw(l2, skb);
-}
-
-static int
-l2down_create(struct layer2 *l2, u_int prim, u_int id, int len, void *arg)
-{
- struct sk_buff *skb;
- int err;
- struct mISDNhead *hh;
-
- skb = mI_alloc_skb(len, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
- hh = mISDN_HEAD_P(skb);
- hh->prim = prim;
- hh->id = id;
- if (len)
- skb_put_data(skb, arg, len);
- err = l2down_raw(l2, skb);
- if (err)
- dev_kfree_skb(skb);
- return err;
-}
-
-static int
-ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) {
- struct sk_buff *nskb = skb;
- int ret = -EAGAIN;
-
- if (test_bit(FLG_L1_NOTREADY, &l2->flag)) {
- if (hh->id == l2->down_id) {
- nskb = skb_dequeue(&l2->down_queue);
- if (nskb) {
- l2->down_id = mISDN_HEAD_ID(nskb);
- if (l2down_skb(l2, nskb)) {
- dev_kfree_skb(nskb);
- l2->down_id = MISDN_ID_NONE;
- }
- } else
- l2->down_id = MISDN_ID_NONE;
- if (ret) {
- dev_kfree_skb(skb);
- ret = 0;
- }
- if (l2->down_id == MISDN_ID_NONE) {
- test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
- mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
- }
- }
- }
- if (!test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) {
- nskb = skb_dequeue(&l2->down_queue);
- if (nskb) {
- l2->down_id = mISDN_HEAD_ID(nskb);
- if (l2down_skb(l2, nskb)) {
- dev_kfree_skb(nskb);
- l2->down_id = MISDN_ID_NONE;
- test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
- }
- } else
- test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag);
- }
- return ret;
-}
-
-static void
-l2_timeout(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb;
- struct mISDNhead *hh;
-
- skb = mI_alloc_skb(0, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_WARNING "%s: L2(%d,%d) nr:%x timer %s no skb\n",
- mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
- l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
- return;
- }
- hh = mISDN_HEAD_P(skb);
- hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND;
- hh->id = l2->ch.nr;
- if (*debug & DEBUG_TIMER)
- printk(KERN_DEBUG "%s: L2(%d,%d) nr:%x timer %s expired\n",
- mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
- l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
- if (l2->ch.st)
- l2->ch.st->own.recv(&l2->ch.st->own, skb);
-}
-
-static int
-l2mgr(struct layer2 *l2, u_int prim, void *arg) {
- long c = (long)arg;
-
- printk(KERN_WARNING "l2mgr: dev %s addr:%x prim %x %c\n",
- mISDNDevName4ch(&l2->ch), l2->id, prim, (char)c);
- if (test_bit(FLG_LAPD, &l2->flag) &&
- !test_bit(FLG_FIXED_TEI, &l2->flag)) {
- switch (c) {
- case 'C':
- case 'D':
- case 'G':
- case 'H':
- l2_tei(l2, prim, (u_long)arg);
- break;
- }
- }
- return 0;
-}
-
-static void
-set_peer_busy(struct layer2 *l2) {
- test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
- if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue))
- test_and_set_bit(FLG_L2BLOCK, &l2->flag);
-}
-
-static void
-clear_peer_busy(struct layer2 *l2) {
- if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag))
- test_and_clear_bit(FLG_L2BLOCK, &l2->flag);
-}
-
-static void
-InitWin(struct layer2 *l2)
-{
- int i;
-
- for (i = 0; i < MAX_WINDOW; i++)
- l2->windowar[i] = NULL;
-}
-
-static int
-freewin(struct layer2 *l2)
-{
- int i, cnt = 0;
-
- for (i = 0; i < MAX_WINDOW; i++) {
- if (l2->windowar[i]) {
- cnt++;
- dev_kfree_skb(l2->windowar[i]);
- l2->windowar[i] = NULL;
- }
- }
- return cnt;
-}
-
-static void
-ReleaseWin(struct layer2 *l2)
-{
- int cnt = freewin(l2);
-
- if (cnt)
- printk(KERN_WARNING
- "isdnl2 freed %d skbuffs in release\n", cnt);
-}
-
-inline unsigned int
-cansend(struct layer2 *l2)
-{
- unsigned int p1;
-
- if (test_bit(FLG_MOD128, &l2->flag))
- p1 = (l2->vs - l2->va) % 128;
- else
- p1 = (l2->vs - l2->va) % 8;
- return (p1 < l2->window) && !test_bit(FLG_PEER_BUSY, &l2->flag);
-}
-
-inline void
-clear_exception(struct layer2 *l2)
-{
- test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
- test_and_clear_bit(FLG_REJEXC, &l2->flag);
- test_and_clear_bit(FLG_OWN_BUSY, &l2->flag);
- clear_peer_busy(l2);
-}
-
-static int
-sethdraddr(struct layer2 *l2, u_char *header, int rsp)
-{
- u_char *ptr = header;
- int crbit = rsp;
-
- if (test_bit(FLG_LAPD, &l2->flag)) {
- if (test_bit(FLG_LAPD_NET, &l2->flag))
- crbit = !crbit;
- *ptr++ = (l2->sapi << 2) | (crbit ? 2 : 0);
- *ptr++ = (l2->tei << 1) | 1;
- return 2;
- } else {
- if (test_bit(FLG_ORIG, &l2->flag))
- crbit = !crbit;
- if (crbit)
- *ptr++ = l2->addr.B;
- else
- *ptr++ = l2->addr.A;
- return 1;
- }
-}
-
-static inline void
-enqueue_super(struct layer2 *l2, struct sk_buff *skb)
-{
- if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb))
- dev_kfree_skb(skb);
-}
-
-static inline void
-enqueue_ui(struct layer2 *l2, struct sk_buff *skb)
-{
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_UI_IND, 0);
- if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb))
- dev_kfree_skb(skb);
-}
-
-inline int
-IsUI(u_char *data)
-{
- return (data[0] & 0xef) == UI;
-}
-
-inline int
-IsUA(u_char *data)
-{
- return (data[0] & 0xef) == UA;
-}
-
-inline int
-IsDM(u_char *data)
-{
- return (data[0] & 0xef) == DM;
-}
-
-inline int
-IsDISC(u_char *data)
-{
- return (data[0] & 0xef) == DISC;
-}
-
-inline int
-IsRR(u_char *data, struct layer2 *l2)
-{
- if (test_bit(FLG_MOD128, &l2->flag))
- return data[0] == RR;
- else
- return (data[0] & 0xf) == 1;
-}
-
-inline int
-IsSFrame(u_char *data, struct layer2 *l2)
-{
- register u_char d = *data;
-
- if (!test_bit(FLG_MOD128, &l2->flag))
- d &= 0xf;
- return ((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c);
-}
-
-inline int
-IsSABME(u_char *data, struct layer2 *l2)
-{
- u_char d = data[0] & ~0x10;
-
- return test_bit(FLG_MOD128, &l2->flag) ? d == SABME : d == SABM;
-}
-
-inline int
-IsREJ(u_char *data, struct layer2 *l2)
-{
- return test_bit(FLG_MOD128, &l2->flag) ?
- data[0] == REJ : (data[0] & 0xf) == REJ;
-}
-
-inline int
-IsFRMR(u_char *data)
-{
- return (data[0] & 0xef) == FRMR;
-}
-
-inline int
-IsRNR(u_char *data, struct layer2 *l2)
-{
- return test_bit(FLG_MOD128, &l2->flag) ?
- data[0] == RNR : (data[0] & 0xf) == RNR;
-}
-
-static int
-iframe_error(struct layer2 *l2, struct sk_buff *skb)
-{
- u_int i;
- int rsp = *skb->data & 0x2;
-
- i = l2addrsize(l2) + (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1);
- if (test_bit(FLG_ORIG, &l2->flag))
- rsp = !rsp;
- if (rsp)
- return 'L';
- if (skb->len < i)
- return 'N';
- if ((skb->len - i) > l2->maxlen)
- return 'O';
- return 0;
-}
-
-static int
-super_error(struct layer2 *l2, struct sk_buff *skb)
-{
- if (skb->len != l2addrsize(l2) +
- (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1))
- return 'N';
- return 0;
-}
-
-static int
-unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp)
-{
- int rsp = (*skb->data & 0x2) >> 1;
- if (test_bit(FLG_ORIG, &l2->flag))
- rsp = !rsp;
- if (rsp != wantrsp)
- return 'L';
- if (skb->len != l2addrsize(l2) + 1)
- return 'N';
- return 0;
-}
-
-static int
-UI_error(struct layer2 *l2, struct sk_buff *skb)
-{
- int rsp = *skb->data & 0x2;
- if (test_bit(FLG_ORIG, &l2->flag))
- rsp = !rsp;
- if (rsp)
- return 'L';
- if (skb->len > l2->maxlen + l2addrsize(l2) + 1)
- return 'O';
- return 0;
-}
-
-static int
-FRMR_error(struct layer2 *l2, struct sk_buff *skb)
-{
- u_int headers = l2addrsize(l2) + 1;
- u_char *datap = skb->data + headers;
- int rsp = *skb->data & 0x2;
-
- if (test_bit(FLG_ORIG, &l2->flag))
- rsp = !rsp;
- if (!rsp)
- return 'L';
- if (test_bit(FLG_MOD128, &l2->flag)) {
- if (skb->len < headers + 5)
- return 'N';
- else if (*debug & DEBUG_L2)
- l2m_debug(&l2->l2m,
- "FRMR information %2x %2x %2x %2x %2x",
- datap[0], datap[1], datap[2], datap[3], datap[4]);
- } else {
- if (skb->len < headers + 3)
- return 'N';
- else if (*debug & DEBUG_L2)
- l2m_debug(&l2->l2m,
- "FRMR information %2x %2x %2x",
- datap[0], datap[1], datap[2]);
- }
- return 0;
-}
-
-static unsigned int
-legalnr(struct layer2 *l2, unsigned int nr)
-{
- if (test_bit(FLG_MOD128, &l2->flag))
- return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128);
- else
- return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8);
-}
-
-static void
-setva(struct layer2 *l2, unsigned int nr)
-{
- struct sk_buff *skb;
-
- while (l2->va != nr) {
- l2->va++;
- if (test_bit(FLG_MOD128, &l2->flag))
- l2->va %= 128;
- else
- l2->va %= 8;
- if (l2->windowar[l2->sow]) {
- skb_trim(l2->windowar[l2->sow], 0);
- skb_queue_tail(&l2->tmp_queue, l2->windowar[l2->sow]);
- l2->windowar[l2->sow] = NULL;
- }
- l2->sow = (l2->sow + 1) % l2->window;
- }
- skb = skb_dequeue(&l2->tmp_queue);
- while (skb) {
- dev_kfree_skb(skb);
- skb = skb_dequeue(&l2->tmp_queue);
- }
-}
-
-static void
-send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr)
-{
- u_char tmp[MAX_L2HEADER_LEN];
- int i;
-
- i = sethdraddr(l2, tmp, cr);
- tmp[i++] = cmd;
- if (skb)
- skb_trim(skb, 0);
- else {
- skb = mI_alloc_skb(i, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_WARNING "%s: can't alloc skbuff in %s\n",
- mISDNDevName4ch(&l2->ch), __func__);
- return;
- }
- }
- skb_put_data(skb, tmp, i);
- enqueue_super(l2, skb);
-}
-
-
-inline u_char
-get_PollFlag(struct layer2 *l2, struct sk_buff *skb)
-{
- return skb->data[l2addrsize(l2)] & 0x10;
-}
-
-inline u_char
-get_PollFlagFree(struct layer2 *l2, struct sk_buff *skb)
-{
- u_char PF;
-
- PF = get_PollFlag(l2, skb);
- dev_kfree_skb(skb);
- return PF;
-}
-
-inline void
-start_t200(struct layer2 *l2, int i)
-{
- mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
- test_and_set_bit(FLG_T200_RUN, &l2->flag);
-}
-
-inline void
-restart_t200(struct layer2 *l2, int i)
-{
- mISDN_FsmRestartTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
- test_and_set_bit(FLG_T200_RUN, &l2->flag);
-}
-
-inline void
-stop_t200(struct layer2 *l2, int i)
-{
- if (test_and_clear_bit(FLG_T200_RUN, &l2->flag))
- mISDN_FsmDelTimer(&l2->t200, i);
-}
-
-inline void
-st5_dl_release_l2l3(struct layer2 *l2)
-{
- int pr;
-
- if (test_and_clear_bit(FLG_PEND_REL, &l2->flag))
- pr = DL_RELEASE_CNF;
- else
- pr = DL_RELEASE_IND;
- l2up_create(l2, pr, 0, NULL);
-}
-
-inline void
-lapb_dl_release_l2l3(struct layer2 *l2, int f)
-{
- if (test_bit(FLG_LAPB, &l2->flag))
- l2down_create(l2, PH_DEACTIVATE_REQ, l2_newid(l2), 0, NULL);
- l2up_create(l2, f, 0, NULL);
-}
-
-static void
-establishlink(struct FsmInst *fi)
-{
- struct layer2 *l2 = fi->userdata;
- u_char cmd;
-
- clear_exception(l2);
- l2->rc = 0;
- cmd = (test_bit(FLG_MOD128, &l2->flag) ? SABME : SABM) | 0x10;
- send_uframe(l2, NULL, cmd, CMD);
- mISDN_FsmDelTimer(&l2->t203, 1);
- restart_t200(l2, 1);
- test_and_clear_bit(FLG_PEND_REL, &l2->flag);
- freewin(l2);
- mISDN_FsmChangeState(fi, ST_L2_5);
-}
-
-static void
-l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg)
-{
- struct sk_buff *skb = arg;
- struct layer2 *l2 = fi->userdata;
-
- if (get_PollFlagFree(l2, skb))
- l2mgr(l2, MDL_ERROR_IND, (void *) 'C');
- else
- l2mgr(l2, MDL_ERROR_IND, (void *) 'D');
-
-}
-
-static void
-l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
-{
- struct sk_buff *skb = arg;
- struct layer2 *l2 = fi->userdata;
-
- if (get_PollFlagFree(l2, skb))
- l2mgr(l2, MDL_ERROR_IND, (void *) 'B');
- else {
- l2mgr(l2, MDL_ERROR_IND, (void *) 'E');
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &l2->flag);
- }
-}
-
-static void
-l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
-{
- struct sk_buff *skb = arg;
- struct layer2 *l2 = fi->userdata;
-
- if (get_PollFlagFree(l2, skb))
- l2mgr(l2, MDL_ERROR_IND, (void *) 'B');
- else
- l2mgr(l2, MDL_ERROR_IND, (void *) 'E');
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &l2->flag);
-}
-
-static void
-l2_go_st3(struct FsmInst *fi, int event, void *arg)
-{
- dev_kfree_skb((struct sk_buff *)arg);
- mISDN_FsmChangeState(fi, ST_L2_3);
-}
-
-static void
-l2_mdl_assign(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- mISDN_FsmChangeState(fi, ST_L2_3);
- dev_kfree_skb((struct sk_buff *)arg);
- l2_tei(l2, MDL_ASSIGN_IND, 0);
-}
-
-static void
-l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_tail(&l2->ui_queue, skb);
- mISDN_FsmChangeState(fi, ST_L2_2);
- l2_tei(l2, MDL_ASSIGN_IND, 0);
-}
-
-static void
-l2_queue_ui(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_tail(&l2->ui_queue, skb);
-}
-
-static void
-tx_ui(struct layer2 *l2)
-{
- struct sk_buff *skb;
- u_char header[MAX_L2HEADER_LEN];
- int i;
-
- i = sethdraddr(l2, header, CMD);
- if (test_bit(FLG_LAPD_NET, &l2->flag))
- header[1] = 0xff; /* tei 127 */
- header[i++] = UI;
- while ((skb = skb_dequeue(&l2->ui_queue))) {
- memcpy(skb_push(skb, i), header, i);
- enqueue_ui(l2, skb);
- }
-}
-
-static void
-l2_send_ui(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_tail(&l2->ui_queue, skb);
- tx_ui(l2);
-}
-
-static void
-l2_got_ui(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_pull(skb, l2headersize(l2, 1));
-/*
- * in states 1-3 for broadcast
- */
-
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_UI_IND, 0);
- l2up(l2, DL_UNITDATA_IND, skb);
-}
-
-static void
-l2_establish(struct FsmInst *fi, int event, void *arg)
-{
- struct sk_buff *skb = arg;
- struct layer2 *l2 = fi->userdata;
-
- establishlink(fi);
- test_and_set_bit(FLG_L3_INIT, &l2->flag);
- dev_kfree_skb(skb);
-}
-
-static void
-l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg)
-{
- struct sk_buff *skb = arg;
- struct layer2 *l2 = fi->userdata;
-
- skb_queue_purge(&l2->i_queue);
- test_and_set_bit(FLG_L3_INIT, &l2->flag);
- test_and_clear_bit(FLG_PEND_REL, &l2->flag);
- dev_kfree_skb(skb);
-}
-
-static void
-l2_l3_reestablish(struct FsmInst *fi, int event, void *arg)
-{
- struct sk_buff *skb = arg;
- struct layer2 *l2 = fi->userdata;
-
- skb_queue_purge(&l2->i_queue);
- establishlink(fi);
- test_and_set_bit(FLG_L3_INIT, &l2->flag);
- dev_kfree_skb(skb);
-}
-
-static void
-l2_release(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_trim(skb, 0);
- l2up(l2, DL_RELEASE_CNF, skb);
-}
-
-static void
-l2_pend_rel(struct FsmInst *fi, int event, void *arg)
-{
- struct sk_buff *skb = arg;
- struct layer2 *l2 = fi->userdata;
-
- test_and_set_bit(FLG_PEND_REL, &l2->flag);
- dev_kfree_skb(skb);
-}
-
-static void
-l2_disconnect(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_purge(&l2->i_queue);
- freewin(l2);
- mISDN_FsmChangeState(fi, ST_L2_6);
- l2->rc = 0;
- send_uframe(l2, NULL, DISC | 0x10, CMD);
- mISDN_FsmDelTimer(&l2->t203, 1);
- restart_t200(l2, 2);
- dev_kfree_skb(skb);
-}
-
-static void
-l2_start_multi(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- l2->vs = 0;
- l2->va = 0;
- l2->vr = 0;
- l2->sow = 0;
- clear_exception(l2);
- send_uframe(l2, NULL, UA | get_PollFlag(l2, skb), RSP);
- mISDN_FsmChangeState(fi, ST_L2_7);
- mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
- skb_trim(skb, 0);
- l2up(l2, DL_ESTABLISH_IND, skb);
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_UP_IND, 0);
-}
-
-static void
-l2_send_UA(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
-}
-
-static void
-l2_send_DM(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- send_uframe(l2, skb, DM | get_PollFlag(l2, skb), RSP);
-}
-
-static void
-l2_restart_multi(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
- int est = 0;
-
- send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
-
- l2mgr(l2, MDL_ERROR_IND, (void *) 'F');
-
- if (l2->vs != l2->va) {
- skb_queue_purge(&l2->i_queue);
- est = 1;
- }
-
- clear_exception(l2);
- l2->vs = 0;
- l2->va = 0;
- l2->vr = 0;
- l2->sow = 0;
- mISDN_FsmChangeState(fi, ST_L2_7);
- stop_t200(l2, 3);
- mISDN_FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
-
- if (est)
- l2up_create(l2, DL_ESTABLISH_IND, 0, NULL);
-/* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
- * MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED,
- * 0, NULL, 0);
- */
- if (skb_queue_len(&l2->i_queue) && cansend(l2))
- mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
-}
-
-static void
-l2_stop_multi(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- mISDN_FsmChangeState(fi, ST_L2_4);
- mISDN_FsmDelTimer(&l2->t203, 3);
- stop_t200(l2, 4);
-
- send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
- skb_queue_purge(&l2->i_queue);
- freewin(l2);
- lapb_dl_release_l2l3(l2, DL_RELEASE_IND);
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
-}
-
-static void
-l2_connected(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
- int pr = -1;
-
- if (!get_PollFlag(l2, skb)) {
- l2_mdl_error_ua(fi, event, arg);
- return;
- }
- dev_kfree_skb(skb);
- if (test_and_clear_bit(FLG_PEND_REL, &l2->flag))
- l2_disconnect(fi, event, NULL);
- if (test_and_clear_bit(FLG_L3_INIT, &l2->flag)) {
- pr = DL_ESTABLISH_CNF;
- } else if (l2->vs != l2->va) {
- skb_queue_purge(&l2->i_queue);
- pr = DL_ESTABLISH_IND;
- }
- stop_t200(l2, 5);
- l2->vr = 0;
- l2->vs = 0;
- l2->va = 0;
- l2->sow = 0;
- mISDN_FsmChangeState(fi, ST_L2_7);
- mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4);
- if (pr != -1)
- l2up_create(l2, pr, 0, NULL);
-
- if (skb_queue_len(&l2->i_queue) && cansend(l2))
- mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
-
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_UP_IND, 0);
-}
-
-static void
-l2_released(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (!get_PollFlag(l2, skb)) {
- l2_mdl_error_ua(fi, event, arg);
- return;
- }
- dev_kfree_skb(skb);
- stop_t200(l2, 6);
- lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
- mISDN_FsmChangeState(fi, ST_L2_4);
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
-}
-
-static void
-l2_reestablish(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (!get_PollFlagFree(l2, skb)) {
- establishlink(fi);
- test_and_set_bit(FLG_L3_INIT, &l2->flag);
- }
-}
-
-static void
-l2_st5_dm_release(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (get_PollFlagFree(l2, skb)) {
- stop_t200(l2, 7);
- if (!test_bit(FLG_L3_INIT, &l2->flag))
- skb_queue_purge(&l2->i_queue);
- if (test_bit(FLG_LAPB, &l2->flag))
- l2down_create(l2, PH_DEACTIVATE_REQ,
- l2_newid(l2), 0, NULL);
- st5_dl_release_l2l3(l2);
- mISDN_FsmChangeState(fi, ST_L2_4);
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
- }
-}
-
-static void
-l2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (get_PollFlagFree(l2, skb)) {
- stop_t200(l2, 8);
- lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
- mISDN_FsmChangeState(fi, ST_L2_4);
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
- }
-}
-
-static void
-enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf)
-{
- struct sk_buff *skb;
- u_char tmp[MAX_L2HEADER_LEN];
- int i;
-
- i = sethdraddr(l2, tmp, cr);
- if (test_bit(FLG_MOD128, &l2->flag)) {
- tmp[i++] = typ;
- tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
- } else
- tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
- skb = mI_alloc_skb(i, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_WARNING "%s: isdnl2 can't alloc sbbuff in %s\n",
- mISDNDevName4ch(&l2->ch), __func__);
- return;
- }
- skb_put_data(skb, tmp, i);
- enqueue_super(l2, skb);
-}
-
-inline void
-enquiry_response(struct layer2 *l2)
-{
- if (test_bit(FLG_OWN_BUSY, &l2->flag))
- enquiry_cr(l2, RNR, RSP, 1);
- else
- enquiry_cr(l2, RR, RSP, 1);
- test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
-}
-
-inline void
-transmit_enquiry(struct layer2 *l2)
-{
- if (test_bit(FLG_OWN_BUSY, &l2->flag))
- enquiry_cr(l2, RNR, CMD, 1);
- else
- enquiry_cr(l2, RR, CMD, 1);
- test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
- start_t200(l2, 9);
-}
-
-
-static void
-nrerrorrecovery(struct FsmInst *fi)
-{
- struct layer2 *l2 = fi->userdata;
-
- l2mgr(l2, MDL_ERROR_IND, (void *) 'J');
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &l2->flag);
-}
-
-static void
-invoke_retransmission(struct layer2 *l2, unsigned int nr)
-{
- u_int p1;
-
- if (l2->vs != nr) {
- while (l2->vs != nr) {
- (l2->vs)--;
- if (test_bit(FLG_MOD128, &l2->flag)) {
- l2->vs %= 128;
- p1 = (l2->vs - l2->va) % 128;
- } else {
- l2->vs %= 8;
- p1 = (l2->vs - l2->va) % 8;
- }
- p1 = (p1 + l2->sow) % l2->window;
- if (l2->windowar[p1])
- skb_queue_head(&l2->i_queue, l2->windowar[p1]);
- else
- printk(KERN_WARNING
- "%s: windowar[%d] is NULL\n",
- mISDNDevName4ch(&l2->ch), p1);
- l2->windowar[p1] = NULL;
- }
- mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
- }
-}
-
-static void
-l2_st7_got_super(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
- int PollFlag, rsp, typ = RR;
- unsigned int nr;
-
- rsp = *skb->data & 0x2;
- if (test_bit(FLG_ORIG, &l2->flag))
- rsp = !rsp;
-
- skb_pull(skb, l2addrsize(l2));
- if (IsRNR(skb->data, l2)) {
- set_peer_busy(l2);
- typ = RNR;
- } else
- clear_peer_busy(l2);
- if (IsREJ(skb->data, l2))
- typ = REJ;
-
- if (test_bit(FLG_MOD128, &l2->flag)) {
- PollFlag = (skb->data[1] & 0x1) == 0x1;
- nr = skb->data[1] >> 1;
- } else {
- PollFlag = (skb->data[0] & 0x10);
- nr = (skb->data[0] >> 5) & 0x7;
- }
- dev_kfree_skb(skb);
-
- if (PollFlag) {
- if (rsp)
- l2mgr(l2, MDL_ERROR_IND, (void *) 'A');
- else
- enquiry_response(l2);
- }
- if (legalnr(l2, nr)) {
- if (typ == REJ) {
- setva(l2, nr);
- invoke_retransmission(l2, nr);
- stop_t200(l2, 10);
- if (mISDN_FsmAddTimer(&l2->t203, l2->T203,
- EV_L2_T203, NULL, 6))
- l2m_debug(&l2->l2m, "Restart T203 ST7 REJ");
- } else if ((nr == l2->vs) && (typ == RR)) {
- setva(l2, nr);
- stop_t200(l2, 11);
- mISDN_FsmRestartTimer(&l2->t203, l2->T203,
- EV_L2_T203, NULL, 7);
- } else if ((l2->va != nr) || (typ == RNR)) {
- setva(l2, nr);
- if (typ != RR)
- mISDN_FsmDelTimer(&l2->t203, 9);
- restart_t200(l2, 12);
- }
- if (skb_queue_len(&l2->i_queue) && (typ == RR))
- mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
- } else
- nrerrorrecovery(fi);
-}
-
-static void
-l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (!test_bit(FLG_L3_INIT, &l2->flag))
- skb_queue_tail(&l2->i_queue, skb);
- else
- dev_kfree_skb(skb);
-}
-
-static void
-l2_feed_i_pull(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_tail(&l2->i_queue, skb);
- mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
-}
-
-static void
-l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_tail(&l2->i_queue, skb);
-}
-
-static void
-l2_got_iframe(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
- int PollFlag, i;
- u_int ns, nr;
-
- i = l2addrsize(l2);
- if (test_bit(FLG_MOD128, &l2->flag)) {
- PollFlag = ((skb->data[i + 1] & 0x1) == 0x1);
- ns = skb->data[i] >> 1;
- nr = (skb->data[i + 1] >> 1) & 0x7f;
- } else {
- PollFlag = (skb->data[i] & 0x10);
- ns = (skb->data[i] >> 1) & 0x7;
- nr = (skb->data[i] >> 5) & 0x7;
- }
- if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
- dev_kfree_skb(skb);
- if (PollFlag)
- enquiry_response(l2);
- } else {
- if (l2->vr == ns) {
- l2->vr++;
- if (test_bit(FLG_MOD128, &l2->flag))
- l2->vr %= 128;
- else
- l2->vr %= 8;
- test_and_clear_bit(FLG_REJEXC, &l2->flag);
- if (PollFlag)
- enquiry_response(l2);
- else
- test_and_set_bit(FLG_ACK_PEND, &l2->flag);
- skb_pull(skb, l2headersize(l2, 0));
- l2up(l2, DL_DATA_IND, skb);
- } else {
- /* n(s)!=v(r) */
- dev_kfree_skb(skb);
- if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
- if (PollFlag)
- enquiry_response(l2);
- } else {
- enquiry_cr(l2, REJ, RSP, PollFlag);
- test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
- }
- }
- }
- if (legalnr(l2, nr)) {
- if (!test_bit(FLG_PEER_BUSY, &l2->flag) &&
- (fi->state == ST_L2_7)) {
- if (nr == l2->vs) {
- stop_t200(l2, 13);
- mISDN_FsmRestartTimer(&l2->t203, l2->T203,
- EV_L2_T203, NULL, 7);
- } else if (nr != l2->va)
- restart_t200(l2, 14);
- }
- setva(l2, nr);
- } else {
- nrerrorrecovery(fi);
- return;
- }
- if (skb_queue_len(&l2->i_queue) && (fi->state == ST_L2_7))
- mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
- if (test_and_clear_bit(FLG_ACK_PEND, &l2->flag))
- enquiry_cr(l2, RR, RSP, 0);
-}
-
-static void
-l2_got_tei(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- u_int info;
-
- l2->tei = (signed char)(long)arg;
- set_channel_address(&l2->ch, l2->sapi, l2->tei);
- info = DL_INFO_L2_CONNECT;
- l2up_create(l2, DL_INFORMATION_IND, sizeof(info), &info);
- if (fi->state == ST_L2_3) {
- establishlink(fi);
- test_and_set_bit(FLG_L3_INIT, &l2->flag);
- } else
- mISDN_FsmChangeState(fi, ST_L2_4);
- if (skb_queue_len(&l2->ui_queue))
- tx_ui(l2);
-}
-
-static void
-l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- if (test_bit(FLG_LAPD, &l2->flag) &&
- test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
- mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
- } else if (l2->rc == l2->N200) {
- mISDN_FsmChangeState(fi, ST_L2_4);
- test_and_clear_bit(FLG_T200_RUN, &l2->flag);
- skb_queue_purge(&l2->i_queue);
- l2mgr(l2, MDL_ERROR_IND, (void *) 'G');
- if (test_bit(FLG_LAPB, &l2->flag))
- l2down_create(l2, PH_DEACTIVATE_REQ,
- l2_newid(l2), 0, NULL);
- st5_dl_release_l2l3(l2);
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
- } else {
- l2->rc++;
- mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
- send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ?
- SABME : SABM) | 0x10, CMD);
- }
-}
-
-static void
-l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- if (test_bit(FLG_LAPD, &l2->flag) &&
- test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
- mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
- } else if (l2->rc == l2->N200) {
- mISDN_FsmChangeState(fi, ST_L2_4);
- test_and_clear_bit(FLG_T200_RUN, &l2->flag);
- l2mgr(l2, MDL_ERROR_IND, (void *) 'H');
- lapb_dl_release_l2l3(l2, DL_RELEASE_CNF);
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
- } else {
- l2->rc++;
- mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200,
- NULL, 9);
- send_uframe(l2, NULL, DISC | 0x10, CMD);
- }
-}
-
-static void
-l2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- if (test_bit(FLG_LAPD, &l2->flag) &&
- test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
- mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
- return;
- }
- test_and_clear_bit(FLG_T200_RUN, &l2->flag);
- l2->rc = 0;
- mISDN_FsmChangeState(fi, ST_L2_8);
- transmit_enquiry(l2);
- l2->rc++;
-}
-
-static void
-l2_st8_tout_200(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- if (test_bit(FLG_LAPD, &l2->flag) &&
- test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
- mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
- return;
- }
- test_and_clear_bit(FLG_T200_RUN, &l2->flag);
- if (l2->rc == l2->N200) {
- l2mgr(l2, MDL_ERROR_IND, (void *) 'I');
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &l2->flag);
- } else {
- transmit_enquiry(l2);
- l2->rc++;
- }
-}
-
-static void
-l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- if (test_bit(FLG_LAPD, &l2->flag) &&
- test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
- mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9);
- return;
- }
- mISDN_FsmChangeState(fi, ST_L2_8);
- transmit_enquiry(l2);
- l2->rc = 0;
-}
-
-static void
-l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb, *nskb;
- u_char header[MAX_L2HEADER_LEN];
- u_int i, p1;
-
- if (!cansend(l2))
- return;
-
- skb = skb_dequeue(&l2->i_queue);
- if (!skb)
- return;
- i = sethdraddr(l2, header, CMD);
- if (test_bit(FLG_MOD128, &l2->flag)) {
- header[i++] = l2->vs << 1;
- header[i++] = l2->vr << 1;
- } else
- header[i++] = (l2->vr << 5) | (l2->vs << 1);
- nskb = skb_realloc_headroom(skb, i);
- if (!nskb) {
- printk(KERN_WARNING "%s: no headroom(%d) copy for IFrame\n",
- mISDNDevName4ch(&l2->ch), i);
- skb_queue_head(&l2->i_queue, skb);
- return;
- }
- if (test_bit(FLG_MOD128, &l2->flag)) {
- p1 = (l2->vs - l2->va) % 128;
- l2->vs = (l2->vs + 1) % 128;
- } else {
- p1 = (l2->vs - l2->va) % 8;
- l2->vs = (l2->vs + 1) % 8;
- }
- p1 = (p1 + l2->sow) % l2->window;
- if (l2->windowar[p1]) {
- printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n",
- mISDNDevName4ch(&l2->ch), p1);
- dev_kfree_skb(l2->windowar[p1]);
- }
- l2->windowar[p1] = skb;
- memcpy(skb_push(nskb, i), header, i);
- l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb);
- test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
- if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) {
- mISDN_FsmDelTimer(&l2->t203, 13);
- mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 11);
- }
-}
-
-static void
-l2_st8_got_super(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
- int PollFlag, rsp, rnr = 0;
- unsigned int nr;
-
- rsp = *skb->data & 0x2;
- if (test_bit(FLG_ORIG, &l2->flag))
- rsp = !rsp;
-
- skb_pull(skb, l2addrsize(l2));
-
- if (IsRNR(skb->data, l2)) {
- set_peer_busy(l2);
- rnr = 1;
- } else
- clear_peer_busy(l2);
-
- if (test_bit(FLG_MOD128, &l2->flag)) {
- PollFlag = (skb->data[1] & 0x1) == 0x1;
- nr = skb->data[1] >> 1;
- } else {
- PollFlag = (skb->data[0] & 0x10);
- nr = (skb->data[0] >> 5) & 0x7;
- }
- dev_kfree_skb(skb);
- if (rsp && PollFlag) {
- if (legalnr(l2, nr)) {
- if (rnr) {
- restart_t200(l2, 15);
- } else {
- stop_t200(l2, 16);
- mISDN_FsmAddTimer(&l2->t203, l2->T203,
- EV_L2_T203, NULL, 5);
- setva(l2, nr);
- }
- invoke_retransmission(l2, nr);
- mISDN_FsmChangeState(fi, ST_L2_7);
- if (skb_queue_len(&l2->i_queue) && cansend(l2))
- mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
- } else
- nrerrorrecovery(fi);
- } else {
- if (!rsp && PollFlag)
- enquiry_response(l2);
- if (legalnr(l2, nr))
- setva(l2, nr);
- else
- nrerrorrecovery(fi);
- }
-}
-
-static void
-l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_pull(skb, l2addrsize(l2) + 1);
-
- if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */
- (IsUA(skb->data) && (fi->state == ST_L2_7))) {
- l2mgr(l2, MDL_ERROR_IND, (void *) 'K');
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &l2->flag);
- }
- dev_kfree_skb(skb);
-}
-
-static void
-l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- skb_queue_purge(&l2->ui_queue);
- l2->tei = GROUP_TEI;
- mISDN_FsmChangeState(fi, ST_L2_1);
-}
-
-static void
-l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- skb_queue_purge(&l2->ui_queue);
- l2->tei = GROUP_TEI;
- l2up_create(l2, DL_RELEASE_IND, 0, NULL);
- mISDN_FsmChangeState(fi, ST_L2_1);
-}
-
-static void
-l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- skb_queue_purge(&l2->i_queue);
- skb_queue_purge(&l2->ui_queue);
- freewin(l2);
- l2->tei = GROUP_TEI;
- stop_t200(l2, 17);
- st5_dl_release_l2l3(l2);
- mISDN_FsmChangeState(fi, ST_L2_1);
-}
-
-static void
-l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- skb_queue_purge(&l2->ui_queue);
- l2->tei = GROUP_TEI;
- stop_t200(l2, 18);
- l2up_create(l2, DL_RELEASE_IND, 0, NULL);
- mISDN_FsmChangeState(fi, ST_L2_1);
-}
-
-static void
-l2_tei_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- skb_queue_purge(&l2->i_queue);
- skb_queue_purge(&l2->ui_queue);
- freewin(l2);
- l2->tei = GROUP_TEI;
- stop_t200(l2, 17);
- mISDN_FsmDelTimer(&l2->t203, 19);
- l2up_create(l2, DL_RELEASE_IND, 0, NULL);
-/* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
- * MGR_SHORTSTATUS_IND, SSTATUS_L2_RELEASED,
- * 0, NULL, 0);
- */
- mISDN_FsmChangeState(fi, ST_L2_1);
-}
-
-static void
-l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_purge(&l2->i_queue);
- skb_queue_purge(&l2->ui_queue);
- if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
- l2up(l2, DL_RELEASE_IND, skb);
- else
- dev_kfree_skb(skb);
-}
-
-static void
-l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_purge(&l2->i_queue);
- skb_queue_purge(&l2->ui_queue);
- freewin(l2);
- stop_t200(l2, 19);
- st5_dl_release_l2l3(l2);
- mISDN_FsmChangeState(fi, ST_L2_4);
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
- dev_kfree_skb(skb);
-}
-
-static void
-l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_purge(&l2->ui_queue);
- stop_t200(l2, 20);
- l2up(l2, DL_RELEASE_CNF, skb);
- mISDN_FsmChangeState(fi, ST_L2_4);
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
-}
-
-static void
-l2_persistent_da(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_purge(&l2->i_queue);
- skb_queue_purge(&l2->ui_queue);
- freewin(l2);
- stop_t200(l2, 19);
- mISDN_FsmDelTimer(&l2->t203, 19);
- l2up(l2, DL_RELEASE_IND, skb);
- mISDN_FsmChangeState(fi, ST_L2_4);
- if (l2->tm)
- l2_tei(l2, MDL_STATUS_DOWN_IND, 0);
-}
-
-static void
-l2_set_own_busy(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (!test_and_set_bit(FLG_OWN_BUSY, &l2->flag)) {
- enquiry_cr(l2, RNR, RSP, 0);
- test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
- }
- dev_kfree_skb(skb);
-}
-
-static void
-l2_clear_own_busy(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (!test_and_clear_bit(FLG_OWN_BUSY, &l2->flag)) {
- enquiry_cr(l2, RR, RSP, 0);
- test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
- }
- dev_kfree_skb(skb);
-}
-
-static void
-l2_frame_error(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- l2mgr(l2, MDL_ERROR_IND, arg);
-}
-
-static void
-l2_frame_error_reest(struct FsmInst *fi, int event, void *arg)
-{
- struct layer2 *l2 = fi->userdata;
-
- l2mgr(l2, MDL_ERROR_IND, arg);
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &l2->flag);
-}
-
-static struct FsmNode L2FnList[] =
-{
- {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign},
- {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3},
- {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish},
- {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3},
- {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
- {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
- {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release},
- {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel},
- {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect},
- {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect},
- {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest},
- {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull},
- {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
- {ST_L2_1, EV_L2_DL_UNITDATA, l2_queue_ui_assign},
- {ST_L2_2, EV_L2_DL_UNITDATA, l2_queue_ui},
- {ST_L2_3, EV_L2_DL_UNITDATA, l2_queue_ui},
- {ST_L2_4, EV_L2_DL_UNITDATA, l2_send_ui},
- {ST_L2_5, EV_L2_DL_UNITDATA, l2_send_ui},
- {ST_L2_6, EV_L2_DL_UNITDATA, l2_send_ui},
- {ST_L2_7, EV_L2_DL_UNITDATA, l2_send_ui},
- {ST_L2_8, EV_L2_DL_UNITDATA, l2_send_ui},
- {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei},
- {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei},
- {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
- {ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove},
- {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove},
- {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove},
- {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove},
- {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove},
- {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
- {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
- {ST_L2_4, EV_L2_SABME, l2_start_multi},
- {ST_L2_5, EV_L2_SABME, l2_send_UA},
- {ST_L2_6, EV_L2_SABME, l2_send_DM},
- {ST_L2_7, EV_L2_SABME, l2_restart_multi},
- {ST_L2_8, EV_L2_SABME, l2_restart_multi},
- {ST_L2_4, EV_L2_DISC, l2_send_DM},
- {ST_L2_5, EV_L2_DISC, l2_send_DM},
- {ST_L2_6, EV_L2_DISC, l2_send_UA},
- {ST_L2_7, EV_L2_DISC, l2_stop_multi},
- {ST_L2_8, EV_L2_DISC, l2_stop_multi},
- {ST_L2_4, EV_L2_UA, l2_mdl_error_ua},
- {ST_L2_5, EV_L2_UA, l2_connected},
- {ST_L2_6, EV_L2_UA, l2_released},
- {ST_L2_7, EV_L2_UA, l2_mdl_error_ua},
- {ST_L2_8, EV_L2_UA, l2_mdl_error_ua},
- {ST_L2_4, EV_L2_DM, l2_reestablish},
- {ST_L2_5, EV_L2_DM, l2_st5_dm_release},
- {ST_L2_6, EV_L2_DM, l2_st6_dm_release},
- {ST_L2_7, EV_L2_DM, l2_mdl_error_dm},
- {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm},
- {ST_L2_1, EV_L2_UI, l2_got_ui},
- {ST_L2_2, EV_L2_UI, l2_got_ui},
- {ST_L2_3, EV_L2_UI, l2_got_ui},
- {ST_L2_4, EV_L2_UI, l2_got_ui},
- {ST_L2_5, EV_L2_UI, l2_got_ui},
- {ST_L2_6, EV_L2_UI, l2_got_ui},
- {ST_L2_7, EV_L2_UI, l2_got_ui},
- {ST_L2_8, EV_L2_UI, l2_got_ui},
- {ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
- {ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
- {ST_L2_7, EV_L2_SUPER, l2_st7_got_super},
- {ST_L2_8, EV_L2_SUPER, l2_st8_got_super},
- {ST_L2_7, EV_L2_I, l2_got_iframe},
- {ST_L2_8, EV_L2_I, l2_got_iframe},
- {ST_L2_5, EV_L2_T200, l2_timeout},
- {ST_L2_6, EV_L2_T200, l2_timeout},
- {ST_L2_7, EV_L2_T200, l2_timeout},
- {ST_L2_8, EV_L2_T200, l2_timeout},
- {ST_L2_7, EV_L2_T203, l2_timeout},
- {ST_L2_5, EV_L2_T200I, l2_st5_tout_200},
- {ST_L2_6, EV_L2_T200I, l2_st6_tout_200},
- {ST_L2_7, EV_L2_T200I, l2_st7_tout_200},
- {ST_L2_8, EV_L2_T200I, l2_st8_tout_200},
- {ST_L2_7, EV_L2_T203I, l2_st7_tout_203},
- {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
- {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
- {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
- {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
- {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
- {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error},
- {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error},
- {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error},
- {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest},
- {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest},
- {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da},
- {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove},
- {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove},
- {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da},
- {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da},
- {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da},
- {ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da},
- {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da},
-};
-
-static int
-ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
-{
- u_char *datap = skb->data;
- int ret = -EINVAL;
- int psapi, ptei;
- u_int l;
- int c = 0;
-
- l = l2addrsize(l2);
- if (skb->len <= l) {
- mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *) 'N');
- return ret;
- }
- if (test_bit(FLG_LAPD, &l2->flag)) { /* Maybe not needed */
- psapi = *datap++;
- ptei = *datap++;
- if ((psapi & 1) || !(ptei & 1)) {
- printk(KERN_WARNING
- "%s l2 D-channel frame wrong EA0/EA1\n",
- mISDNDevName4ch(&l2->ch));
- return ret;
- }
- psapi >>= 2;
- ptei >>= 1;
- if (psapi != l2->sapi) {
- /* not our business */
- if (*debug & DEBUG_L2)
- printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n",
- mISDNDevName4ch(&l2->ch), psapi,
- l2->sapi);
- dev_kfree_skb(skb);
- return 0;
- }
- if ((ptei != l2->tei) && (ptei != GROUP_TEI)) {
- /* not our business */
- if (*debug & DEBUG_L2)
- printk(KERN_DEBUG "%s: tei %d/%d mismatch\n",
- mISDNDevName4ch(&l2->ch), ptei, l2->tei);
- dev_kfree_skb(skb);
- return 0;
- }
- } else
- datap += l;
- if (!(*datap & 1)) { /* I-Frame */
- c = iframe_error(l2, skb);
- if (!c)
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_I, skb);
- } else if (IsSFrame(datap, l2)) { /* S-Frame */
- c = super_error(l2, skb);
- if (!c)
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SUPER, skb);
- } else if (IsUI(datap)) {
- c = UI_error(l2, skb);
- if (!c)
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UI, skb);
- } else if (IsSABME(datap, l2)) {
- c = unnum_error(l2, skb, CMD);
- if (!c)
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SABME, skb);
- } else if (IsUA(datap)) {
- c = unnum_error(l2, skb, RSP);
- if (!c)
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UA, skb);
- } else if (IsDISC(datap)) {
- c = unnum_error(l2, skb, CMD);
- if (!c)
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DISC, skb);
- } else if (IsDM(datap)) {
- c = unnum_error(l2, skb, RSP);
- if (!c)
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DM, skb);
- } else if (IsFRMR(datap)) {
- c = FRMR_error(l2, skb);
- if (!c)
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_FRMR, skb);
- } else
- c = 'L';
- if (c) {
- printk(KERN_WARNING "%s:l2 D-channel frame error %c\n",
- mISDNDevName4ch(&l2->ch), c);
- mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
- }
- return ret;
-}
-
-static int
-l2_send(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct layer2 *l2 = container_of(ch, struct layer2, ch);
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- int ret = -EINVAL;
-
- if (*debug & DEBUG_L2_RECV)
- printk(KERN_DEBUG "%s: %s prim(%x) id(%x) sapi(%d) tei(%d)\n",
- __func__, mISDNDevName4ch(&l2->ch), hh->prim, hh->id,
- l2->sapi, l2->tei);
- if (hh->prim == DL_INTERN_MSG) {
- struct mISDNhead *chh = hh + 1; /* saved copy */
-
- *hh = *chh;
- if (*debug & DEBUG_L2_RECV)
- printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n",
- mISDNDevName4ch(&l2->ch), hh->prim, hh->id);
- }
- switch (hh->prim) {
- case PH_DATA_IND:
- ret = ph_data_indication(l2, hh, skb);
- break;
- case PH_DATA_CNF:
- ret = ph_data_confirm(l2, hh, skb);
- break;
- case PH_ACTIVATE_IND:
- test_and_set_bit(FLG_L1_ACTIV, &l2->flag);
- l2up_create(l2, MPH_ACTIVATE_IND, 0, NULL);
- if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
- ret = mISDN_FsmEvent(&l2->l2m,
- EV_L2_DL_ESTABLISH_REQ, skb);
- break;
- case PH_DEACTIVATE_IND:
- test_and_clear_bit(FLG_L1_ACTIV, &l2->flag);
- l2up_create(l2, MPH_DEACTIVATE_IND, 0, NULL);
- ret = mISDN_FsmEvent(&l2->l2m, EV_L1_DEACTIVATE, skb);
- break;
- case MPH_INFORMATION_IND:
- if (!l2->up)
- break;
- ret = l2->up->send(l2->up, skb);
- break;
- case DL_DATA_REQ:
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_DATA, skb);
- break;
- case DL_UNITDATA_REQ:
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_UNITDATA, skb);
- break;
- case DL_ESTABLISH_REQ:
- if (test_bit(FLG_LAPB, &l2->flag))
- test_and_set_bit(FLG_ORIG, &l2->flag);
- if (test_bit(FLG_L1_ACTIV, &l2->flag)) {
- if (test_bit(FLG_LAPD, &l2->flag) ||
- test_bit(FLG_ORIG, &l2->flag))
- ret = mISDN_FsmEvent(&l2->l2m,
- EV_L2_DL_ESTABLISH_REQ, skb);
- } else {
- if (test_bit(FLG_LAPD, &l2->flag) ||
- test_bit(FLG_ORIG, &l2->flag)) {
- test_and_set_bit(FLG_ESTAB_PEND,
- &l2->flag);
- }
- ret = l2down(l2, PH_ACTIVATE_REQ, l2_newid(l2),
- skb);
- }
- break;
- case DL_RELEASE_REQ:
- if (test_bit(FLG_LAPB, &l2->flag))
- l2down_create(l2, PH_DEACTIVATE_REQ,
- l2_newid(l2), 0, NULL);
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ,
- skb);
- break;
- case DL_TIMER200_IND:
- mISDN_FsmEvent(&l2->l2m, EV_L2_T200I, NULL);
- break;
- case DL_TIMER203_IND:
- mISDN_FsmEvent(&l2->l2m, EV_L2_T203I, NULL);
- break;
- default:
- if (*debug & DEBUG_L2)
- l2m_debug(&l2->l2m, "l2 unknown pr %04x",
- hh->prim);
- }
- if (ret) {
- dev_kfree_skb(skb);
- ret = 0;
- }
- return ret;
-}
-
-int
-tei_l2(struct layer2 *l2, u_int cmd, u_long arg)
-{
- int ret = -EINVAL;
-
- if (*debug & DEBUG_L2_TEI)
- printk(KERN_DEBUG "%s: cmd(%x) in %s\n",
- mISDNDevName4ch(&l2->ch), cmd, __func__);
- switch (cmd) {
- case (MDL_ASSIGN_REQ):
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg);
- break;
- case (MDL_REMOVE_REQ):
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, NULL);
- break;
- case (MDL_ERROR_IND):
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL);
- break;
- case (MDL_ERROR_RSP):
- /* ETS 300-125 5.3.2.1 Test: TC13010 */
- printk(KERN_NOTICE "%s: MDL_ERROR|REQ (tei_l2)\n",
- mISDNDevName4ch(&l2->ch));
- ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL);
- break;
- }
- return ret;
-}
-
-static void
-release_l2(struct layer2 *l2)
-{
- mISDN_FsmDelTimer(&l2->t200, 21);
- mISDN_FsmDelTimer(&l2->t203, 16);
- skb_queue_purge(&l2->i_queue);
- skb_queue_purge(&l2->ui_queue);
- skb_queue_purge(&l2->down_queue);
- ReleaseWin(l2);
- if (test_bit(FLG_LAPD, &l2->flag)) {
- TEIrelease(l2);
- if (l2->ch.st)
- l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D,
- CLOSE_CHANNEL, NULL);
- }
- kfree(l2);
-}
-
-static int
-l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct layer2 *l2 = container_of(ch, struct layer2, ch);
- u_int info;
-
- if (*debug & DEBUG_L2_CTRL)
- printk(KERN_DEBUG "%s: %s cmd(%x)\n",
- mISDNDevName4ch(ch), __func__, cmd);
-
- switch (cmd) {
- case OPEN_CHANNEL:
- if (test_bit(FLG_LAPD, &l2->flag)) {
- set_channel_address(&l2->ch, l2->sapi, l2->tei);
- info = DL_INFO_L2_CONNECT;
- l2up_create(l2, DL_INFORMATION_IND,
- sizeof(info), &info);
- }
- break;
- case CLOSE_CHANNEL:
- if (l2->ch.peer)
- l2->ch.peer->ctrl(l2->ch.peer, CLOSE_CHANNEL, NULL);
- release_l2(l2);
- break;
- }
- return 0;
-}
-
-struct layer2 *
-create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei,
- int sapi)
-{
- struct layer2 *l2;
- struct channel_req rq;
-
- l2 = kzalloc_obj(struct layer2);
- if (!l2) {
- printk(KERN_ERR "kzalloc layer2 failed\n");
- return NULL;
- }
- l2->next_id = 1;
- l2->down_id = MISDN_ID_NONE;
- l2->up = ch;
- l2->ch.st = ch->st;
- l2->ch.send = l2_send;
- l2->ch.ctrl = l2_ctrl;
- switch (protocol) {
- case ISDN_P_LAPD_NT:
- test_and_set_bit(FLG_LAPD, &l2->flag);
- test_and_set_bit(FLG_LAPD_NET, &l2->flag);
- test_and_set_bit(FLG_MOD128, &l2->flag);
- l2->sapi = sapi;
- l2->maxlen = MAX_DFRAME_LEN;
- if (test_bit(OPTION_L2_PMX, &options))
- l2->window = 7;
- else
- l2->window = 1;
- if (test_bit(OPTION_L2_PTP, &options))
- test_and_set_bit(FLG_PTP, &l2->flag);
- if (test_bit(OPTION_L2_FIXEDTEI, &options))
- test_and_set_bit(FLG_FIXED_TEI, &l2->flag);
- l2->tei = tei;
- l2->T200 = 1000;
- l2->N200 = 3;
- l2->T203 = 10000;
- if (test_bit(OPTION_L2_PMX, &options))
- rq.protocol = ISDN_P_NT_E1;
- else
- rq.protocol = ISDN_P_NT_S0;
- rq.adr.channel = 0;
- l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq);
- break;
- case ISDN_P_LAPD_TE:
- test_and_set_bit(FLG_LAPD, &l2->flag);
- test_and_set_bit(FLG_MOD128, &l2->flag);
- test_and_set_bit(FLG_ORIG, &l2->flag);
- l2->sapi = sapi;
- l2->maxlen = MAX_DFRAME_LEN;
- if (test_bit(OPTION_L2_PMX, &options))
- l2->window = 7;
- else
- l2->window = 1;
- if (test_bit(OPTION_L2_PTP, &options))
- test_and_set_bit(FLG_PTP, &l2->flag);
- if (test_bit(OPTION_L2_FIXEDTEI, &options))
- test_and_set_bit(FLG_FIXED_TEI, &l2->flag);
- l2->tei = tei;
- l2->T200 = 1000;
- l2->N200 = 3;
- l2->T203 = 10000;
- if (test_bit(OPTION_L2_PMX, &options))
- rq.protocol = ISDN_P_TE_E1;
- else
- rq.protocol = ISDN_P_TE_S0;
- rq.adr.channel = 0;
- l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq);
- break;
- case ISDN_P_B_X75SLP:
- test_and_set_bit(FLG_LAPB, &l2->flag);
- l2->window = 7;
- l2->maxlen = MAX_DATA_SIZE;
- l2->T200 = 1000;
- l2->N200 = 4;
- l2->T203 = 5000;
- l2->addr.A = 3;
- l2->addr.B = 1;
- break;
- default:
- printk(KERN_ERR "layer2 create failed prt %x\n",
- protocol);
- kfree(l2);
- return NULL;
- }
- skb_queue_head_init(&l2->i_queue);
- skb_queue_head_init(&l2->ui_queue);
- skb_queue_head_init(&l2->down_queue);
- skb_queue_head_init(&l2->tmp_queue);
- InitWin(l2);
- l2->l2m.fsm = &l2fsm;
- if (test_bit(FLG_LAPB, &l2->flag) ||
- test_bit(FLG_FIXED_TEI, &l2->flag) ||
- test_bit(FLG_LAPD_NET, &l2->flag))
- l2->l2m.state = ST_L2_4;
- else
- l2->l2m.state = ST_L2_1;
- l2->l2m.debug = *debug;
- l2->l2m.userdata = l2;
- l2->l2m.userint = 0;
- l2->l2m.printdebug = l2m_debug;
-
- mISDN_FsmInitTimer(&l2->l2m, &l2->t200);
- mISDN_FsmInitTimer(&l2->l2m, &l2->t203);
- return l2;
-}
-
-static int
-x75create(struct channel_req *crq)
-{
- struct layer2 *l2;
-
- if (crq->protocol != ISDN_P_B_X75SLP)
- return -EPROTONOSUPPORT;
- l2 = create_l2(crq->ch, crq->protocol, 0, 0, 0);
- if (!l2)
- return -ENOMEM;
- crq->ch = &l2->ch;
- crq->protocol = ISDN_P_B_HDLC;
- return 0;
-}
-
-static struct Bprotocol X75SLP = {
- .Bprotocols = (1 << (ISDN_P_B_X75SLP & ISDN_P_B_MASK)),
- .name = "X75SLP",
- .create = x75create
-};
-
-int
-Isdnl2_Init(u_int *deb)
-{
- int res;
- debug = deb;
- mISDN_register_Bprotocol(&X75SLP);
- l2fsm.state_count = L2_STATE_COUNT;
- l2fsm.event_count = L2_EVENT_COUNT;
- l2fsm.strEvent = strL2Event;
- l2fsm.strState = strL2State;
- res = mISDN_FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList));
- if (res)
- goto error;
- res = TEIInit(deb);
- if (res)
- goto error_fsm;
- return 0;
-
-error_fsm:
- mISDN_FsmFree(&l2fsm);
-error:
- mISDN_unregister_Bprotocol(&X75SLP);
- return res;
-}
-
-void
-Isdnl2_cleanup(void)
-{
- mISDN_unregister_Bprotocol(&X75SLP);
- TEIFree();
- mISDN_FsmFree(&l2fsm);
-}
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Layer 2 defines
- *
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#include <linux/mISDNif.h>
-#include <linux/skbuff.h>
-#include "fsm.h"
-
-#define MAX_WINDOW 8
-
-struct manager {
- struct mISDNchannel ch;
- struct mISDNchannel bcast;
- u_long options;
- struct list_head layer2;
- rwlock_t lock;
- struct FsmInst deact;
- struct FsmTimer datimer;
- struct sk_buff_head sendq;
- struct mISDNchannel *up;
- u_int nextid;
- u_int lastid;
-};
-
-struct teimgr {
- int ri;
- int rcnt;
- struct FsmInst tei_m;
- struct FsmTimer timer;
- int tval, nval;
- struct layer2 *l2;
- struct manager *mgr;
-};
-
-struct laddr {
- u_char A;
- u_char B;
-};
-
-struct layer2 {
- struct list_head list;
- struct mISDNchannel ch;
- u_long flag;
- int id;
- struct mISDNchannel *up;
- signed char sapi;
- signed char tei;
- struct laddr addr;
- u_int maxlen;
- struct teimgr *tm;
- u_int vs, va, vr;
- int rc;
- u_int window;
- u_int sow;
- struct FsmInst l2m;
- struct FsmTimer t200, t203;
- int T200, N200, T203;
- u_int next_id;
- u_int down_id;
- struct sk_buff *windowar[MAX_WINDOW];
- struct sk_buff_head i_queue;
- struct sk_buff_head ui_queue;
- struct sk_buff_head down_queue;
- struct sk_buff_head tmp_queue;
-};
-
-enum {
- ST_L2_1,
- ST_L2_2,
- ST_L2_3,
- ST_L2_4,
- ST_L2_5,
- ST_L2_6,
- ST_L2_7,
- ST_L2_8,
-};
-
-#define L2_STATE_COUNT (ST_L2_8 + 1)
-
-extern struct layer2 *create_l2(struct mISDNchannel *, u_int,
- u_long, int, int);
-extern int tei_l2(struct layer2 *, u_int, u_long arg);
-
-
-/* from tei.c */
-extern int l2_tei(struct layer2 *, u_int, u_long arg);
-extern void TEIrelease(struct layer2 *);
-extern int TEIInit(u_int *);
-extern void TEIFree(void);
-
-#define MAX_L2HEADER_LEN 4
-
-#define RR 0x01
-#define RNR 0x05
-#define REJ 0x09
-#define SABME 0x6f
-#define SABM 0x2f
-#define DM 0x0f
-#define UI 0x03
-#define DISC 0x43
-#define UA 0x63
-#define FRMR 0x87
-#define XID 0xaf
-
-#define CMD 0
-#define RSP 1
-
-#define LC_FLUSH_WAIT 1
-
-#define FLG_LAPB 0
-#define FLG_LAPD 1
-#define FLG_ORIG 2
-#define FLG_MOD128 3
-#define FLG_PEND_REL 4
-#define FLG_L3_INIT 5
-#define FLG_T200_RUN 6
-#define FLG_ACK_PEND 7
-#define FLG_REJEXC 8
-#define FLG_OWN_BUSY 9
-#define FLG_PEER_BUSY 10
-#define FLG_DCHAN_BUSY 11
-#define FLG_L1_ACTIV 12
-#define FLG_ESTAB_PEND 13
-#define FLG_PTP 14
-#define FLG_FIXED_TEI 15
-#define FLG_L2BLOCK 16
-#define FLG_L1_NOTREADY 17
-#define FLG_LAPD_NET 18
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *
- * Author Karsten Keil <kkeil@novell.com>
- *
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#include <linux/mISDNif.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include "core.h"
-
-static u_int *debug;
-
-static struct proto mISDN_proto = {
- .name = "misdn",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct mISDN_sock)
-};
-
-#define _pms(sk) ((struct mISDN_sock *)sk)
-
-static struct mISDN_sock_list data_sockets = {
- .lock = __RW_LOCK_UNLOCKED(data_sockets.lock)
-};
-
-static struct mISDN_sock_list base_sockets = {
- .lock = __RW_LOCK_UNLOCKED(base_sockets.lock)
-};
-
-#define L2_HEADER_LEN 4
-
-static inline struct sk_buff *
-_l2_alloc_skb(unsigned int len, gfp_t gfp_mask)
-{
- struct sk_buff *skb;
-
- skb = alloc_skb(len + L2_HEADER_LEN, gfp_mask);
- if (likely(skb))
- skb_reserve(skb, L2_HEADER_LEN);
- return skb;
-}
-
-static void
-mISDN_sock_link(struct mISDN_sock_list *l, struct sock *sk)
-{
- write_lock_bh(&l->lock);
- sk_add_node(sk, &l->head);
- write_unlock_bh(&l->lock);
-}
-
-static void mISDN_sock_unlink(struct mISDN_sock_list *l, struct sock *sk)
-{
- write_lock_bh(&l->lock);
- sk_del_node_init(sk);
- write_unlock_bh(&l->lock);
-}
-
-static int
-mISDN_send(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct mISDN_sock *msk;
- int err;
-
- msk = container_of(ch, struct mISDN_sock, ch);
- if (*debug & DEBUG_SOCKET)
- printk(KERN_DEBUG "%s len %d %p\n", __func__, skb->len, skb);
- if (msk->sk.sk_state == MISDN_CLOSED)
- return -EUNATCH;
- __net_timestamp(skb);
- err = sock_queue_rcv_skb(&msk->sk, skb);
- if (err)
- printk(KERN_WARNING "%s: error %d\n", __func__, err);
- return err;
-}
-
-static int
-mISDN_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct mISDN_sock *msk;
-
- msk = container_of(ch, struct mISDN_sock, ch);
- if (*debug & DEBUG_SOCKET)
- printk(KERN_DEBUG "%s(%p, %x, %p)\n", __func__, ch, cmd, arg);
- switch (cmd) {
- case CLOSE_CHANNEL:
- msk->sk.sk_state = MISDN_CLOSED;
- break;
- }
- return 0;
-}
-
-static inline void
-mISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
-{
- struct __kernel_old_timeval tv;
-
- if (_pms(sk)->cmask & MISDN_TIME_STAMP) {
- skb_get_timestamp(skb, &tv);
- put_cmsg(msg, SOL_MISDN, MISDN_TIME_STAMP, sizeof(tv), &tv);
- }
-}
-
-static int
-mISDN_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
- int flags)
-{
- struct sk_buff *skb;
- struct sock *sk = sock->sk;
-
- int copied, err;
-
- if (*debug & DEBUG_SOCKET)
- printk(KERN_DEBUG "%s: len %d, flags %x ch.nr %d, proto %x\n",
- __func__, (int)len, flags, _pms(sk)->ch.nr,
- sk->sk_protocol);
- if (flags & (MSG_OOB))
- return -EOPNOTSUPP;
-
- if (sk->sk_state == MISDN_CLOSED)
- return 0;
-
- skb = skb_recv_datagram(sk, flags, &err);
- if (!skb)
- return err;
-
- if (msg->msg_name) {
- DECLARE_SOCKADDR(struct sockaddr_mISDN *, maddr, msg->msg_name);
-
- maddr->family = AF_ISDN;
- maddr->dev = _pms(sk)->dev->id;
- if ((sk->sk_protocol == ISDN_P_LAPD_TE) ||
- (sk->sk_protocol == ISDN_P_LAPD_NT)) {
- maddr->channel = (mISDN_HEAD_ID(skb) >> 16) & 0xff;
- maddr->tei = (mISDN_HEAD_ID(skb) >> 8) & 0xff;
- maddr->sapi = mISDN_HEAD_ID(skb) & 0xff;
- } else {
- maddr->channel = _pms(sk)->ch.nr;
- maddr->sapi = _pms(sk)->ch.addr & 0xFF;
- maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF;
- }
- msg->msg_namelen = sizeof(*maddr);
- }
-
- copied = skb->len + MISDN_HEADER_LEN;
- if (len < copied) {
- if (flags & MSG_PEEK)
- refcount_dec(&skb->users);
- else
- skb_queue_head(&sk->sk_receive_queue, skb);
- return -ENOSPC;
- }
- memcpy(skb_push(skb, MISDN_HEADER_LEN), mISDN_HEAD_P(skb),
- MISDN_HEADER_LEN);
-
- err = skb_copy_datagram_msg(skb, 0, msg, copied);
-
- mISDN_sock_cmsg(sk, msg, skb);
-
- skb_free_datagram(sk, skb);
-
- return err ? : copied;
-}
-
-static int
-mISDN_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
-{
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
- int err = -ENOMEM;
-
- if (*debug & DEBUG_SOCKET)
- printk(KERN_DEBUG "%s: len %d flags %x ch %d proto %x\n",
- __func__, (int)len, msg->msg_flags, _pms(sk)->ch.nr,
- sk->sk_protocol);
-
- if (msg->msg_flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL | MSG_ERRQUEUE))
- return -EINVAL;
-
- if (len < MISDN_HEADER_LEN)
- return -EINVAL;
-
- if (sk->sk_state != MISDN_BOUND)
- return -EBADFD;
-
- lock_sock(sk);
-
- skb = _l2_alloc_skb(len, GFP_KERNEL);
- if (!skb)
- goto done;
-
- if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
- err = -EFAULT;
- goto done;
- }
-
- memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN);
- skb_pull(skb, MISDN_HEADER_LEN);
-
- if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) {
- /* if we have a address, we use it */
- DECLARE_SOCKADDR(struct sockaddr_mISDN *, maddr, msg->msg_name);
- mISDN_HEAD_ID(skb) = maddr->channel;
- } else { /* use default for L2 messages */
- if ((sk->sk_protocol == ISDN_P_LAPD_TE) ||
- (sk->sk_protocol == ISDN_P_LAPD_NT))
- mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr;
- }
-
- if (*debug & DEBUG_SOCKET)
- printk(KERN_DEBUG "%s: ID:%x\n",
- __func__, mISDN_HEAD_ID(skb));
-
- err = -ENODEV;
- if (!_pms(sk)->ch.peer)
- goto done;
- err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb);
- if (err)
- goto done;
- else {
- skb = NULL;
- err = len;
- }
-
-done:
- kfree_skb(skb);
- release_sock(sk);
- return err;
-}
-
-static int
-data_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- if (*debug & DEBUG_SOCKET)
- printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk);
- if (!sk)
- return 0;
- switch (sk->sk_protocol) {
- case ISDN_P_TE_S0:
- case ISDN_P_NT_S0:
- case ISDN_P_TE_E1:
- case ISDN_P_NT_E1:
- if (sk->sk_state == MISDN_BOUND)
- delete_channel(&_pms(sk)->ch);
- else
- mISDN_sock_unlink(&data_sockets, sk);
- break;
- case ISDN_P_LAPD_TE:
- case ISDN_P_LAPD_NT:
- case ISDN_P_B_RAW:
- case ISDN_P_B_HDLC:
- case ISDN_P_B_X75SLP:
- case ISDN_P_B_L2DTMF:
- case ISDN_P_B_L2DSP:
- case ISDN_P_B_L2DSPHDLC:
- delete_channel(&_pms(sk)->ch);
- mISDN_sock_unlink(&data_sockets, sk);
- break;
- }
-
- lock_sock(sk);
-
- sock_orphan(sk);
- skb_queue_purge(&sk->sk_receive_queue);
-
- release_sock(sk);
- sock_put(sk);
-
- return 0;
-}
-
-static int
-data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p)
-{
- struct mISDN_ctrl_req cq;
- int err = -EINVAL, val[2];
- struct mISDNchannel *bchan, *next;
-
- lock_sock(sk);
- if (!_pms(sk)->dev) {
- err = -ENODEV;
- goto done;
- }
- switch (cmd) {
- case IMCTRLREQ:
- if (copy_from_user(&cq, p, sizeof(cq))) {
- err = -EFAULT;
- break;
- }
- if ((sk->sk_protocol & ~ISDN_P_B_MASK) == ISDN_P_B_START) {
- list_for_each_entry_safe(bchan, next,
- &_pms(sk)->dev->bchannels, list) {
- if (bchan->nr == cq.channel) {
- err = bchan->ctrl(bchan,
- CONTROL_CHANNEL, &cq);
- break;
- }
- }
- } else
- err = _pms(sk)->dev->D.ctrl(&_pms(sk)->dev->D,
- CONTROL_CHANNEL, &cq);
- if (err)
- break;
- if (copy_to_user(p, &cq, sizeof(cq)))
- err = -EFAULT;
- break;
- case IMCLEAR_L2:
- if (sk->sk_protocol != ISDN_P_LAPD_NT) {
- err = -EINVAL;
- break;
- }
- val[0] = cmd;
- if (get_user(val[1], (int __user *)p)) {
- err = -EFAULT;
- break;
- }
- err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr,
- CONTROL_CHANNEL, val);
- break;
- case IMHOLD_L1:
- if (sk->sk_protocol != ISDN_P_LAPD_NT
- && sk->sk_protocol != ISDN_P_LAPD_TE) {
- err = -EINVAL;
- break;
- }
- val[0] = cmd;
- if (get_user(val[1], (int __user *)p)) {
- err = -EFAULT;
- break;
- }
- err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr,
- CONTROL_CHANNEL, val);
- break;
- default:
- err = -EINVAL;
- break;
- }
-done:
- release_sock(sk);
- return err;
-}
-
-static int
-data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- int err = 0, id;
- struct sock *sk = sock->sk;
- struct mISDNdevice *dev;
- struct mISDNversion ver;
-
- switch (cmd) {
- case IMGETVERSION:
- ver.major = MISDN_MAJOR_VERSION;
- ver.minor = MISDN_MINOR_VERSION;
- ver.release = MISDN_RELEASE;
- if (copy_to_user((void __user *)arg, &ver, sizeof(ver)))
- err = -EFAULT;
- break;
- case IMGETCOUNT:
- id = get_mdevice_count();
- if (put_user(id, (int __user *)arg))
- err = -EFAULT;
- break;
- case IMGETDEVINFO:
- if (get_user(id, (int __user *)arg)) {
- err = -EFAULT;
- break;
- }
- dev = get_mdevice(id);
- if (dev) {
- struct mISDN_devinfo di;
-
- memset(&di, 0, sizeof(di));
- di.id = dev->id;
- di.Dprotocols = dev->Dprotocols;
- di.Bprotocols = dev->Bprotocols | get_all_Bprotocols();
- di.protocol = dev->D.protocol;
- memcpy(di.channelmap, dev->channelmap,
- sizeof(di.channelmap));
- di.nrbchan = dev->nrbchan;
- strscpy(di.name, dev_name(&dev->dev), sizeof(di.name));
- if (copy_to_user((void __user *)arg, &di, sizeof(di)))
- err = -EFAULT;
- } else
- err = -ENODEV;
- break;
- default:
- if (sk->sk_state == MISDN_BOUND)
- err = data_sock_ioctl_bound(sk, cmd,
- (void __user *)arg);
- else
- err = -ENOTCONN;
- }
- return err;
-}
-
-static int data_sock_setsockopt(struct socket *sock, int level, int optname,
- sockptr_t optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- int err = 0, opt = 0;
-
- if (*debug & DEBUG_SOCKET)
- printk(KERN_DEBUG "%s(%p, %d, %x, optval, %d)\n", __func__, sock,
- level, optname, optlen);
-
- lock_sock(sk);
-
- switch (optname) {
- case MISDN_TIME_STAMP:
- err = copy_safe_from_sockptr(&opt, sizeof(opt),
- optval, optlen);
- if (err)
- break;
-
- if (opt)
- _pms(sk)->cmask |= MISDN_TIME_STAMP;
- else
- _pms(sk)->cmask &= ~MISDN_TIME_STAMP;
- break;
- default:
- err = -ENOPROTOOPT;
- break;
- }
- release_sock(sk);
- return err;
-}
-
-static int data_sock_getsockopt(struct socket *sock, int level, int optname,
- char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- int len, opt;
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- if (len != sizeof(char))
- return -EINVAL;
-
- switch (optname) {
- case MISDN_TIME_STAMP:
- if (_pms(sk)->cmask & MISDN_TIME_STAMP)
- opt = 1;
- else
- opt = 0;
-
- if (put_user(opt, optval))
- return -EFAULT;
- break;
- default:
- return -ENOPROTOOPT;
- }
-
- return 0;
-}
-
-static int
-data_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, int addr_len)
-{
- struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr;
- struct sock *sk = sock->sk;
- struct sock *csk;
- int err = 0;
-
- if (*debug & DEBUG_SOCKET)
- printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk);
- if (addr_len != sizeof(struct sockaddr_mISDN))
- return -EINVAL;
- if (!maddr || maddr->family != AF_ISDN)
- return -EINVAL;
-
- lock_sock(sk);
-
- if (_pms(sk)->dev) {
- err = -EALREADY;
- goto done;
- }
- _pms(sk)->dev = get_mdevice(maddr->dev);
- if (!_pms(sk)->dev) {
- err = -ENODEV;
- goto done;
- }
-
- if (sk->sk_protocol < ISDN_P_B_START) {
- read_lock_bh(&data_sockets.lock);
- sk_for_each(csk, &data_sockets.head) {
- if (sk == csk)
- continue;
- if (_pms(csk)->dev != _pms(sk)->dev)
- continue;
- if (csk->sk_protocol >= ISDN_P_B_START)
- continue;
- if (IS_ISDN_P_TE(csk->sk_protocol)
- == IS_ISDN_P_TE(sk->sk_protocol))
- continue;
- read_unlock_bh(&data_sockets.lock);
- err = -EBUSY;
- goto done;
- }
- read_unlock_bh(&data_sockets.lock);
- }
-
- _pms(sk)->ch.send = mISDN_send;
- _pms(sk)->ch.ctrl = mISDN_ctrl;
-
- switch (sk->sk_protocol) {
- case ISDN_P_TE_S0:
- case ISDN_P_NT_S0:
- case ISDN_P_TE_E1:
- case ISDN_P_NT_E1:
- mISDN_sock_unlink(&data_sockets, sk);
- err = connect_layer1(_pms(sk)->dev, &_pms(sk)->ch,
- sk->sk_protocol, maddr);
- if (err)
- mISDN_sock_link(&data_sockets, sk);
- break;
- case ISDN_P_LAPD_TE:
- case ISDN_P_LAPD_NT:
- err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch,
- sk->sk_protocol, maddr);
- break;
- case ISDN_P_B_RAW:
- case ISDN_P_B_HDLC:
- case ISDN_P_B_X75SLP:
- case ISDN_P_B_L2DTMF:
- case ISDN_P_B_L2DSP:
- case ISDN_P_B_L2DSPHDLC:
- err = connect_Bstack(_pms(sk)->dev, &_pms(sk)->ch,
- sk->sk_protocol, maddr);
- break;
- default:
- err = -EPROTONOSUPPORT;
- }
- if (err)
- goto done;
- sk->sk_state = MISDN_BOUND;
- _pms(sk)->ch.protocol = sk->sk_protocol;
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int
-data_sock_getname(struct socket *sock, struct sockaddr *addr,
- int peer)
-{
- struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr;
- struct sock *sk = sock->sk;
-
- if (!_pms(sk)->dev)
- return -EBADFD;
-
- lock_sock(sk);
-
- maddr->family = AF_ISDN;
- maddr->dev = _pms(sk)->dev->id;
- maddr->channel = _pms(sk)->ch.nr;
- maddr->sapi = _pms(sk)->ch.addr & 0xff;
- maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xff;
- release_sock(sk);
- return sizeof(*maddr);
-}
-
-static const struct proto_ops data_sock_ops = {
- .family = PF_ISDN,
- .owner = THIS_MODULE,
- .release = data_sock_release,
- .ioctl = data_sock_ioctl,
- .bind = data_sock_bind,
- .getname = data_sock_getname,
- .sendmsg = mISDN_sock_sendmsg,
- .recvmsg = mISDN_sock_recvmsg,
- .poll = datagram_poll,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = data_sock_setsockopt,
- .getsockopt = data_sock_getsockopt,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
-};
-
-static int
-data_sock_create(struct net *net, struct socket *sock, int protocol, int kern)
-{
- struct sock *sk;
-
- if (sock->type != SOCK_DGRAM)
- return -ESOCKTNOSUPPORT;
-
- sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern);
- if (!sk)
- return -ENOMEM;
-
- sock_init_data(sock, sk);
-
- sock->ops = &data_sock_ops;
- sock->state = SS_UNCONNECTED;
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = protocol;
- sk->sk_state = MISDN_OPEN;
- mISDN_sock_link(&data_sockets, sk);
-
- return 0;
-}
-
-static int
-base_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk);
- if (!sk)
- return 0;
-
- mISDN_sock_unlink(&base_sockets, sk);
- sock_orphan(sk);
- sock_put(sk);
-
- return 0;
-}
-
-static int
-base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- int err = 0, id;
- struct mISDNdevice *dev;
- struct mISDNversion ver;
-
- switch (cmd) {
- case IMGETVERSION:
- ver.major = MISDN_MAJOR_VERSION;
- ver.minor = MISDN_MINOR_VERSION;
- ver.release = MISDN_RELEASE;
- if (copy_to_user((void __user *)arg, &ver, sizeof(ver)))
- err = -EFAULT;
- break;
- case IMGETCOUNT:
- id = get_mdevice_count();
- if (put_user(id, (int __user *)arg))
- err = -EFAULT;
- break;
- case IMGETDEVINFO:
- if (get_user(id, (int __user *)arg)) {
- err = -EFAULT;
- break;
- }
- dev = get_mdevice(id);
- if (dev) {
- struct mISDN_devinfo di;
-
- memset(&di, 0, sizeof(di));
- di.id = dev->id;
- di.Dprotocols = dev->Dprotocols;
- di.Bprotocols = dev->Bprotocols | get_all_Bprotocols();
- di.protocol = dev->D.protocol;
- memcpy(di.channelmap, dev->channelmap,
- sizeof(di.channelmap));
- di.nrbchan = dev->nrbchan;
- strscpy(di.name, dev_name(&dev->dev), sizeof(di.name));
- if (copy_to_user((void __user *)arg, &di, sizeof(di)))
- err = -EFAULT;
- } else
- err = -ENODEV;
- break;
- case IMSETDEVNAME:
- {
- struct mISDN_devrename dn;
- if (copy_from_user(&dn, (void __user *)arg,
- sizeof(dn))) {
- err = -EFAULT;
- break;
- }
- dn.name[sizeof(dn.name) - 1] = '\0';
- dev = get_mdevice(dn.id);
- if (dev)
- err = device_rename(&dev->dev, dn.name);
- else
- err = -ENODEV;
- }
- break;
- default:
- err = -EINVAL;
- }
- return err;
-}
-
-static int
-base_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, int addr_len)
-{
- struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr;
- struct sock *sk = sock->sk;
- int err = 0;
-
- if (addr_len < sizeof(struct sockaddr_mISDN))
- return -EINVAL;
-
- if (!maddr || maddr->family != AF_ISDN)
- return -EINVAL;
-
- lock_sock(sk);
-
- if (_pms(sk)->dev) {
- err = -EALREADY;
- goto done;
- }
-
- _pms(sk)->dev = get_mdevice(maddr->dev);
- if (!_pms(sk)->dev) {
- err = -ENODEV;
- goto done;
- }
- sk->sk_state = MISDN_BOUND;
-
-done:
- release_sock(sk);
- return err;
-}
-
-static const struct proto_ops base_sock_ops = {
- .family = PF_ISDN,
- .owner = THIS_MODULE,
- .release = base_sock_release,
- .ioctl = base_sock_ioctl,
- .bind = base_sock_bind,
- .getname = sock_no_getname,
- .sendmsg = sock_no_sendmsg,
- .recvmsg = sock_no_recvmsg,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
-};
-
-
-static int
-base_sock_create(struct net *net, struct socket *sock, int protocol, int kern)
-{
- struct sock *sk;
-
- if (sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
- if (!capable(CAP_NET_RAW))
- return -EPERM;
-
- sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern);
- if (!sk)
- return -ENOMEM;
-
- sock_init_data(sock, sk);
- sock->ops = &base_sock_ops;
- sock->state = SS_UNCONNECTED;
- sock_reset_flag(sk, SOCK_ZAPPED);
- sk->sk_protocol = protocol;
- sk->sk_state = MISDN_OPEN;
- mISDN_sock_link(&base_sockets, sk);
-
- return 0;
-}
-
-static int
-mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern)
-{
- int err = -EPROTONOSUPPORT;
-
- switch (proto) {
- case ISDN_P_BASE:
- err = base_sock_create(net, sock, proto, kern);
- break;
- case ISDN_P_TE_S0:
- case ISDN_P_NT_S0:
- case ISDN_P_TE_E1:
- case ISDN_P_NT_E1:
- case ISDN_P_LAPD_TE:
- case ISDN_P_LAPD_NT:
- case ISDN_P_B_RAW:
- case ISDN_P_B_HDLC:
- case ISDN_P_B_X75SLP:
- case ISDN_P_B_L2DTMF:
- case ISDN_P_B_L2DSP:
- case ISDN_P_B_L2DSPHDLC:
- err = data_sock_create(net, sock, proto, kern);
- break;
- default:
- return err;
- }
-
- return err;
-}
-
-static const struct net_proto_family mISDN_sock_family_ops = {
- .owner = THIS_MODULE,
- .family = PF_ISDN,
- .create = mISDN_sock_create,
-};
-
-int
-misdn_sock_init(u_int *deb)
-{
- int err;
-
- debug = deb;
- err = sock_register(&mISDN_sock_family_ops);
- if (err)
- printk(KERN_ERR "%s: error(%d)\n", __func__, err);
- return err;
-}
-
-void
-misdn_sock_cleanup(void)
-{
- sock_unregister(PF_ISDN);
-}
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *
- * Author Karsten Keil <kkeil@novell.com>
- *
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#include <linux/slab.h>
-#include <linux/mISDNif.h>
-#include <linux/kthread.h>
-#include <linux/sched.h>
-#include <linux/sched/cputime.h>
-#include <linux/signal.h>
-
-#include "core.h"
-
-static u_int *debug;
-
-static inline void
-_queue_message(struct mISDNstack *st, struct sk_buff *skb)
-{
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
-
- if (*debug & DEBUG_QUEUE_FUNC)
- printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n",
- __func__, hh->prim, hh->id, skb);
- skb_queue_tail(&st->msgq, skb);
- if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) {
- test_and_set_bit(mISDN_STACK_WORK, &st->status);
- wake_up_interruptible(&st->workq);
- }
-}
-
-static int
-mISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- _queue_message(ch->st, skb);
- return 0;
-}
-
-static struct mISDNchannel *
-get_channel4id(struct mISDNstack *st, u_int id)
-{
- struct mISDNchannel *ch;
-
- mutex_lock(&st->lmutex);
- list_for_each_entry(ch, &st->layer2, list) {
- if (id == ch->nr)
- goto unlock;
- }
- ch = NULL;
-unlock:
- mutex_unlock(&st->lmutex);
- return ch;
-}
-
-static void
-send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb)
-{
- struct sock *sk;
- struct sk_buff *cskb = NULL;
-
- read_lock(&sl->lock);
- sk_for_each(sk, &sl->head) {
- if (sk->sk_state != MISDN_BOUND)
- continue;
- if (!cskb)
- cskb = skb_copy(skb, GFP_ATOMIC);
- if (!cskb) {
- printk(KERN_WARNING "%s no skb\n", __func__);
- break;
- }
- if (!sock_queue_rcv_skb(sk, cskb))
- cskb = NULL;
- }
- read_unlock(&sl->lock);
- dev_kfree_skb(cskb);
-}
-
-static void
-send_layer2(struct mISDNstack *st, struct sk_buff *skb)
-{
- struct sk_buff *cskb;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- struct mISDNchannel *ch;
- int ret;
-
- if (!st)
- return;
- mutex_lock(&st->lmutex);
- if ((hh->id & MISDN_ID_ADDR_MASK) == MISDN_ID_ANY) { /* L2 for all */
- list_for_each_entry(ch, &st->layer2, list) {
- if (list_is_last(&ch->list, &st->layer2)) {
- cskb = skb;
- skb = NULL;
- } else {
- cskb = skb_copy(skb, GFP_KERNEL);
- }
- if (cskb) {
- ret = ch->send(ch, cskb);
- if (ret) {
- if (*debug & DEBUG_SEND_ERR)
- printk(KERN_DEBUG
- "%s ch%d prim(%x) addr(%x)"
- " err %d\n",
- __func__, ch->nr,
- hh->prim, ch->addr, ret);
- dev_kfree_skb(cskb);
- }
- } else {
- printk(KERN_WARNING "%s ch%d addr %x no mem\n",
- __func__, ch->nr, ch->addr);
- goto out;
- }
- }
- } else {
- list_for_each_entry(ch, &st->layer2, list) {
- if ((hh->id & MISDN_ID_ADDR_MASK) == ch->addr) {
- ret = ch->send(ch, skb);
- if (!ret)
- skb = NULL;
- goto out;
- }
- }
- ret = st->dev->teimgr->ctrl(st->dev->teimgr, CHECK_DATA, skb);
- if (!ret)
- skb = NULL;
- else if (*debug & DEBUG_SEND_ERR)
- printk(KERN_DEBUG
- "%s mgr prim(%x) err %d\n",
- __func__, hh->prim, ret);
- }
-out:
- mutex_unlock(&st->lmutex);
- dev_kfree_skb(skb);
-}
-
-static inline int
-send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb)
-{
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- struct mISDNchannel *ch;
- int lm;
-
- lm = hh->prim & MISDN_LAYERMASK;
- if (*debug & DEBUG_QUEUE_FUNC)
- printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n",
- __func__, hh->prim, hh->id, skb);
- if (lm == 0x1) {
- if (!hlist_empty(&st->l1sock.head)) {
- __net_timestamp(skb);
- send_socklist(&st->l1sock, skb);
- }
- return st->layer1->send(st->layer1, skb);
- } else if (lm == 0x2) {
- if (!hlist_empty(&st->l1sock.head))
- send_socklist(&st->l1sock, skb);
- send_layer2(st, skb);
- return 0;
- } else if (lm == 0x4) {
- ch = get_channel4id(st, hh->id);
- if (ch)
- return ch->send(ch, skb);
- else
- printk(KERN_WARNING
- "%s: dev(%s) prim(%x) id(%x) no channel\n",
- __func__, dev_name(&st->dev->dev), hh->prim,
- hh->id);
- } else if (lm == 0x8) {
- WARN_ON(lm == 0x8);
- ch = get_channel4id(st, hh->id);
- if (ch)
- return ch->send(ch, skb);
- else
- printk(KERN_WARNING
- "%s: dev(%s) prim(%x) id(%x) no channel\n",
- __func__, dev_name(&st->dev->dev), hh->prim,
- hh->id);
- } else {
- /* broadcast not handled yet */
- printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n",
- __func__, dev_name(&st->dev->dev), hh->prim);
- }
- return -ESRCH;
-}
-
-static void
-do_clear_stack(struct mISDNstack *st)
-{
-}
-
-static int
-mISDNStackd(void *data)
-{
- struct mISDNstack *st = data;
-#ifdef MISDN_MSG_STATS
- u64 utime, stime;
-#endif
- int err = 0;
-
- sigfillset(¤t->blocked);
- if (*debug & DEBUG_MSG_THREAD)
- printk(KERN_DEBUG "mISDNStackd %s started\n",
- dev_name(&st->dev->dev));
-
- if (st->notify != NULL) {
- complete(st->notify);
- st->notify = NULL;
- }
-
- for (;;) {
- struct sk_buff *skb;
-
- if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) {
- test_and_clear_bit(mISDN_STACK_WORK, &st->status);
- test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
- } else
- test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
- while (test_bit(mISDN_STACK_WORK, &st->status)) {
- skb = skb_dequeue(&st->msgq);
- if (!skb) {
- test_and_clear_bit(mISDN_STACK_WORK,
- &st->status);
- /* test if a race happens */
- skb = skb_dequeue(&st->msgq);
- if (!skb)
- continue;
- test_and_set_bit(mISDN_STACK_WORK,
- &st->status);
- }
-#ifdef MISDN_MSG_STATS
- st->msg_cnt++;
-#endif
- err = send_msg_to_layer(st, skb);
- if (unlikely(err)) {
- if (*debug & DEBUG_SEND_ERR)
- printk(KERN_DEBUG
- "%s: %s prim(%x) id(%x) "
- "send call(%d)\n",
- __func__, dev_name(&st->dev->dev),
- mISDN_HEAD_PRIM(skb),
- mISDN_HEAD_ID(skb), err);
- dev_kfree_skb(skb);
- continue;
- }
- if (unlikely(test_bit(mISDN_STACK_STOPPED,
- &st->status))) {
- test_and_clear_bit(mISDN_STACK_WORK,
- &st->status);
- test_and_clear_bit(mISDN_STACK_RUNNING,
- &st->status);
- break;
- }
- }
- if (test_bit(mISDN_STACK_CLEARING, &st->status)) {
- test_and_set_bit(mISDN_STACK_STOPPED, &st->status);
- test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
- do_clear_stack(st);
- test_and_clear_bit(mISDN_STACK_CLEARING, &st->status);
- test_and_set_bit(mISDN_STACK_RESTART, &st->status);
- }
- if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) {
- test_and_clear_bit(mISDN_STACK_STOPPED, &st->status);
- test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
- if (!skb_queue_empty(&st->msgq))
- test_and_set_bit(mISDN_STACK_WORK,
- &st->status);
- }
- if (test_bit(mISDN_STACK_ABORT, &st->status))
- break;
- if (st->notify != NULL) {
- complete(st->notify);
- st->notify = NULL;
- }
-#ifdef MISDN_MSG_STATS
- st->sleep_cnt++;
-#endif
- test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
- wait_event_interruptible(st->workq, (st->status &
- mISDN_STACK_ACTION_MASK));
- if (*debug & DEBUG_MSG_THREAD)
- printk(KERN_DEBUG "%s: %s wake status %08lx\n",
- __func__, dev_name(&st->dev->dev), st->status);
- test_and_set_bit(mISDN_STACK_ACTIVE, &st->status);
-
- test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status);
-
- if (test_bit(mISDN_STACK_STOPPED, &st->status)) {
- test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
-#ifdef MISDN_MSG_STATS
- st->stopped_cnt++;
-#endif
- }
- }
-#ifdef MISDN_MSG_STATS
- printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d "
- "msg %d sleep %d stopped\n",
- dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt,
- st->stopped_cnt);
- task_cputime(st->thread, &utime, &stime);
- printk(KERN_DEBUG
- "mISDNStackd daemon for %s utime(%llu) stime(%llu)\n",
- dev_name(&st->dev->dev), utime, stime);
- printk(KERN_DEBUG
- "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n",
- dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw);
- printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n",
- dev_name(&st->dev->dev));
-#endif
- test_and_set_bit(mISDN_STACK_KILLED, &st->status);
- test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
- test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
- test_and_clear_bit(mISDN_STACK_ABORT, &st->status);
- skb_queue_purge(&st->msgq);
- st->thread = NULL;
- if (st->notify != NULL) {
- complete(st->notify);
- st->notify = NULL;
- }
- return 0;
-}
-
-static int
-l1_receive(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- if (!ch->st)
- return -ENODEV;
- __net_timestamp(skb);
- _queue_message(ch->st, skb);
- return 0;
-}
-
-void
-set_channel_address(struct mISDNchannel *ch, u_int sapi, u_int tei)
-{
- ch->addr = sapi | (tei << 8);
-}
-
-void
-__add_layer2(struct mISDNchannel *ch, struct mISDNstack *st)
-{
- list_add_tail(&ch->list, &st->layer2);
-}
-
-void
-add_layer2(struct mISDNchannel *ch, struct mISDNstack *st)
-{
- mutex_lock(&st->lmutex);
- __add_layer2(ch, st);
- mutex_unlock(&st->lmutex);
-}
-
-static int
-st_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- if (!ch->st || !ch->st->layer1)
- return -EINVAL;
- return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg);
-}
-
-int
-create_stack(struct mISDNdevice *dev)
-{
- struct mISDNstack *newst;
- int err;
- DECLARE_COMPLETION_ONSTACK(done);
-
- newst = kzalloc_obj(struct mISDNstack);
- if (!newst) {
- printk(KERN_ERR "kmalloc mISDN_stack failed\n");
- return -ENOMEM;
- }
- newst->dev = dev;
- INIT_LIST_HEAD(&newst->layer2);
- INIT_HLIST_HEAD(&newst->l1sock.head);
- rwlock_init(&newst->l1sock.lock);
- init_waitqueue_head(&newst->workq);
- skb_queue_head_init(&newst->msgq);
- mutex_init(&newst->lmutex);
- dev->D.st = newst;
- err = create_teimanager(dev);
- if (err) {
- printk(KERN_ERR "kmalloc teimanager failed\n");
- kfree(newst);
- return err;
- }
- dev->teimgr->peer = &newst->own;
- dev->teimgr->recv = mISDN_queue_message;
- dev->teimgr->st = newst;
- newst->layer1 = &dev->D;
- dev->D.recv = l1_receive;
- dev->D.peer = &newst->own;
- newst->own.st = newst;
- newst->own.ctrl = st_own_ctrl;
- newst->own.send = mISDN_queue_message;
- newst->own.recv = mISDN_queue_message;
- if (*debug & DEBUG_CORE_FUNC)
- printk(KERN_DEBUG "%s: st(%s)\n", __func__,
- dev_name(&newst->dev->dev));
- newst->notify = &done;
- newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s",
- dev_name(&newst->dev->dev));
- if (IS_ERR(newst->thread)) {
- err = PTR_ERR(newst->thread);
- printk(KERN_ERR
- "mISDN:cannot create kernel thread for %s (%d)\n",
- dev_name(&newst->dev->dev), err);
- delete_teimanager(dev->teimgr);
- kfree(newst);
- } else
- wait_for_completion(&done);
- return err;
-}
-
-int
-connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch,
- u_int protocol, struct sockaddr_mISDN *adr)
-{
- struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch);
- struct channel_req rq;
- int err;
-
-
- if (*debug & DEBUG_CORE_FUNC)
- printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
- __func__, dev_name(&dev->dev), protocol, adr->dev,
- adr->channel, adr->sapi, adr->tei);
- switch (protocol) {
- case ISDN_P_NT_S0:
- case ISDN_P_NT_E1:
- case ISDN_P_TE_S0:
- case ISDN_P_TE_E1:
- ch->recv = mISDN_queue_message;
- ch->peer = &dev->D.st->own;
- ch->st = dev->D.st;
- rq.protocol = protocol;
- rq.adr.channel = adr->channel;
- err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
- printk(KERN_DEBUG "%s: ret %d (dev %d)\n", __func__, err,
- dev->id);
- if (err)
- return err;
- write_lock_bh(&dev->D.st->l1sock.lock);
- sk_add_node(&msk->sk, &dev->D.st->l1sock.head);
- write_unlock_bh(&dev->D.st->l1sock.lock);
- break;
- default:
- return -ENOPROTOOPT;
- }
- return 0;
-}
-
-int
-connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch,
- u_int protocol, struct sockaddr_mISDN *adr)
-{
- struct channel_req rq, rq2;
- int pmask, err;
- struct Bprotocol *bp;
-
- if (*debug & DEBUG_CORE_FUNC)
- printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
- __func__, dev_name(&dev->dev), protocol,
- adr->dev, adr->channel, adr->sapi,
- adr->tei);
- ch->st = dev->D.st;
- pmask = 1 << (protocol & ISDN_P_B_MASK);
- if (pmask & dev->Bprotocols) {
- rq.protocol = protocol;
- rq.adr = *adr;
- err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
- if (err)
- return err;
- ch->recv = rq.ch->send;
- ch->peer = rq.ch;
- rq.ch->recv = ch->send;
- rq.ch->peer = ch;
- rq.ch->st = dev->D.st;
- } else {
- bp = get_Bprotocol4mask(pmask);
- if (!bp)
- return -ENOPROTOOPT;
- rq2.protocol = protocol;
- rq2.adr = *adr;
- rq2.ch = ch;
- err = bp->create(&rq2);
- if (err)
- return err;
- ch->recv = rq2.ch->send;
- ch->peer = rq2.ch;
- rq2.ch->st = dev->D.st;
- rq.protocol = rq2.protocol;
- rq.adr = *adr;
- err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
- if (err) {
- rq2.ch->ctrl(rq2.ch, CLOSE_CHANNEL, NULL);
- return err;
- }
- rq2.ch->recv = rq.ch->send;
- rq2.ch->peer = rq.ch;
- rq.ch->recv = rq2.ch->send;
- rq.ch->peer = rq2.ch;
- rq.ch->st = dev->D.st;
- }
- ch->protocol = protocol;
- ch->nr = rq.ch->nr;
- return 0;
-}
-
-int
-create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch,
- u_int protocol, struct sockaddr_mISDN *adr)
-{
- struct channel_req rq;
- int err;
-
- if (*debug & DEBUG_CORE_FUNC)
- printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
- __func__, dev_name(&dev->dev), protocol,
- adr->dev, adr->channel, adr->sapi,
- adr->tei);
- rq.protocol = ISDN_P_TE_S0;
- if (dev->Dprotocols & (1 << ISDN_P_TE_E1))
- rq.protocol = ISDN_P_TE_E1;
- switch (protocol) {
- case ISDN_P_LAPD_NT:
- rq.protocol = ISDN_P_NT_S0;
- if (dev->Dprotocols & (1 << ISDN_P_NT_E1))
- rq.protocol = ISDN_P_NT_E1;
- fallthrough;
- case ISDN_P_LAPD_TE:
- ch->recv = mISDN_queue_message;
- ch->peer = &dev->D.st->own;
- ch->st = dev->D.st;
- rq.adr.channel = 0;
- err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
- printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err);
- if (err)
- break;
- rq.protocol = protocol;
- rq.adr = *adr;
- rq.ch = ch;
- err = dev->teimgr->ctrl(dev->teimgr, OPEN_CHANNEL, &rq);
- printk(KERN_DEBUG "%s: ret 2 %d\n", __func__, err);
- if (!err) {
- if ((protocol == ISDN_P_LAPD_NT) && !rq.ch)
- break;
- add_layer2(rq.ch, dev->D.st);
- rq.ch->recv = mISDN_queue_message;
- rq.ch->peer = &dev->D.st->own;
- rq.ch->ctrl(rq.ch, OPEN_CHANNEL, NULL); /* can't fail */
- }
- break;
- default:
- err = -EPROTONOSUPPORT;
- }
- return err;
-}
-
-void
-delete_channel(struct mISDNchannel *ch)
-{
- struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch);
- struct mISDNchannel *pch;
-
- if (!ch->st) {
- printk(KERN_WARNING "%s: no stack\n", __func__);
- return;
- }
- if (*debug & DEBUG_CORE_FUNC)
- printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__,
- dev_name(&ch->st->dev->dev), ch->protocol);
- if (ch->protocol >= ISDN_P_B_START) {
- if (ch->peer) {
- ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL);
- ch->peer = NULL;
- }
- return;
- }
- switch (ch->protocol) {
- case ISDN_P_NT_S0:
- case ISDN_P_TE_S0:
- case ISDN_P_NT_E1:
- case ISDN_P_TE_E1:
- write_lock_bh(&ch->st->l1sock.lock);
- sk_del_node_init(&msk->sk);
- write_unlock_bh(&ch->st->l1sock.lock);
- ch->st->dev->D.ctrl(&ch->st->dev->D, CLOSE_CHANNEL, NULL);
- break;
- case ISDN_P_LAPD_TE:
- pch = get_channel4id(ch->st, ch->nr);
- if (pch) {
- mutex_lock(&ch->st->lmutex);
- list_del(&pch->list);
- mutex_unlock(&ch->st->lmutex);
- pch->ctrl(pch, CLOSE_CHANNEL, NULL);
- pch = ch->st->dev->teimgr;
- pch->ctrl(pch, CLOSE_CHANNEL, NULL);
- } else
- printk(KERN_WARNING "%s: no l2 channel\n",
- __func__);
- break;
- case ISDN_P_LAPD_NT:
- pch = ch->st->dev->teimgr;
- if (pch) {
- pch->ctrl(pch, CLOSE_CHANNEL, NULL);
- } else
- printk(KERN_WARNING "%s: no l2 channel\n",
- __func__);
- break;
- default:
- break;
- }
- return;
-}
-
-void
-delete_stack(struct mISDNdevice *dev)
-{
- struct mISDNstack *st = dev->D.st;
- DECLARE_COMPLETION_ONSTACK(done);
-
- if (*debug & DEBUG_CORE_FUNC)
- printk(KERN_DEBUG "%s: st(%s)\n", __func__,
- dev_name(&st->dev->dev));
- if (dev->teimgr)
- delete_teimanager(dev->teimgr);
- if (st->thread) {
- if (st->notify) {
- printk(KERN_WARNING "%s: notifier in use\n",
- __func__);
- complete(st->notify);
- }
- st->notify = &done;
- test_and_set_bit(mISDN_STACK_ABORT, &st->status);
- test_and_set_bit(mISDN_STACK_WAKEUP, &st->status);
- wake_up_interruptible(&st->workq);
- wait_for_completion(&done);
- }
- if (!list_empty(&st->layer2))
- printk(KERN_WARNING "%s: layer2 list not empty\n",
- __func__);
- if (!hlist_empty(&st->l1sock.head))
- printk(KERN_WARNING "%s: layer1 list not empty\n",
- __func__);
- kfree(st);
-}
-
-void
-mISDN_initstack(u_int *dp)
-{
- debug = dp;
-}
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *
- * Author Karsten Keil <kkeil@novell.com>
- *
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-#include "layer2.h"
-#include <linux/random.h>
-#include <linux/slab.h>
-#include "core.h"
-
-#define ID_REQUEST 1
-#define ID_ASSIGNED 2
-#define ID_DENIED 3
-#define ID_CHK_REQ 4
-#define ID_CHK_RES 5
-#define ID_REMOVE 6
-#define ID_VERIFY 7
-
-#define TEI_ENTITY_ID 0xf
-
-#define MGR_PH_ACTIVE 16
-#define MGR_PH_NOTREADY 17
-
-#define DATIMER_VAL 10000
-
-static u_int *debug;
-
-static struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL};
-static struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL};
-static struct Fsm teifsmn = {NULL, 0, 0, NULL, NULL};
-
-enum {
- ST_L1_DEACT,
- ST_L1_DEACT_PENDING,
- ST_L1_ACTIV,
-};
-#define DEACT_STATE_COUNT (ST_L1_ACTIV + 1)
-
-static char *strDeactState[] =
-{
- "ST_L1_DEACT",
- "ST_L1_DEACT_PENDING",
- "ST_L1_ACTIV",
-};
-
-enum {
- EV_ACTIVATE,
- EV_ACTIVATE_IND,
- EV_DEACTIVATE,
- EV_DEACTIVATE_IND,
- EV_UI,
- EV_DATIMER,
-};
-
-#define DEACT_EVENT_COUNT (EV_DATIMER + 1)
-
-static char *strDeactEvent[] =
-{
- "EV_ACTIVATE",
- "EV_ACTIVATE_IND",
- "EV_DEACTIVATE",
- "EV_DEACTIVATE_IND",
- "EV_UI",
- "EV_DATIMER",
-};
-
-static void
-da_debug(struct FsmInst *fi, char *fmt, ...)
-{
- struct manager *mgr = fi->userdata;
- struct va_format vaf;
- va_list va;
-
- if (!(*debug & DEBUG_L2_TEIFSM))
- return;
-
- va_start(va, fmt);
-
- vaf.fmt = fmt;
- vaf.va = &va;
-
- printk(KERN_DEBUG "mgr(%d): %pV\n", mgr->ch.st->dev->id, &vaf);
-
- va_end(va);
-}
-
-static void
-da_activate(struct FsmInst *fi, int event, void *arg)
-{
- struct manager *mgr = fi->userdata;
-
- if (fi->state == ST_L1_DEACT_PENDING)
- mISDN_FsmDelTimer(&mgr->datimer, 1);
- mISDN_FsmChangeState(fi, ST_L1_ACTIV);
-}
-
-static void
-da_deactivate_ind(struct FsmInst *fi, int event, void *arg)
-{
- mISDN_FsmChangeState(fi, ST_L1_DEACT);
-}
-
-static void
-da_deactivate(struct FsmInst *fi, int event, void *arg)
-{
- struct manager *mgr = fi->userdata;
- struct layer2 *l2;
- u_long flags;
-
- read_lock_irqsave(&mgr->lock, flags);
- list_for_each_entry(l2, &mgr->layer2, list) {
- if (l2->l2m.state > ST_L2_4) {
- /* have still activ TEI */
- read_unlock_irqrestore(&mgr->lock, flags);
- return;
- }
- }
- read_unlock_irqrestore(&mgr->lock, flags);
- /* All TEI are inactiv */
- if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
- mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
- NULL, 1);
- mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING);
- }
-}
-
-static void
-da_ui(struct FsmInst *fi, int event, void *arg)
-{
- struct manager *mgr = fi->userdata;
-
- /* restart da timer */
- if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
- mISDN_FsmDelTimer(&mgr->datimer, 2);
- mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
- NULL, 2);
- }
-}
-
-static void
-da_timer(struct FsmInst *fi, int event, void *arg)
-{
- struct manager *mgr = fi->userdata;
- struct layer2 *l2;
- u_long flags;
-
- /* check again */
- read_lock_irqsave(&mgr->lock, flags);
- list_for_each_entry(l2, &mgr->layer2, list) {
- if (l2->l2m.state > ST_L2_4) {
- /* have still activ TEI */
- read_unlock_irqrestore(&mgr->lock, flags);
- mISDN_FsmChangeState(fi, ST_L1_ACTIV);
- return;
- }
- }
- read_unlock_irqrestore(&mgr->lock, flags);
- /* All TEI are inactiv */
- mISDN_FsmChangeState(fi, ST_L1_DEACT);
- _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL,
- GFP_ATOMIC);
-}
-
-static struct FsmNode DeactFnList[] =
-{
- {ST_L1_DEACT, EV_ACTIVATE_IND, da_activate},
- {ST_L1_ACTIV, EV_DEACTIVATE_IND, da_deactivate_ind},
- {ST_L1_ACTIV, EV_DEACTIVATE, da_deactivate},
- {ST_L1_DEACT_PENDING, EV_ACTIVATE, da_activate},
- {ST_L1_DEACT_PENDING, EV_UI, da_ui},
- {ST_L1_DEACT_PENDING, EV_DATIMER, da_timer},
-};
-
-enum {
- ST_TEI_NOP,
- ST_TEI_IDREQ,
- ST_TEI_IDVERIFY,
-};
-
-#define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1)
-
-static char *strTeiState[] =
-{
- "ST_TEI_NOP",
- "ST_TEI_IDREQ",
- "ST_TEI_IDVERIFY",
-};
-
-enum {
- EV_IDREQ,
- EV_ASSIGN,
- EV_ASSIGN_REQ,
- EV_DENIED,
- EV_CHKREQ,
- EV_CHKRESP,
- EV_REMOVE,
- EV_VERIFY,
- EV_TIMER,
-};
-
-#define TEI_EVENT_COUNT (EV_TIMER + 1)
-
-static char *strTeiEvent[] =
-{
- "EV_IDREQ",
- "EV_ASSIGN",
- "EV_ASSIGN_REQ",
- "EV_DENIED",
- "EV_CHKREQ",
- "EV_CHKRESP",
- "EV_REMOVE",
- "EV_VERIFY",
- "EV_TIMER",
-};
-
-static void
-tei_debug(struct FsmInst *fi, char *fmt, ...)
-{
- struct teimgr *tm = fi->userdata;
- struct va_format vaf;
- va_list va;
-
- if (!(*debug & DEBUG_L2_TEIFSM))
- return;
-
- va_start(va, fmt);
-
- vaf.fmt = fmt;
- vaf.va = &va;
-
- printk(KERN_DEBUG "sapi(%d) tei(%d): %pV\n",
- tm->l2->sapi, tm->l2->tei, &vaf);
-
- va_end(va);
-}
-
-
-
-static int
-get_free_id(struct manager *mgr)
-{
- DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 };
- int i;
- struct layer2 *l2;
-
- list_for_each_entry(l2, &mgr->layer2, list) {
- if (l2->ch.nr > 63) {
- printk(KERN_WARNING
- "%s: more as 63 layer2 for one device\n",
- __func__);
- return -EBUSY;
- }
- __set_bit(l2->ch.nr, ids);
- }
- i = find_next_zero_bit(ids, 64, 1);
- if (i < 64)
- return i;
- printk(KERN_WARNING "%s: more as 63 layer2 for one device\n",
- __func__);
- return -EBUSY;
-}
-
-static int
-get_free_tei(struct manager *mgr)
-{
- DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 };
- int i;
- struct layer2 *l2;
-
- list_for_each_entry(l2, &mgr->layer2, list) {
- if (l2->ch.nr == 0)
- continue;
- if ((l2->ch.addr & 0xff) != 0)
- continue;
- i = l2->ch.addr >> 8;
- if (i < 64)
- continue;
- i -= 64;
-
- __set_bit(i, ids);
- }
- i = find_first_zero_bit(ids, 64);
- if (i < 64)
- return i + 64;
- printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n",
- __func__);
- return -1;
-}
-
-static void
-teiup_create(struct manager *mgr, u_int prim, int len, void *arg)
-{
- struct sk_buff *skb;
- struct mISDNhead *hh;
- int err;
-
- skb = mI_alloc_skb(len, GFP_ATOMIC);
- if (!skb)
- return;
- hh = mISDN_HEAD_P(skb);
- hh->prim = prim;
- hh->id = (mgr->ch.nr << 16) | mgr->ch.addr;
- if (len)
- skb_put_data(skb, arg, len);
- err = mgr->up->send(mgr->up, skb);
- if (err) {
- printk(KERN_WARNING "%s: err=%d\n", __func__, err);
- dev_kfree_skb(skb);
- }
-}
-
-static u_int
-new_id(struct manager *mgr)
-{
- u_int id;
-
- id = mgr->nextid++;
- if (id == 0x7fff)
- mgr->nextid = 1;
- id <<= 16;
- id |= GROUP_TEI << 8;
- id |= TEI_SAPI;
- return id;
-}
-
-static void
-do_send(struct manager *mgr)
-{
- if (!test_bit(MGR_PH_ACTIVE, &mgr->options))
- return;
-
- if (!test_and_set_bit(MGR_PH_NOTREADY, &mgr->options)) {
- struct sk_buff *skb = skb_dequeue(&mgr->sendq);
-
- if (!skb) {
- test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options);
- return;
- }
- mgr->lastid = mISDN_HEAD_ID(skb);
- mISDN_FsmEvent(&mgr->deact, EV_UI, NULL);
- if (mgr->ch.recv(mgr->ch.peer, skb)) {
- dev_kfree_skb(skb);
- test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options);
- mgr->lastid = MISDN_ID_NONE;
- }
- }
-}
-
-static void
-do_ack(struct manager *mgr, u_int id)
-{
- if (test_bit(MGR_PH_NOTREADY, &mgr->options)) {
- if (id == mgr->lastid) {
- if (test_bit(MGR_PH_ACTIVE, &mgr->options)) {
- struct sk_buff *skb;
-
- skb = skb_dequeue(&mgr->sendq);
- if (skb) {
- mgr->lastid = mISDN_HEAD_ID(skb);
- if (!mgr->ch.recv(mgr->ch.peer, skb))
- return;
- dev_kfree_skb(skb);
- }
- }
- mgr->lastid = MISDN_ID_NONE;
- test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options);
- }
- }
-}
-
-static void
-mgr_send_down(struct manager *mgr, struct sk_buff *skb)
-{
- skb_queue_tail(&mgr->sendq, skb);
- if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) {
- _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- } else {
- do_send(mgr);
- }
-}
-
-static int
-dl_unit_data(struct manager *mgr, struct sk_buff *skb)
-{
- if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) /* only net send UI */
- return -EINVAL;
- if (!test_bit(MGR_PH_ACTIVE, &mgr->options))
- _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0,
- NULL, GFP_KERNEL);
- skb_push(skb, 3);
- skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */
- skb->data[1] = 0xff; /* TEI 127 */
- skb->data[2] = UI; /* UI frame */
- mISDN_HEAD_PRIM(skb) = PH_DATA_REQ;
- mISDN_HEAD_ID(skb) = new_id(mgr);
- skb_queue_tail(&mgr->sendq, skb);
- do_send(mgr);
- return 0;
-}
-
-static unsigned int
-random_ri(void)
-{
- u16 x;
-
- get_random_bytes(&x, sizeof(x));
- return x;
-}
-
-static struct layer2 *
-findtei(struct manager *mgr, int tei)
-{
- struct layer2 *l2;
- u_long flags;
-
- read_lock_irqsave(&mgr->lock, flags);
- list_for_each_entry(l2, &mgr->layer2, list) {
- if ((l2->sapi == 0) && (l2->tei > 0) &&
- (l2->tei != GROUP_TEI) && (l2->tei == tei))
- goto done;
- }
- l2 = NULL;
-done:
- read_unlock_irqrestore(&mgr->lock, flags);
- return l2;
-}
-
-static void
-put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, int tei)
-{
- struct sk_buff *skb;
- u_char bp[8];
-
- bp[0] = (TEI_SAPI << 2);
- if (test_bit(MGR_OPT_NETWORK, &mgr->options))
- bp[0] |= 2; /* CR:=1 for net command */
- bp[1] = (GROUP_TEI << 1) | 0x1;
- bp[2] = UI;
- bp[3] = TEI_ENTITY_ID;
- bp[4] = ri >> 8;
- bp[5] = ri & 0xff;
- bp[6] = m_id;
- bp[7] = ((tei << 1) & 0xff) | 1;
- skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), 8, bp, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_WARNING "%s: no skb for tei msg\n", __func__);
- return;
- }
- mgr_send_down(mgr, skb);
-}
-
-static void
-tei_id_request(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
-
- if (tm->l2->tei != GROUP_TEI) {
- tm->tei_m.printdebug(&tm->tei_m,
- "assign request for already assigned tei %d",
- tm->l2->tei);
- return;
- }
- tm->ri = random_ri();
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(&tm->tei_m,
- "assign request ri %d", tm->ri);
- put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI);
- mISDN_FsmChangeState(fi, ST_TEI_IDREQ);
- mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1);
- tm->nval = 3;
-}
-
-static void
-tei_id_assign(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
- struct layer2 *l2;
- u_char *dp = arg;
- int ri, tei;
-
- ri = ((unsigned int) *dp++ << 8);
- ri += *dp++;
- dp++;
- tei = *dp >> 1;
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi, "identity assign ri %d tei %d",
- ri, tei);
- l2 = findtei(tm->mgr, tei);
- if (l2) { /* same tei is in use */
- if (ri != l2->tm->ri) {
- tm->tei_m.printdebug(fi,
- "possible duplicate assignment tei %d", tei);
- tei_l2(l2, MDL_ERROR_RSP, 0);
- }
- } else if (ri == tm->ri) {
- mISDN_FsmDelTimer(&tm->timer, 1);
- mISDN_FsmChangeState(fi, ST_TEI_NOP);
- tei_l2(tm->l2, MDL_ASSIGN_REQ, tei);
- }
-}
-
-static void
-tei_id_test_dup(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
- struct layer2 *l2;
- u_char *dp = arg;
- int tei, ri;
-
- ri = ((unsigned int) *dp++ << 8);
- ri += *dp++;
- dp++;
- tei = *dp >> 1;
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d",
- ri, tei);
- l2 = findtei(tm->mgr, tei);
- if (l2) { /* same tei is in use */
- if (ri != l2->tm->ri) { /* and it wasn't our request */
- tm->tei_m.printdebug(fi,
- "possible duplicate assignment tei %d", tei);
- mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL);
- }
- }
-}
-
-static void
-tei_id_denied(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
- u_char *dp = arg;
- int ri, tei;
-
- ri = ((unsigned int) *dp++ << 8);
- ri += *dp++;
- dp++;
- tei = *dp >> 1;
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi, "identity denied ri %d tei %d",
- ri, tei);
-}
-
-static void
-tei_id_chk_req(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
- u_char *dp = arg;
- int tei;
-
- tei = *(dp + 3) >> 1;
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi, "identity check req tei %d", tei);
- if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) ||
- (tei == tm->l2->tei))) {
- mISDN_FsmDelTimer(&tm->timer, 4);
- mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP);
- put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei);
- }
-}
-
-static void
-tei_id_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
- u_char *dp = arg;
- int tei;
-
- tei = *(dp + 3) >> 1;
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi, "identity remove tei %d", tei);
- if ((tm->l2->tei != GROUP_TEI) &&
- ((tei == GROUP_TEI) || (tei == tm->l2->tei))) {
- mISDN_FsmDelTimer(&tm->timer, 5);
- mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP);
- tei_l2(tm->l2, MDL_REMOVE_REQ, 0);
- }
-}
-
-static void
-tei_id_verify(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
-
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi, "id verify request for tei %d",
- tm->l2->tei);
- put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei);
- mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY);
- mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2);
- tm->nval = 2;
-}
-
-static void
-tei_id_req_tout(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
-
- if (--tm->nval) {
- tm->ri = random_ri();
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi, "assign req(%d) ri %d",
- 4 - tm->nval, tm->ri);
- put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI);
- mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3);
- } else {
- tm->tei_m.printdebug(fi, "assign req failed");
- tei_l2(tm->l2, MDL_ERROR_RSP, 0);
- mISDN_FsmChangeState(fi, ST_TEI_NOP);
- }
-}
-
-static void
-tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
-
- if (--tm->nval) {
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi,
- "id verify req(%d) for tei %d",
- 3 - tm->nval, tm->l2->tei);
- put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei);
- mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4);
- } else {
- tm->tei_m.printdebug(fi, "verify req for tei %d failed",
- tm->l2->tei);
- tei_l2(tm->l2, MDL_REMOVE_REQ, 0);
- mISDN_FsmChangeState(fi, ST_TEI_NOP);
- }
-}
-
-static struct FsmNode TeiFnListUser[] =
-{
- {ST_TEI_NOP, EV_IDREQ, tei_id_request},
- {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup},
- {ST_TEI_NOP, EV_VERIFY, tei_id_verify},
- {ST_TEI_NOP, EV_REMOVE, tei_id_remove},
- {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req},
- {ST_TEI_IDREQ, EV_TIMER, tei_id_req_tout},
- {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign},
- {ST_TEI_IDREQ, EV_DENIED, tei_id_denied},
- {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout},
- {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
- {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
-};
-
-static void
-tei_l2remove(struct layer2 *l2)
-{
- put_tei_msg(l2->tm->mgr, ID_REMOVE, 0, l2->tei);
- tei_l2(l2, MDL_REMOVE_REQ, 0);
- list_del(&l2->ch.list);
- l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
-}
-
-static void
-tei_assign_req(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
- u_char *dp = arg;
-
- if (tm->l2->tei == GROUP_TEI) {
- tm->tei_m.printdebug(&tm->tei_m,
- "net tei assign request without tei");
- return;
- }
- tm->ri = ((unsigned int) *dp++ << 8);
- tm->ri += *dp++;
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(&tm->tei_m,
- "net assign request ri %d teim %d", tm->ri, *dp);
- put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei);
- mISDN_FsmChangeState(fi, ST_TEI_NOP);
-}
-
-static void
-tei_id_chk_req_net(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
-
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi, "id check request for tei %d",
- tm->l2->tei);
- tm->rcnt = 0;
- put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei);
- mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY);
- mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2);
- tm->nval = 2;
-}
-
-static void
-tei_id_chk_resp(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
- u_char *dp = arg;
- int tei;
-
- tei = dp[3] >> 1;
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi, "identity check resp tei %d", tei);
- if (tei == tm->l2->tei)
- tm->rcnt++;
-}
-
-static void
-tei_id_verify_net(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
- u_char *dp = arg;
- int tei;
-
- tei = dp[3] >> 1;
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi, "identity verify req tei %d/%d",
- tei, tm->l2->tei);
- if (tei == tm->l2->tei)
- tei_id_chk_req_net(fi, event, arg);
-}
-
-static void
-tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg)
-{
- struct teimgr *tm = fi->userdata;
-
- if (tm->rcnt == 1) {
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi,
- "check req for tei %d successful\n", tm->l2->tei);
- mISDN_FsmChangeState(fi, ST_TEI_NOP);
- } else if (tm->rcnt > 1) {
- /* duplicate assignment; remove */
- tei_l2remove(tm->l2);
- } else if (--tm->nval) {
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(fi,
- "id check req(%d) for tei %d",
- 3 - tm->nval, tm->l2->tei);
- put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei);
- mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4);
- } else {
- tm->tei_m.printdebug(fi, "check req for tei %d failed",
- tm->l2->tei);
- mISDN_FsmChangeState(fi, ST_TEI_NOP);
- tei_l2remove(tm->l2);
- }
-}
-
-static struct FsmNode TeiFnListNet[] =
-{
- {ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req},
- {ST_TEI_NOP, EV_VERIFY, tei_id_verify_net},
- {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req_net},
- {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout_net},
- {ST_TEI_IDVERIFY, EV_CHKRESP, tei_id_chk_resp},
-};
-
-static void
-tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len)
-{
- if (test_bit(FLG_FIXED_TEI, &tm->l2->flag))
- return;
- if (*debug & DEBUG_L2_TEI)
- tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt);
- if (mt == ID_ASSIGNED)
- mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp);
- else if (mt == ID_DENIED)
- mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp);
- else if (mt == ID_CHK_REQ)
- mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp);
- else if (mt == ID_REMOVE)
- mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp);
- else if (mt == ID_VERIFY)
- mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, dp);
- else if (mt == ID_CHK_RES)
- mISDN_FsmEvent(&tm->tei_m, EV_CHKRESP, dp);
-}
-
-static struct layer2 *
-create_new_tei(struct manager *mgr, int tei, int sapi)
-{
- unsigned long opt = 0;
- unsigned long flags;
- int id;
- struct layer2 *l2;
- struct channel_req rq;
-
- if (!mgr->up)
- return NULL;
- if ((tei >= 0) && (tei < 64))
- test_and_set_bit(OPTION_L2_FIXEDTEI, &opt);
- if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) |
- (1 << ISDN_P_NT_E1))) {
- test_and_set_bit(OPTION_L2_PMX, &opt);
- rq.protocol = ISDN_P_NT_E1;
- } else {
- rq.protocol = ISDN_P_NT_S0;
- }
- l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi);
- if (!l2) {
- printk(KERN_WARNING "%s:no memory for layer2\n", __func__);
- return NULL;
- }
- l2->tm = kzalloc_obj(struct teimgr);
- if (!l2->tm) {
- kfree(l2);
- printk(KERN_WARNING "%s:no memory for teimgr\n", __func__);
- return NULL;
- }
- l2->tm->mgr = mgr;
- l2->tm->l2 = l2;
- l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM;
- l2->tm->tei_m.userdata = l2->tm;
- l2->tm->tei_m.printdebug = tei_debug;
- l2->tm->tei_m.fsm = &teifsmn;
- l2->tm->tei_m.state = ST_TEI_NOP;
- l2->tm->tval = 2000; /* T202 2 sec */
- mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer);
- write_lock_irqsave(&mgr->lock, flags);
- id = get_free_id(mgr);
- list_add_tail(&l2->list, &mgr->layer2);
- write_unlock_irqrestore(&mgr->lock, flags);
- if (id < 0) {
- l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
- printk(KERN_WARNING "%s:no free id\n", __func__);
- return NULL;
- } else {
- l2->ch.nr = id;
- __add_layer2(&l2->ch, mgr->ch.st);
- l2->ch.recv = mgr->ch.recv;
- l2->ch.peer = mgr->ch.peer;
- l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL);
- /* We need open here L1 for the manager as well (refcounting) */
- rq.adr.dev = mgr->ch.st->dev->id;
- id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq);
- if (id < 0) {
- printk(KERN_WARNING "%s: cannot open L1\n", __func__);
- l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
- l2 = NULL;
- }
- }
- return l2;
-}
-
-static void
-new_tei_req(struct manager *mgr, u_char *dp)
-{
- int tei, ri;
- struct layer2 *l2;
-
- ri = dp[0] << 8;
- ri += dp[1];
- if (!mgr->up)
- goto denied;
- if (!(dp[3] & 1)) /* Extension bit != 1 */
- goto denied;
- if (dp[3] != 0xff)
- tei = dp[3] >> 1; /* 3GPP TS 08.56 6.1.11.2 */
- else
- tei = get_free_tei(mgr);
- if (tei < 0) {
- printk(KERN_WARNING "%s:No free tei\n", __func__);
- goto denied;
- }
- l2 = create_new_tei(mgr, tei, CTRL_SAPI);
- if (!l2)
- goto denied;
- else
- mISDN_FsmEvent(&l2->tm->tei_m, EV_ASSIGN_REQ, dp);
- return;
-denied:
- put_tei_msg(mgr, ID_DENIED, ri, GROUP_TEI);
-}
-
-static int
-ph_data_ind(struct manager *mgr, struct sk_buff *skb)
-{
- int ret = -EINVAL;
- struct layer2 *l2, *nl2;
- u_char mt;
-
- if (skb->len < 8) {
- if (*debug & DEBUG_L2_TEI)
- printk(KERN_DEBUG "%s: short mgr frame %d/8\n",
- __func__, skb->len);
- goto done;
- }
-
- if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */
- goto done;
- if (skb->data[0] & 1) /* EA0 formal error */
- goto done;
- if (!(skb->data[1] & 1)) /* EA1 formal error */
- goto done;
- if ((skb->data[1] >> 1) != GROUP_TEI) /* not for us */
- goto done;
- if ((skb->data[2] & 0xef) != UI) /* not UI */
- goto done;
- if (skb->data[3] != TEI_ENTITY_ID) /* not tei entity */
- goto done;
- mt = skb->data[6];
- switch (mt) {
- case ID_REQUEST:
- case ID_CHK_RES:
- case ID_VERIFY:
- if (!test_bit(MGR_OPT_NETWORK, &mgr->options))
- goto done;
- break;
- case ID_ASSIGNED:
- case ID_DENIED:
- case ID_CHK_REQ:
- case ID_REMOVE:
- if (test_bit(MGR_OPT_NETWORK, &mgr->options))
- goto done;
- break;
- default:
- goto done;
- }
- ret = 0;
- if (mt == ID_REQUEST) {
- new_tei_req(mgr, &skb->data[4]);
- goto done;
- }
- list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
- tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4);
- }
-done:
- return ret;
-}
-
-int
-l2_tei(struct layer2 *l2, u_int cmd, u_long arg)
-{
- struct teimgr *tm = l2->tm;
-
- if (test_bit(FLG_FIXED_TEI, &l2->flag))
- return 0;
- if (*debug & DEBUG_L2_TEI)
- printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd);
- switch (cmd) {
- case MDL_ASSIGN_IND:
- mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL);
- break;
- case MDL_ERROR_IND:
- if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
- mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, &l2->tei);
- if (test_bit(MGR_OPT_USER, &tm->mgr->options))
- mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL);
- break;
- case MDL_STATUS_UP_IND:
- if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
- mISDN_FsmEvent(&tm->mgr->deact, EV_ACTIVATE, NULL);
- break;
- case MDL_STATUS_DOWN_IND:
- if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
- mISDN_FsmEvent(&tm->mgr->deact, EV_DEACTIVATE, NULL);
- break;
- case MDL_STATUS_UI_IND:
- if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options))
- mISDN_FsmEvent(&tm->mgr->deact, EV_UI, NULL);
- break;
- }
- return 0;
-}
-
-void
-TEIrelease(struct layer2 *l2)
-{
- struct teimgr *tm = l2->tm;
- u_long flags;
-
- mISDN_FsmDelTimer(&tm->timer, 1);
- write_lock_irqsave(&tm->mgr->lock, flags);
- list_del(&l2->list);
- write_unlock_irqrestore(&tm->mgr->lock, flags);
- l2->tm = NULL;
- kfree(tm);
-}
-
-static int
-create_teimgr(struct manager *mgr, struct channel_req *crq)
-{
- struct layer2 *l2;
- unsigned long opt = 0;
- unsigned long flags;
- int id;
- struct channel_req l1rq;
-
- if (*debug & DEBUG_L2_TEI)
- printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
- __func__, dev_name(&mgr->ch.st->dev->dev),
- crq->protocol, crq->adr.dev, crq->adr.channel,
- crq->adr.sapi, crq->adr.tei);
- if (crq->adr.tei > GROUP_TEI)
- return -EINVAL;
- if (crq->adr.tei < 64)
- test_and_set_bit(OPTION_L2_FIXEDTEI, &opt);
- if (crq->adr.tei == 0)
- test_and_set_bit(OPTION_L2_PTP, &opt);
- if (test_bit(MGR_OPT_NETWORK, &mgr->options)) {
- if (crq->protocol == ISDN_P_LAPD_TE)
- return -EPROTONOSUPPORT;
- if ((crq->adr.tei != 0) && (crq->adr.tei != 127))
- return -EINVAL;
- if (mgr->up) {
- printk(KERN_WARNING
- "%s: only one network manager is allowed\n",
- __func__);
- return -EBUSY;
- }
- } else if (test_bit(MGR_OPT_USER, &mgr->options)) {
- if (crq->protocol == ISDN_P_LAPD_NT)
- return -EPROTONOSUPPORT;
- if ((crq->adr.tei >= 64) && (crq->adr.tei < GROUP_TEI))
- return -EINVAL; /* dyn tei */
- } else {
- if (crq->protocol == ISDN_P_LAPD_NT)
- test_and_set_bit(MGR_OPT_NETWORK, &mgr->options);
- if (crq->protocol == ISDN_P_LAPD_TE)
- test_and_set_bit(MGR_OPT_USER, &mgr->options);
- }
- l1rq.adr = crq->adr;
- if (mgr->ch.st->dev->Dprotocols
- & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1)))
- test_and_set_bit(OPTION_L2_PMX, &opt);
- if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) {
- mgr->up = crq->ch;
- id = DL_INFO_L2_CONNECT;
- teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id);
- if (test_bit(MGR_PH_ACTIVE, &mgr->options))
- teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL);
- crq->ch = NULL;
- if (!list_empty(&mgr->layer2)) {
- read_lock_irqsave(&mgr->lock, flags);
- list_for_each_entry(l2, &mgr->layer2, list) {
- l2->up = mgr->up;
- l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL);
- }
- read_unlock_irqrestore(&mgr->lock, flags);
- }
- return 0;
- }
- l2 = create_l2(crq->ch, crq->protocol, opt,
- crq->adr.tei, crq->adr.sapi);
- if (!l2)
- return -ENOMEM;
- l2->tm = kzalloc_obj(struct teimgr);
- if (!l2->tm) {
- kfree(l2);
- printk(KERN_ERR "kmalloc teimgr failed\n");
- return -ENOMEM;
- }
- l2->tm->mgr = mgr;
- l2->tm->l2 = l2;
- l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM;
- l2->tm->tei_m.userdata = l2->tm;
- l2->tm->tei_m.printdebug = tei_debug;
- if (crq->protocol == ISDN_P_LAPD_TE) {
- l2->tm->tei_m.fsm = &teifsmu;
- l2->tm->tei_m.state = ST_TEI_NOP;
- l2->tm->tval = 1000; /* T201 1 sec */
- if (test_bit(OPTION_L2_PMX, &opt))
- l1rq.protocol = ISDN_P_TE_E1;
- else
- l1rq.protocol = ISDN_P_TE_S0;
- } else {
- l2->tm->tei_m.fsm = &teifsmn;
- l2->tm->tei_m.state = ST_TEI_NOP;
- l2->tm->tval = 2000; /* T202 2 sec */
- if (test_bit(OPTION_L2_PMX, &opt))
- l1rq.protocol = ISDN_P_NT_E1;
- else
- l1rq.protocol = ISDN_P_NT_S0;
- }
- mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer);
- write_lock_irqsave(&mgr->lock, flags);
- id = get_free_id(mgr);
- list_add_tail(&l2->list, &mgr->layer2);
- write_unlock_irqrestore(&mgr->lock, flags);
- if (id >= 0) {
- l2->ch.nr = id;
- l2->up->nr = id;
- crq->ch = &l2->ch;
- /* We need open here L1 for the manager as well (refcounting) */
- id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL,
- &l1rq);
- }
- if (id < 0)
- l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
- return id;
-}
-
-static int
-mgr_send(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct manager *mgr;
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- int ret = -EINVAL;
-
- mgr = container_of(ch, struct manager, ch);
- if (*debug & DEBUG_L2_RECV)
- printk(KERN_DEBUG "%s: prim(%x) id(%x)\n",
- __func__, hh->prim, hh->id);
- switch (hh->prim) {
- case PH_DATA_IND:
- mISDN_FsmEvent(&mgr->deact, EV_UI, NULL);
- ret = ph_data_ind(mgr, skb);
- break;
- case PH_DATA_CNF:
- do_ack(mgr, hh->id);
- ret = 0;
- break;
- case PH_ACTIVATE_IND:
- test_and_set_bit(MGR_PH_ACTIVE, &mgr->options);
- if (mgr->up)
- teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL);
- mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL);
- do_send(mgr);
- ret = 0;
- break;
- case PH_DEACTIVATE_IND:
- test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options);
- if (mgr->up)
- teiup_create(mgr, PH_DEACTIVATE_IND, 0, NULL);
- mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL);
- ret = 0;
- break;
- case DL_UNITDATA_REQ:
- return dl_unit_data(mgr, skb);
- }
- if (!ret)
- dev_kfree_skb(skb);
- return ret;
-}
-
-static int
-free_teimanager(struct manager *mgr)
-{
- struct layer2 *l2, *nl2;
-
- test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
- if (test_bit(MGR_OPT_NETWORK, &mgr->options)) {
- /* not locked lock is taken in release tei */
- mgr->up = NULL;
- if (test_bit(OPTION_L2_CLEANUP, &mgr->options)) {
- list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
- put_tei_msg(mgr, ID_REMOVE, 0, l2->tei);
- mutex_lock(&mgr->ch.st->lmutex);
- list_del(&l2->ch.list);
- mutex_unlock(&mgr->ch.st->lmutex);
- l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
- }
- test_and_clear_bit(MGR_OPT_NETWORK, &mgr->options);
- } else {
- list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
- l2->up = NULL;
- }
- }
- }
- if (test_bit(MGR_OPT_USER, &mgr->options)) {
- if (list_empty(&mgr->layer2))
- test_and_clear_bit(MGR_OPT_USER, &mgr->options);
- }
- mgr->ch.st->dev->D.ctrl(&mgr->ch.st->dev->D, CLOSE_CHANNEL, NULL);
- return 0;
-}
-
-static int
-ctrl_teimanager(struct manager *mgr, void *arg)
-{
- /* currently we only have one option */
- unsigned int *val = (unsigned int *)arg;
-
- switch (val[0]) {
- case IMCLEAR_L2:
- if (val[1])
- test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options);
- else
- test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options);
- break;
- case IMHOLD_L1:
- if (val[1])
- test_and_set_bit(OPTION_L1_HOLD, &mgr->options);
- else
- test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-/* This function does create a L2 for fixed TEI in NT Mode */
-static int
-check_data(struct manager *mgr, struct sk_buff *skb)
-{
- struct mISDNhead *hh = mISDN_HEAD_P(skb);
- int ret, tei, sapi;
- struct layer2 *l2;
-
- if (*debug & DEBUG_L2_CTRL)
- printk(KERN_DEBUG "%s: prim(%x) id(%x)\n",
- __func__, hh->prim, hh->id);
- if (test_bit(MGR_OPT_USER, &mgr->options))
- return -ENOTCONN;
- if (hh->prim != PH_DATA_IND)
- return -ENOTCONN;
- if (skb->len != 3)
- return -ENOTCONN;
- if (skb->data[0] & 3) /* EA0 and CR must be 0 */
- return -EINVAL;
- sapi = skb->data[0] >> 2;
- if (!(skb->data[1] & 1)) /* invalid EA1 */
- return -EINVAL;
- tei = skb->data[1] >> 1;
- if (tei > 63) /* not a fixed tei */
- return -ENOTCONN;
- if ((skb->data[2] & ~0x10) != SABME)
- return -ENOTCONN;
- /* We got a SABME for a fixed TEI */
- if (*debug & DEBUG_L2_CTRL)
- printk(KERN_DEBUG "%s: SABME sapi(%d) tei(%d)\n",
- __func__, sapi, tei);
- l2 = create_new_tei(mgr, tei, sapi);
- if (!l2) {
- if (*debug & DEBUG_L2_CTRL)
- printk(KERN_DEBUG "%s: failed to create new tei\n",
- __func__);
- return -ENOMEM;
- }
- ret = l2->ch.send(&l2->ch, skb);
- return ret;
-}
-
-void
-delete_teimanager(struct mISDNchannel *ch)
-{
- struct manager *mgr;
- struct layer2 *l2, *nl2;
-
- mgr = container_of(ch, struct manager, ch);
- /* not locked lock is taken in release tei */
- list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) {
- mutex_lock(&mgr->ch.st->lmutex);
- list_del(&l2->ch.list);
- mutex_unlock(&mgr->ch.st->lmutex);
- l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
- }
- list_del(&mgr->ch.list);
- list_del(&mgr->bcast.list);
- skb_queue_purge(&mgr->sendq);
- kfree(mgr);
-}
-
-static int
-mgr_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
- struct manager *mgr;
- int ret = -EINVAL;
-
- mgr = container_of(ch, struct manager, ch);
- if (*debug & DEBUG_L2_CTRL)
- printk(KERN_DEBUG "%s(%x, %p)\n", __func__, cmd, arg);
- switch (cmd) {
- case OPEN_CHANNEL:
- ret = create_teimgr(mgr, arg);
- break;
- case CLOSE_CHANNEL:
- ret = free_teimanager(mgr);
- break;
- case CONTROL_CHANNEL:
- ret = ctrl_teimanager(mgr, arg);
- break;
- case CHECK_DATA:
- ret = check_data(mgr, arg);
- break;
- }
- return ret;
-}
-
-static int
-mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb)
-{
- struct manager *mgr = container_of(ch, struct manager, bcast);
- struct mISDNhead *hhc, *hh = mISDN_HEAD_P(skb);
- struct sk_buff *cskb = NULL;
- struct layer2 *l2;
- u_long flags;
- int ret;
-
- read_lock_irqsave(&mgr->lock, flags);
- list_for_each_entry(l2, &mgr->layer2, list) {
- if ((hh->id & MISDN_ID_SAPI_MASK) ==
- (l2->ch.addr & MISDN_ID_SAPI_MASK)) {
- if (list_is_last(&l2->list, &mgr->layer2)) {
- cskb = skb;
- skb = NULL;
- } else {
- if (!cskb)
- cskb = skb_copy(skb, GFP_ATOMIC);
- }
- if (cskb) {
- hhc = mISDN_HEAD_P(cskb);
- /* save original header behind normal header */
- hhc++;
- *hhc = *hh;
- hhc--;
- hhc->prim = DL_INTERN_MSG;
- hhc->id = l2->ch.nr;
- ret = ch->st->own.recv(&ch->st->own, cskb);
- if (ret) {
- if (*debug & DEBUG_SEND_ERR)
- printk(KERN_DEBUG
- "%s ch%d prim(%x) addr(%x)"
- " err %d\n",
- __func__, l2->ch.nr,
- hh->prim, l2->ch.addr, ret);
- } else
- cskb = NULL;
- } else {
- printk(KERN_WARNING "%s ch%d addr %x no mem\n",
- __func__, ch->nr, ch->addr);
- goto out;
- }
- }
- }
-out:
- read_unlock_irqrestore(&mgr->lock, flags);
- dev_kfree_skb(cskb);
- dev_kfree_skb(skb);
- return 0;
-}
-
-static int
-mgr_bcast_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
-{
-
- return -EINVAL;
-}
-
-int
-create_teimanager(struct mISDNdevice *dev)
-{
- struct manager *mgr;
-
- mgr = kzalloc_obj(struct manager);
- if (!mgr)
- return -ENOMEM;
- INIT_LIST_HEAD(&mgr->layer2);
- rwlock_init(&mgr->lock);
- skb_queue_head_init(&mgr->sendq);
- mgr->nextid = 1;
- mgr->lastid = MISDN_ID_NONE;
- mgr->ch.send = mgr_send;
- mgr->ch.ctrl = mgr_ctrl;
- mgr->ch.st = dev->D.st;
- set_channel_address(&mgr->ch, TEI_SAPI, GROUP_TEI);
- add_layer2(&mgr->ch, dev->D.st);
- mgr->bcast.send = mgr_bcast;
- mgr->bcast.ctrl = mgr_bcast_ctrl;
- mgr->bcast.st = dev->D.st;
- set_channel_address(&mgr->bcast, 0, GROUP_TEI);
- add_layer2(&mgr->bcast, dev->D.st);
- mgr->deact.debug = *debug & DEBUG_MANAGER;
- mgr->deact.userdata = mgr;
- mgr->deact.printdebug = da_debug;
- mgr->deact.fsm = &deactfsm;
- mgr->deact.state = ST_L1_DEACT;
- mISDN_FsmInitTimer(&mgr->deact, &mgr->datimer);
- dev->teimgr = &mgr->ch;
- return 0;
-}
-
-int TEIInit(u_int *deb)
-{
- int res;
- debug = deb;
- teifsmu.state_count = TEI_STATE_COUNT;
- teifsmu.event_count = TEI_EVENT_COUNT;
- teifsmu.strEvent = strTeiEvent;
- teifsmu.strState = strTeiState;
- res = mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser));
- if (res)
- goto error;
- teifsmn.state_count = TEI_STATE_COUNT;
- teifsmn.event_count = TEI_EVENT_COUNT;
- teifsmn.strEvent = strTeiEvent;
- teifsmn.strState = strTeiState;
- res = mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet));
- if (res)
- goto error_smn;
- deactfsm.state_count = DEACT_STATE_COUNT;
- deactfsm.event_count = DEACT_EVENT_COUNT;
- deactfsm.strEvent = strDeactEvent;
- deactfsm.strState = strDeactState;
- res = mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList));
- if (res)
- goto error_deact;
- return 0;
-
-error_deact:
- mISDN_FsmFree(&teifsmn);
-error_smn:
- mISDN_FsmFree(&teifsmu);
-error:
- return res;
-}
-
-void TEIFree(void)
-{
- mISDN_FsmFree(&teifsmu);
- mISDN_FsmFree(&teifsmn);
- mISDN_FsmFree(&deactfsm);
-}
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *
- * general timer device for using in ISDN stacks
- *
- * Author Karsten Keil <kkeil@novell.com>
- *
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#include <linux/poll.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/mISDNif.h>
-#include <linux/mutex.h>
-#include <linux/sched/signal.h>
-
-#include "core.h"
-
-static DEFINE_MUTEX(mISDN_mutex);
-static u_int *debug;
-
-
-struct mISDNtimerdev {
- int next_id;
- struct list_head pending;
- struct list_head expired;
- wait_queue_head_t wait;
- u_int work;
- spinlock_t lock; /* protect lists */
-};
-
-struct mISDNtimer {
- struct list_head list;
- struct mISDNtimerdev *dev;
- struct timer_list tl;
- int id;
-};
-
-static int
-mISDN_open(struct inode *ino, struct file *filep)
-{
- struct mISDNtimerdev *dev;
-
- if (*debug & DEBUG_TIMER)
- printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep);
- dev = kmalloc_obj(struct mISDNtimerdev);
- if (!dev)
- return -ENOMEM;
- dev->next_id = 1;
- INIT_LIST_HEAD(&dev->pending);
- INIT_LIST_HEAD(&dev->expired);
- spin_lock_init(&dev->lock);
- dev->work = 0;
- init_waitqueue_head(&dev->wait);
- filep->private_data = dev;
- return nonseekable_open(ino, filep);
-}
-
-static int
-mISDN_close(struct inode *ino, struct file *filep)
-{
- struct mISDNtimerdev *dev = filep->private_data;
- struct list_head *list = &dev->pending;
- struct mISDNtimer *timer, *next;
-
- if (*debug & DEBUG_TIMER)
- printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep);
-
- spin_lock_irq(&dev->lock);
- while (!list_empty(list)) {
- timer = list_first_entry(list, struct mISDNtimer, list);
- spin_unlock_irq(&dev->lock);
- timer_shutdown_sync(&timer->tl);
- spin_lock_irq(&dev->lock);
- /* it might have been moved to ->expired */
- list_del(&timer->list);
- kfree(timer);
- }
- spin_unlock_irq(&dev->lock);
-
- list_for_each_entry_safe(timer, next, &dev->expired, list) {
- kfree(timer);
- }
- kfree(dev);
- return 0;
-}
-
-static ssize_t
-mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off)
-{
- struct mISDNtimerdev *dev = filep->private_data;
- struct list_head *list = &dev->expired;
- struct mISDNtimer *timer;
- int ret = 0;
-
- if (*debug & DEBUG_TIMER)
- printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__,
- filep, buf, (int)count, off);
-
- if (count < sizeof(int))
- return -ENOSPC;
-
- spin_lock_irq(&dev->lock);
- while (list_empty(list) && (dev->work == 0)) {
- spin_unlock_irq(&dev->lock);
- if (filep->f_flags & O_NONBLOCK)
- return -EAGAIN;
- wait_event_interruptible(dev->wait, (READ_ONCE(dev->work) ||
- !list_empty(list)));
- if (signal_pending(current))
- return -ERESTARTSYS;
- spin_lock_irq(&dev->lock);
- }
- if (dev->work)
- WRITE_ONCE(dev->work, 0);
- if (!list_empty(list)) {
- timer = list_first_entry(list, struct mISDNtimer, list);
- list_del(&timer->list);
- spin_unlock_irq(&dev->lock);
- if (put_user(timer->id, (int __user *)buf))
- ret = -EFAULT;
- else
- ret = sizeof(int);
- kfree(timer);
- } else {
- spin_unlock_irq(&dev->lock);
- }
- return ret;
-}
-
-static __poll_t
-mISDN_poll(struct file *filep, poll_table *wait)
-{
- struct mISDNtimerdev *dev = filep->private_data;
- __poll_t mask = EPOLLERR;
-
- if (*debug & DEBUG_TIMER)
- printk(KERN_DEBUG "%s(%p, %p)\n", __func__, filep, wait);
- if (dev) {
- u32 work;
-
- poll_wait(filep, &dev->wait, wait);
- mask = 0;
- work = READ_ONCE(dev->work);
- if (work || !list_empty(&dev->expired))
- mask |= (EPOLLIN | EPOLLRDNORM);
- if (*debug & DEBUG_TIMER)
- printk(KERN_DEBUG "%s work(%d) empty(%d)\n", __func__,
- work, list_empty(&dev->expired));
- }
- return mask;
-}
-
-static void
-dev_expire_timer(struct timer_list *t)
-{
- struct mISDNtimer *timer = timer_container_of(timer, t, tl);
- u_long flags;
-
- spin_lock_irqsave(&timer->dev->lock, flags);
- if (timer->id >= 0)
- list_move_tail(&timer->list, &timer->dev->expired);
- wake_up_interruptible(&timer->dev->wait);
- spin_unlock_irqrestore(&timer->dev->lock, flags);
-}
-
-static int
-misdn_add_timer(struct mISDNtimerdev *dev, int timeout)
-{
- int id;
- struct mISDNtimer *timer;
-
- if (!timeout) {
- WRITE_ONCE(dev->work, 1);
- wake_up_interruptible(&dev->wait);
- id = 0;
- } else {
- timer = kzalloc_obj(struct mISDNtimer);
- if (!timer)
- return -ENOMEM;
- timer->dev = dev;
- timer_setup(&timer->tl, dev_expire_timer, 0);
- spin_lock_irq(&dev->lock);
- id = timer->id = dev->next_id++;
- if (dev->next_id < 0)
- dev->next_id = 1;
- list_add_tail(&timer->list, &dev->pending);
- timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000);
- add_timer(&timer->tl);
- spin_unlock_irq(&dev->lock);
- }
- return id;
-}
-
-static int
-misdn_del_timer(struct mISDNtimerdev *dev, int id)
-{
- struct mISDNtimer *timer;
-
- spin_lock_irq(&dev->lock);
- list_for_each_entry(timer, &dev->pending, list) {
- if (timer->id == id) {
- list_del_init(&timer->list);
- timer->id = -1;
- spin_unlock_irq(&dev->lock);
- timer_shutdown_sync(&timer->tl);
- kfree(timer);
- return id;
- }
- }
- spin_unlock_irq(&dev->lock);
- return 0;
-}
-
-static long
-mISDN_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
-{
- struct mISDNtimerdev *dev = filep->private_data;
- int id, tout, ret = 0;
-
-
- if (*debug & DEBUG_TIMER)
- printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__,
- filep, cmd, arg);
- mutex_lock(&mISDN_mutex);
- switch (cmd) {
- case IMADDTIMER:
- if (get_user(tout, (int __user *)arg)) {
- ret = -EFAULT;
- break;
- }
- id = misdn_add_timer(dev, tout);
- if (*debug & DEBUG_TIMER)
- printk(KERN_DEBUG "%s add %d id %d\n", __func__,
- tout, id);
- if (id < 0) {
- ret = id;
- break;
- }
- if (put_user(id, (int __user *)arg))
- ret = -EFAULT;
- break;
- case IMDELTIMER:
- if (get_user(id, (int __user *)arg)) {
- ret = -EFAULT;
- break;
- }
- if (*debug & DEBUG_TIMER)
- printk(KERN_DEBUG "%s del id %d\n", __func__, id);
- id = misdn_del_timer(dev, id);
- if (put_user(id, (int __user *)arg))
- ret = -EFAULT;
- break;
- default:
- ret = -EINVAL;
- }
- mutex_unlock(&mISDN_mutex);
- return ret;
-}
-
-static const struct file_operations mISDN_fops = {
- .owner = THIS_MODULE,
- .read = mISDN_read,
- .poll = mISDN_poll,
- .unlocked_ioctl = mISDN_ioctl,
- .open = mISDN_open,
- .release = mISDN_close,
-};
-
-static struct miscdevice mISDNtimer = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "mISDNtimer",
- .fops = &mISDN_fops,
-};
-
-int
-mISDN_inittimer(u_int *deb)
-{
- int err;
-
- debug = deb;
- err = misc_register(&mISDNtimer);
- if (err)
- printk(KERN_WARNING "mISDN: Could not register timer device\n");
- return err;
-}
-
-void mISDN_timer_cleanup(void)
-{
- misc_deregister(&mISDNtimer);
-}
+++ /dev/null
-/* $Id: capilli.h,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
- *
- * Kernel CAPI 2.0 Driver Interface for Linux
- *
- * Copyright 1999 by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef __CAPILLI_H__
-#define __CAPILLI_H__
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/capi.h>
-#include <linux/kernelcapi.h>
-
-typedef struct capiloaddatapart {
- int user; /* data in userspace ? */
- int len;
- unsigned char *data;
-} capiloaddatapart;
-
-typedef struct capiloaddata {
- capiloaddatapart firmware;
- capiloaddatapart configuration;
-} capiloaddata;
-
-typedef struct capicardparams {
- unsigned int port;
- unsigned irq;
- int cardtype;
- int cardnr;
- unsigned int membase;
-} capicardparams;
-
-struct capi_ctr {
- /* filled in before calling attach_capi_ctr */
- struct module *owner;
- void *driverdata; /* driver specific */
- char name[32]; /* name of controller */
- char *driver_name; /* name of driver */
- int (*load_firmware)(struct capi_ctr *, capiloaddata *);
- void (*reset_ctr)(struct capi_ctr *);
- void (*register_appl)(struct capi_ctr *, u16 appl,
- capi_register_params *);
- void (*release_appl)(struct capi_ctr *, u16 appl);
- u16 (*send_message)(struct capi_ctr *, struct sk_buff *skb);
-
- char *(*procinfo)(struct capi_ctr *);
- int (*proc_show)(struct seq_file *, void *);
-
- /* filled in before calling ready callback */
- u8 manu[CAPI_MANUFACTURER_LEN]; /* CAPI_GET_MANUFACTURER */
- capi_version version; /* CAPI_GET_VERSION */
- capi_profile profile; /* CAPI_GET_PROFILE */
- u8 serial[CAPI_SERIAL_LEN]; /* CAPI_GET_SERIAL */
-
- /* management information for kcapi */
-
- unsigned long nrecvctlpkt;
- unsigned long nrecvdatapkt;
- unsigned long nsentctlpkt;
- unsigned long nsentdatapkt;
-
- int cnr; /* controller number */
- unsigned short state; /* controller state */
- int blocked; /* output blocked */
- int traceflag; /* capi trace */
-
- struct proc_dir_entry *procent;
- char procfn[128];
-};
-
-int attach_capi_ctr(struct capi_ctr *);
-int detach_capi_ctr(struct capi_ctr *);
-
-void capi_ctr_ready(struct capi_ctr * card);
-void capi_ctr_down(struct capi_ctr * card);
-void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb);
-
-// ---------------------------------------------------------------------------
-// needed for AVM capi drivers
-
-struct capi_driver {
- char name[32]; /* driver name */
- char revision[32];
-
- /* management information for kcapi */
- struct list_head list;
-};
-
-#endif /* __CAPILLI_H__ */
+++ /dev/null
-/* $Id: capiutil.h,v 1.5.6.2 2001/09/23 22:24:33 kai Exp $
- *
- * CAPI 2.0 defines & types
- *
- * From CAPI 2.0 Development Kit AVM 1995 (msg.c)
- * Rewritten for Linux 1996 by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef __CAPIUTIL_H__
-#define __CAPIUTIL_H__
-
-#include <asm/types.h>
-
-#define CAPIMSG_BASELEN 8
-#define CAPIMSG_U8(m, off) (m[off])
-#define CAPIMSG_U16(m, off) (m[off]|(m[(off)+1]<<8))
-#define CAPIMSG_U32(m, off) (m[off]|(m[(off)+1]<<8)|(m[(off)+2]<<16)|(m[(off)+3]<<24))
-#define CAPIMSG_LEN(m) CAPIMSG_U16(m,0)
-#define CAPIMSG_APPID(m) CAPIMSG_U16(m,2)
-#define CAPIMSG_COMMAND(m) CAPIMSG_U8(m,4)
-#define CAPIMSG_SUBCOMMAND(m) CAPIMSG_U8(m,5)
-#define CAPIMSG_CMD(m) (((m[4])<<8)|(m[5]))
-#define CAPIMSG_MSGID(m) CAPIMSG_U16(m,6)
-#define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f)
-#define CAPIMSG_CONTROL(m) CAPIMSG_U32(m, 8)
-#define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m)
-#define CAPIMSG_DATALEN(m) CAPIMSG_U16(m,16) /* DATA_B3_REQ */
-
-static inline void capimsg_setu8(void *m, int off, __u8 val)
-{
- ((__u8 *)m)[off] = val;
-}
-
-static inline void capimsg_setu16(void *m, int off, __u16 val)
-{
- ((__u8 *)m)[off] = val & 0xff;
- ((__u8 *)m)[off+1] = (val >> 8) & 0xff;
-}
-
-static inline void capimsg_setu32(void *m, int off, __u32 val)
-{
- ((__u8 *)m)[off] = val & 0xff;
- ((__u8 *)m)[off+1] = (val >> 8) & 0xff;
- ((__u8 *)m)[off+2] = (val >> 16) & 0xff;
- ((__u8 *)m)[off+3] = (val >> 24) & 0xff;
-}
-
-#define CAPIMSG_SETLEN(m, len) capimsg_setu16(m, 0, len)
-#define CAPIMSG_SETAPPID(m, applid) capimsg_setu16(m, 2, applid)
-#define CAPIMSG_SETCOMMAND(m,cmd) capimsg_setu8(m, 4, cmd)
-#define CAPIMSG_SETSUBCOMMAND(m, cmd) capimsg_setu8(m, 5, cmd)
-#define CAPIMSG_SETMSGID(m, msgid) capimsg_setu16(m, 6, msgid)
-#define CAPIMSG_SETCONTROL(m, contr) capimsg_setu32(m, 8, contr)
-#define CAPIMSG_SETDATALEN(m, len) capimsg_setu16(m, 16, len)
-
-#endif /* __CAPIUTIL_H__ */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * $Id: kernelcapi.h,v 1.8.6.2 2001/02/07 11:31:31 kai Exp $
- *
- * Kernel CAPI 2.0 Interface for Linux
- *
- * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
- *
- */
-#ifndef __KERNELCAPI_H__
-#define __KERNELCAPI_H__
-
-#include <linux/list.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-#include <linux/notifier.h>
-#include <uapi/linux/kernelcapi.h>
-
-#define CAPI_NOERROR 0x0000
-
-#define CAPI_TOOMANYAPPLS 0x1001
-#define CAPI_LOGBLKSIZETOSMALL 0x1002
-#define CAPI_BUFFEXECEEDS64K 0x1003
-#define CAPI_MSGBUFSIZETOOSMALL 0x1004
-#define CAPI_ANZLOGCONNNOTSUPPORTED 0x1005
-#define CAPI_REGRESERVED 0x1006
-#define CAPI_REGBUSY 0x1007
-#define CAPI_REGOSRESOURCEERR 0x1008
-#define CAPI_REGNOTINSTALLED 0x1009
-#define CAPI_REGCTRLERNOTSUPPORTEXTEQUIP 0x100a
-#define CAPI_REGCTRLERONLYSUPPORTEXTEQUIP 0x100b
-
-#define CAPI_ILLAPPNR 0x1101
-#define CAPI_ILLCMDORSUBCMDORMSGTOSMALL 0x1102
-#define CAPI_SENDQUEUEFULL 0x1103
-#define CAPI_RECEIVEQUEUEEMPTY 0x1104
-#define CAPI_RECEIVEOVERFLOW 0x1105
-#define CAPI_UNKNOWNNOTPAR 0x1106
-#define CAPI_MSGBUSY 0x1107
-#define CAPI_MSGOSRESOURCEERR 0x1108
-#define CAPI_MSGNOTINSTALLED 0x1109
-#define CAPI_MSGCTRLERNOTSUPPORTEXTEQUIP 0x110a
-#define CAPI_MSGCTRLERONLYSUPPORTEXTEQUIP 0x110b
-
-#endif /* __KERNELCAPI_H__ */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __mISDNdsp_H__
-#define __mISDNdsp_H__
-
-struct mISDN_dsp_element_arg {
- char *name;
- char *def;
- char *desc;
-};
-
-struct mISDN_dsp_element {
- char *name;
- void *(*new)(const char *arg);
- void (*free)(void *p);
- void (*process_tx)(void *p, unsigned char *data, int len);
- void (*process_rx)(void *p, unsigned char *data, int len,
- unsigned int txlen);
- int num_args;
- struct mISDN_dsp_element_arg
- *args;
-};
-
-extern int mISDN_dsp_element_register(struct mISDN_dsp_element *elem);
-extern void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem);
-
-struct dsp_features {
- int hfc_id; /* unique id to identify the chip (or -1) */
- int hfc_dtmf; /* set if HFCmulti card supports dtmf */
- int hfc_conf; /* set if HFCmulti card supports conferences */
- int hfc_loops; /* set if card supports tone loops */
- int hfc_echocanhw; /* set if card supports echocancelation*/
- int pcm_id; /* unique id to identify the pcm bus (or -1) */
- int pcm_slots; /* number of slots on the pcm bus */
- int pcm_banks; /* number of IO banks of pcm bus */
- int unclocked; /* data is not clocked (has jitter/loss) */
- int unordered; /* data is unordered (packets have index) */
-};
-
-#endif
-
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- *
- * Author Karsten Keil <kkeil@novell.com>
- *
- * Basic declarations for the mISDN HW channels
- *
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- */
-
-#ifndef MISDNHW_H
-#define MISDNHW_H
-#include <linux/mISDNif.h>
-#include <linux/timer.h>
-
-/*
- * HW DEBUG 0xHHHHGGGG
- * H - hardware driver specific bits
- * G - for all drivers
- */
-
-#define DEBUG_HW 0x00000001
-#define DEBUG_HW_OPEN 0x00000002
-#define DEBUG_HW_DCHANNEL 0x00000100
-#define DEBUG_HW_DFIFO 0x00000200
-#define DEBUG_HW_BCHANNEL 0x00001000
-#define DEBUG_HW_BFIFO 0x00002000
-
-#define MAX_DFRAME_LEN_L1 300
-#define MAX_MON_FRAME 32
-#define MAX_LOG_SPACE 2048
-#define MISDN_COPY_SIZE 32
-
-/* channel->Flags bit field */
-#define FLG_TX_BUSY 0 /* tx_buf in use */
-#define FLG_TX_NEXT 1 /* next_skb in use */
-#define FLG_L1_BUSY 2 /* L1 is permanent busy */
-#define FLG_L2_ACTIVATED 3 /* activated from L2 */
-#define FLG_OPEN 5 /* channel is in use */
-#define FLG_ACTIVE 6 /* channel is activated */
-#define FLG_BUSY_TIMER 7
-/* channel type */
-#define FLG_DCHANNEL 8 /* channel is D-channel */
-#define FLG_BCHANNEL 9 /* channel is B-channel */
-#define FLG_ECHANNEL 10 /* channel is E-channel */
-#define FLG_TRANSPARENT 12 /* channel use transparent data */
-#define FLG_HDLC 13 /* channel use hdlc data */
-#define FLG_L2DATA 14 /* channel use L2 DATA primitivs */
-#define FLG_ORIGIN 15 /* channel is on origin site */
-/* channel specific stuff */
-#define FLG_FILLEMPTY 16 /* fill fifo on first frame (empty) */
-/* arcofi specific */
-#define FLG_ARCOFI_TIMER 17
-#define FLG_ARCOFI_ERROR 18
-/* isar specific */
-#define FLG_INITIALIZED 17
-#define FLG_DLEETX 18
-#define FLG_LASTDLE 19
-#define FLG_FIRST 20
-#define FLG_LASTDATA 21
-#define FLG_NMD_DATA 22
-#define FLG_FTI_RUN 23
-#define FLG_LL_OK 24
-#define FLG_LL_CONN 25
-#define FLG_DTMFSEND 26
-#define FLG_TX_EMPTY 27
-/* stop sending received data upstream */
-#define FLG_RX_OFF 28
-/* workq events */
-#define FLG_RECVQUEUE 30
-#define FLG_PHCHANGE 31
-
-#define schedule_event(s, ev) do { \
- test_and_set_bit(ev, &((s)->Flags)); \
- schedule_work(&((s)->workq)); \
- } while (0)
-
-struct dchannel {
- struct mISDNdevice dev;
- u_long Flags;
- struct work_struct workq;
- void (*phfunc) (struct dchannel *);
- u_int state;
- void *l1;
- void *hw;
- int slot; /* multiport card channel slot */
- struct timer_list timer;
- /* receive data */
- struct sk_buff *rx_skb;
- int maxlen;
- /* send data */
- struct sk_buff_head squeue;
- struct sk_buff_head rqueue;
- struct sk_buff *tx_skb;
- int tx_idx;
- int debug;
- /* statistics */
- int err_crc;
- int err_tx;
- int err_rx;
-};
-
-typedef int (dchannel_l1callback)(struct dchannel *, u_int);
-extern int create_l1(struct dchannel *, dchannel_l1callback *);
-
-/* private L1 commands */
-#define INFO0 0x8002
-#define INFO1 0x8102
-#define INFO2 0x8202
-#define INFO3_P8 0x8302
-#define INFO3_P10 0x8402
-#define INFO4_P8 0x8502
-#define INFO4_P10 0x8602
-#define LOSTFRAMING 0x8702
-#define ANYSIGNAL 0x8802
-#define HW_POWERDOWN 0x8902
-#define HW_RESET_REQ 0x8a02
-#define HW_POWERUP_REQ 0x8b02
-#define HW_DEACT_REQ 0x8c02
-#define HW_ACTIVATE_REQ 0x8e02
-#define HW_D_NOBLOCKED 0x8f02
-#define HW_RESET_IND 0x9002
-#define HW_POWERUP_IND 0x9102
-#define HW_DEACT_IND 0x9202
-#define HW_ACTIVATE_IND 0x9302
-#define HW_DEACT_CNF 0x9402
-#define HW_TESTLOOP 0x9502
-#define HW_TESTRX_RAW 0x9602
-#define HW_TESTRX_HDLC 0x9702
-#define HW_TESTRX_OFF 0x9802
-#define HW_TIMER3_IND 0x9902
-#define HW_TIMER3_VALUE 0x9a00
-#define HW_TIMER3_VMASK 0x00FF
-
-struct layer1;
-extern int l1_event(struct layer1 *, u_int);
-
-#define MISDN_BCH_FILL_SIZE 4
-
-struct bchannel {
- struct mISDNchannel ch;
- int nr;
- u_long Flags;
- struct work_struct workq;
- u_int state;
- void *hw;
- int slot; /* multiport card channel slot */
- struct timer_list timer;
- /* receive data */
- u8 fill[MISDN_BCH_FILL_SIZE];
- struct sk_buff *rx_skb;
- unsigned short maxlen;
- unsigned short init_maxlen; /* initial value */
- unsigned short next_maxlen; /* pending value */
- unsigned short minlen; /* for transparent data */
- unsigned short init_minlen; /* initial value */
- unsigned short next_minlen; /* pending value */
- /* send data */
- struct sk_buff *next_skb;
- struct sk_buff *tx_skb;
- struct sk_buff_head rqueue;
- int rcount;
- int tx_idx;
- int debug;
- /* statistics */
- int err_crc;
- int err_tx;
- int err_rx;
- int dropcnt;
-};
-
-extern int mISDN_initdchannel(struct dchannel *, int, void *);
-extern int mISDN_initbchannel(struct bchannel *, unsigned short,
- unsigned short);
-extern int mISDN_freedchannel(struct dchannel *);
-extern void mISDN_clear_bchannel(struct bchannel *);
-extern void mISDN_freebchannel(struct bchannel *);
-extern int mISDN_ctrl_bchannel(struct bchannel *, struct mISDN_ctrl_req *);
-extern void queue_ch_frame(struct mISDNchannel *, u_int,
- int, struct sk_buff *);
-extern int dchannel_senddata(struct dchannel *, struct sk_buff *);
-extern int bchannel_senddata(struct bchannel *, struct sk_buff *);
-extern int bchannel_get_rxbuf(struct bchannel *, int);
-extern void recv_Dchannel(struct dchannel *);
-extern void recv_Echannel(struct dchannel *, struct dchannel *);
-extern void recv_Bchannel(struct bchannel *, unsigned int, bool);
-extern void recv_Dchannel_skb(struct dchannel *, struct sk_buff *);
-extern void recv_Bchannel_skb(struct bchannel *, struct sk_buff *);
-extern int get_next_bframe(struct bchannel *);
-extern int get_next_dframe(struct dchannel *);
-
-#endif
+++ /dev/null
-/*
- *
- * Author Karsten Keil <kkeil@novell.com>
- *
- * Copyright 2008 by Karsten Keil <kkeil@novell.com>
- *
- * This code is free software; you can redistribute it and/or modify
- * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
- * version 2.1 as published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU LESSER GENERAL PUBLIC LICENSE for more details.
- *
- */
-
-#ifndef mISDNIF_H
-#define mISDNIF_H
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/socket.h>
-
-/*
- * ABI Version 32 bit
- *
- * <8 bit> Major version
- * - changed if any interface become backwards incompatible
- *
- * <8 bit> Minor version
- * - changed if any interface is extended but backwards compatible
- *
- * <16 bit> Release number
- * - should be incremented on every checkin
- */
-#define MISDN_MAJOR_VERSION 1
-#define MISDN_MINOR_VERSION 1
-#define MISDN_RELEASE 29
-
-/* primitives for information exchange
- * generell format
- * <16 bit 0 >
- * <8 bit command>
- * BIT 8 = 1 LAYER private
- * BIT 7 = 1 answer
- * BIT 6 = 1 DATA
- * <8 bit target layer mask>
- *
- * Layer = 00 is reserved for general commands
- Layer = 01 L2 -> HW
- Layer = 02 HW -> L2
- Layer = 04 L3 -> L2
- Layer = 08 L2 -> L3
- * Layer = FF is reserved for broadcast commands
- */
-
-#define MISDN_CMDMASK 0xff00
-#define MISDN_LAYERMASK 0x00ff
-
-/* generell commands */
-#define OPEN_CHANNEL 0x0100
-#define CLOSE_CHANNEL 0x0200
-#define CONTROL_CHANNEL 0x0300
-#define CHECK_DATA 0x0400
-
-/* layer 2 -> layer 1 */
-#define PH_ACTIVATE_REQ 0x0101
-#define PH_DEACTIVATE_REQ 0x0201
-#define PH_DATA_REQ 0x2001
-#define MPH_ACTIVATE_REQ 0x0501
-#define MPH_DEACTIVATE_REQ 0x0601
-#define MPH_INFORMATION_REQ 0x0701
-#define PH_CONTROL_REQ 0x0801
-
-/* layer 1 -> layer 2 */
-#define PH_ACTIVATE_IND 0x0102
-#define PH_ACTIVATE_CNF 0x4102
-#define PH_DEACTIVATE_IND 0x0202
-#define PH_DEACTIVATE_CNF 0x4202
-#define PH_DATA_IND 0x2002
-#define PH_DATA_E_IND 0x3002
-#define MPH_ACTIVATE_IND 0x0502
-#define MPH_DEACTIVATE_IND 0x0602
-#define MPH_INFORMATION_IND 0x0702
-#define PH_DATA_CNF 0x6002
-#define PH_CONTROL_IND 0x0802
-#define PH_CONTROL_CNF 0x4802
-
-/* layer 3 -> layer 2 */
-#define DL_ESTABLISH_REQ 0x1004
-#define DL_RELEASE_REQ 0x1104
-#define DL_DATA_REQ 0x3004
-#define DL_UNITDATA_REQ 0x3104
-#define DL_INFORMATION_REQ 0x0004
-
-/* layer 2 -> layer 3 */
-#define DL_ESTABLISH_IND 0x1008
-#define DL_ESTABLISH_CNF 0x5008
-#define DL_RELEASE_IND 0x1108
-#define DL_RELEASE_CNF 0x5108
-#define DL_DATA_IND 0x3008
-#define DL_UNITDATA_IND 0x3108
-#define DL_INFORMATION_IND 0x0008
-
-/* intern layer 2 management */
-#define MDL_ASSIGN_REQ 0x1804
-#define MDL_ASSIGN_IND 0x1904
-#define MDL_REMOVE_REQ 0x1A04
-#define MDL_REMOVE_IND 0x1B04
-#define MDL_STATUS_UP_IND 0x1C04
-#define MDL_STATUS_DOWN_IND 0x1D04
-#define MDL_STATUS_UI_IND 0x1E04
-#define MDL_ERROR_IND 0x1F04
-#define MDL_ERROR_RSP 0x5F04
-
-/* intern layer 2 */
-#define DL_TIMER200_IND 0x7004
-#define DL_TIMER203_IND 0x7304
-#define DL_INTERN_MSG 0x7804
-
-/* DL_INFORMATION_IND types */
-#define DL_INFO_L2_CONNECT 0x0001
-#define DL_INFO_L2_REMOVED 0x0002
-
-/* PH_CONTROL types */
-/* TOUCH TONE IS 0x20XX XX "0"..."9", "A","B","C","D","*","#" */
-#define DTMF_TONE_VAL 0x2000
-#define DTMF_TONE_MASK 0x007F
-#define DTMF_TONE_START 0x2100
-#define DTMF_TONE_STOP 0x2200
-#define DTMF_HFC_COEF 0x4000
-#define DSP_CONF_JOIN 0x2403
-#define DSP_CONF_SPLIT 0x2404
-#define DSP_RECEIVE_OFF 0x2405
-#define DSP_RECEIVE_ON 0x2406
-#define DSP_ECHO_ON 0x2407
-#define DSP_ECHO_OFF 0x2408
-#define DSP_MIX_ON 0x2409
-#define DSP_MIX_OFF 0x240a
-#define DSP_DELAY 0x240b
-#define DSP_JITTER 0x240c
-#define DSP_TXDATA_ON 0x240d
-#define DSP_TXDATA_OFF 0x240e
-#define DSP_TX_DEJITTER 0x240f
-#define DSP_TX_DEJ_OFF 0x2410
-#define DSP_TONE_PATT_ON 0x2411
-#define DSP_TONE_PATT_OFF 0x2412
-#define DSP_VOL_CHANGE_TX 0x2413
-#define DSP_VOL_CHANGE_RX 0x2414
-#define DSP_BF_ENABLE_KEY 0x2415
-#define DSP_BF_DISABLE 0x2416
-#define DSP_BF_ACCEPT 0x2416
-#define DSP_BF_REJECT 0x2417
-#define DSP_PIPELINE_CFG 0x2418
-#define HFC_VOL_CHANGE_TX 0x2601
-#define HFC_VOL_CHANGE_RX 0x2602
-#define HFC_SPL_LOOP_ON 0x2603
-#define HFC_SPL_LOOP_OFF 0x2604
-/* for T30 FAX and analog modem */
-#define HW_MOD_FRM 0x4000
-#define HW_MOD_FRH 0x4001
-#define HW_MOD_FTM 0x4002
-#define HW_MOD_FTH 0x4003
-#define HW_MOD_FTS 0x4004
-#define HW_MOD_CONNECT 0x4010
-#define HW_MOD_OK 0x4011
-#define HW_MOD_NOCARR 0x4012
-#define HW_MOD_FCERROR 0x4013
-#define HW_MOD_READY 0x4014
-#define HW_MOD_LASTDATA 0x4015
-
-/* DSP_TONE_PATT_ON parameter */
-#define TONE_OFF 0x0000
-#define TONE_GERMAN_DIALTONE 0x0001
-#define TONE_GERMAN_OLDDIALTONE 0x0002
-#define TONE_AMERICAN_DIALTONE 0x0003
-#define TONE_GERMAN_DIALPBX 0x0004
-#define TONE_GERMAN_OLDDIALPBX 0x0005
-#define TONE_AMERICAN_DIALPBX 0x0006
-#define TONE_GERMAN_RINGING 0x0007
-#define TONE_GERMAN_OLDRINGING 0x0008
-#define TONE_AMERICAN_RINGPBX 0x000b
-#define TONE_GERMAN_RINGPBX 0x000c
-#define TONE_GERMAN_OLDRINGPBX 0x000d
-#define TONE_AMERICAN_RINGING 0x000e
-#define TONE_GERMAN_BUSY 0x000f
-#define TONE_GERMAN_OLDBUSY 0x0010
-#define TONE_AMERICAN_BUSY 0x0011
-#define TONE_GERMAN_HANGUP 0x0012
-#define TONE_GERMAN_OLDHANGUP 0x0013
-#define TONE_AMERICAN_HANGUP 0x0014
-#define TONE_SPECIAL_INFO 0x0015
-#define TONE_GERMAN_GASSENBESETZT 0x0016
-#define TONE_GERMAN_AUFSCHALTTON 0x0016
-
-/* MPH_INFORMATION_IND */
-#define L1_SIGNAL_LOS_OFF 0x0010
-#define L1_SIGNAL_LOS_ON 0x0011
-#define L1_SIGNAL_AIS_OFF 0x0012
-#define L1_SIGNAL_AIS_ON 0x0013
-#define L1_SIGNAL_RDI_OFF 0x0014
-#define L1_SIGNAL_RDI_ON 0x0015
-#define L1_SIGNAL_SLIP_RX 0x0020
-#define L1_SIGNAL_SLIP_TX 0x0021
-
-/*
- * protocol ids
- * D channel 1-31
- * B channel 33 - 63
- */
-
-#define ISDN_P_NONE 0
-#define ISDN_P_BASE 0
-#define ISDN_P_TE_S0 0x01
-#define ISDN_P_NT_S0 0x02
-#define ISDN_P_TE_E1 0x03
-#define ISDN_P_NT_E1 0x04
-#define ISDN_P_TE_UP0 0x05
-#define ISDN_P_NT_UP0 0x06
-
-#define IS_ISDN_P_TE(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_TE_E1) || \
- (p == ISDN_P_TE_UP0) || (p == ISDN_P_LAPD_TE))
-#define IS_ISDN_P_NT(p) ((p == ISDN_P_NT_S0) || (p == ISDN_P_NT_E1) || \
- (p == ISDN_P_NT_UP0) || (p == ISDN_P_LAPD_NT))
-#define IS_ISDN_P_S0(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_NT_S0))
-#define IS_ISDN_P_E1(p) ((p == ISDN_P_TE_E1) || (p == ISDN_P_NT_E1))
-#define IS_ISDN_P_UP0(p) ((p == ISDN_P_TE_UP0) || (p == ISDN_P_NT_UP0))
-
-
-#define ISDN_P_LAPD_TE 0x10
-#define ISDN_P_LAPD_NT 0x11
-
-#define ISDN_P_B_MASK 0x1f
-#define ISDN_P_B_START 0x20
-
-#define ISDN_P_B_RAW 0x21
-#define ISDN_P_B_HDLC 0x22
-#define ISDN_P_B_X75SLP 0x23
-#define ISDN_P_B_L2DTMF 0x24
-#define ISDN_P_B_L2DSP 0x25
-#define ISDN_P_B_L2DSPHDLC 0x26
-#define ISDN_P_B_T30_FAX 0x27
-#define ISDN_P_B_MODEM_ASYNC 0x28
-
-#define OPTION_L2_PMX 1
-#define OPTION_L2_PTP 2
-#define OPTION_L2_FIXEDTEI 3
-#define OPTION_L2_CLEANUP 4
-#define OPTION_L1_HOLD 5
-
-/* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */
-#define MISDN_MAX_IDLEN 20
-
-struct mISDNhead {
- unsigned int prim;
- unsigned int id;
-} __packed;
-
-#define MISDN_HEADER_LEN sizeof(struct mISDNhead)
-#define MAX_DATA_SIZE 2048
-#define MAX_DATA_MEM (MAX_DATA_SIZE + MISDN_HEADER_LEN)
-#define MAX_DFRAME_LEN 260
-
-#define MISDN_ID_ADDR_MASK 0xFFFF
-#define MISDN_ID_TEI_MASK 0xFF00
-#define MISDN_ID_SAPI_MASK 0x00FF
-#define MISDN_ID_TEI_ANY 0x7F00
-
-#define MISDN_ID_ANY 0xFFFF
-#define MISDN_ID_NONE 0xFFFE
-
-#define GROUP_TEI 127
-#define TEI_SAPI 63
-#define CTRL_SAPI 0
-
-#define MISDN_MAX_CHANNEL 127
-#define MISDN_CHMAP_SIZE ((MISDN_MAX_CHANNEL + 1) >> 3)
-
-#define SOL_MISDN 0
-
-struct sockaddr_mISDN {
- sa_family_t family;
- unsigned char dev;
- unsigned char channel;
- unsigned char sapi;
- unsigned char tei;
-};
-
-struct mISDNversion {
- unsigned char major;
- unsigned char minor;
- unsigned short release;
-};
-
-struct mISDN_devinfo {
- u_int id;
- u_int Dprotocols;
- u_int Bprotocols;
- u_int protocol;
- u_char channelmap[MISDN_CHMAP_SIZE];
- u_int nrbchan;
- char name[MISDN_MAX_IDLEN];
-};
-
-struct mISDN_devrename {
- u_int id;
- char name[MISDN_MAX_IDLEN]; /* new name */
-};
-
-/* MPH_INFORMATION_REQ payload */
-struct ph_info_ch {
- __u32 protocol;
- __u64 Flags;
-};
-
-struct ph_info_dch {
- struct ph_info_ch ch;
- __u16 state;
- __u16 num_bch;
-};
-
-struct ph_info {
- struct ph_info_dch dch;
- struct ph_info_ch bch[];
-};
-
-/* timer device ioctl */
-#define IMADDTIMER _IOR('I', 64, int)
-#define IMDELTIMER _IOR('I', 65, int)
-
-/* socket ioctls */
-#define IMGETVERSION _IOR('I', 66, int)
-#define IMGETCOUNT _IOR('I', 67, int)
-#define IMGETDEVINFO _IOR('I', 68, int)
-#define IMCTRLREQ _IOR('I', 69, int)
-#define IMCLEAR_L2 _IOR('I', 70, int)
-#define IMSETDEVNAME _IOR('I', 71, struct mISDN_devrename)
-#define IMHOLD_L1 _IOR('I', 72, int)
-
-static inline int
-test_channelmap(u_int nr, u_char *map)
-{
- if (nr <= MISDN_MAX_CHANNEL)
- return map[nr >> 3] & (1 << (nr & 7));
- else
- return 0;
-}
-
-static inline void
-set_channelmap(u_int nr, u_char *map)
-{
- map[nr >> 3] |= (1 << (nr & 7));
-}
-
-static inline void
-clear_channelmap(u_int nr, u_char *map)
-{
- map[nr >> 3] &= ~(1 << (nr & 7));
-}
-
-/* CONTROL_CHANNEL parameters */
-#define MISDN_CTRL_GETOP 0x0000
-#define MISDN_CTRL_LOOP 0x0001
-#define MISDN_CTRL_CONNECT 0x0002
-#define MISDN_CTRL_DISCONNECT 0x0004
-#define MISDN_CTRL_RX_BUFFER 0x0008
-#define MISDN_CTRL_PCMCONNECT 0x0010
-#define MISDN_CTRL_PCMDISCONNECT 0x0020
-#define MISDN_CTRL_SETPEER 0x0040
-#define MISDN_CTRL_UNSETPEER 0x0080
-#define MISDN_CTRL_RX_OFF 0x0100
-#define MISDN_CTRL_FILL_EMPTY 0x0200
-#define MISDN_CTRL_GETPEER 0x0400
-#define MISDN_CTRL_L1_TIMER3 0x0800
-#define MISDN_CTRL_HW_FEATURES_OP 0x2000
-#define MISDN_CTRL_HW_FEATURES 0x2001
-#define MISDN_CTRL_HFC_OP 0x4000
-#define MISDN_CTRL_HFC_PCM_CONN 0x4001
-#define MISDN_CTRL_HFC_PCM_DISC 0x4002
-#define MISDN_CTRL_HFC_CONF_JOIN 0x4003
-#define MISDN_CTRL_HFC_CONF_SPLIT 0x4004
-#define MISDN_CTRL_HFC_RECEIVE_OFF 0x4005
-#define MISDN_CTRL_HFC_RECEIVE_ON 0x4006
-#define MISDN_CTRL_HFC_ECHOCAN_ON 0x4007
-#define MISDN_CTRL_HFC_ECHOCAN_OFF 0x4008
-#define MISDN_CTRL_HFC_WD_INIT 0x4009
-#define MISDN_CTRL_HFC_WD_RESET 0x400A
-
-/* special RX buffer value for MISDN_CTRL_RX_BUFFER request.p1 is the minimum
- * buffer size request.p2 the maximum. Using MISDN_CTRL_RX_SIZE_IGNORE will
- * not change the value, but still read back the actual stetting.
- */
-#define MISDN_CTRL_RX_SIZE_IGNORE -1
-
-/* socket options */
-#define MISDN_TIME_STAMP 0x0001
-
-struct mISDN_ctrl_req {
- int op;
- int channel;
- int p1;
- int p2;
-};
-
-/* muxer options */
-#define MISDN_OPT_ALL 1
-#define MISDN_OPT_TEIMGR 2
-
-#ifdef __KERNEL__
-#include <linux/list.h>
-#include <linux/skbuff.h>
-#include <linux/net.h>
-#include <net/sock.h>
-#include <linux/completion.h>
-
-#define DEBUG_CORE 0x000000ff
-#define DEBUG_CORE_FUNC 0x00000002
-#define DEBUG_SOCKET 0x00000004
-#define DEBUG_MANAGER 0x00000008
-#define DEBUG_SEND_ERR 0x00000010
-#define DEBUG_MSG_THREAD 0x00000020
-#define DEBUG_QUEUE_FUNC 0x00000040
-#define DEBUG_L1 0x0000ff00
-#define DEBUG_L1_FSM 0x00000200
-#define DEBUG_L2 0x00ff0000
-#define DEBUG_L2_FSM 0x00020000
-#define DEBUG_L2_CTRL 0x00040000
-#define DEBUG_L2_RECV 0x00080000
-#define DEBUG_L2_TEI 0x00100000
-#define DEBUG_L2_TEIFSM 0x00200000
-#define DEBUG_TIMER 0x01000000
-#define DEBUG_CLOCK 0x02000000
-
-#define mISDN_HEAD_P(s) ((struct mISDNhead *)&s->cb[0])
-#define mISDN_HEAD_PRIM(s) (((struct mISDNhead *)&s->cb[0])->prim)
-#define mISDN_HEAD_ID(s) (((struct mISDNhead *)&s->cb[0])->id)
-
-/* socket states */
-#define MISDN_OPEN 1
-#define MISDN_BOUND 2
-#define MISDN_CLOSED 3
-
-struct mISDNchannel;
-struct mISDNdevice;
-struct mISDNstack;
-struct mISDNclock;
-
-struct channel_req {
- u_int protocol;
- struct sockaddr_mISDN adr;
- struct mISDNchannel *ch;
-};
-
-typedef int (ctrl_func_t)(struct mISDNchannel *, u_int, void *);
-typedef int (send_func_t)(struct mISDNchannel *, struct sk_buff *);
-typedef int (create_func_t)(struct channel_req *);
-
-struct Bprotocol {
- struct list_head list;
- char *name;
- u_int Bprotocols;
- create_func_t *create;
-};
-
-struct mISDNchannel {
- struct list_head list;
- u_int protocol;
- u_int nr;
- u_long opt;
- u_int addr;
- struct mISDNstack *st;
- struct mISDNchannel *peer;
- send_func_t *send;
- send_func_t *recv;
- ctrl_func_t *ctrl;
-};
-
-struct mISDN_sock_list {
- struct hlist_head head;
- rwlock_t lock;
-};
-
-struct mISDN_sock {
- struct sock sk;
- struct mISDNchannel ch;
- u_int cmask;
- struct mISDNdevice *dev;
-};
-
-
-
-struct mISDNdevice {
- struct mISDNchannel D;
- u_int id;
- u_int Dprotocols;
- u_int Bprotocols;
- u_int nrbchan;
- u_char channelmap[MISDN_CHMAP_SIZE];
- struct list_head bchannels;
- struct mISDNchannel *teimgr;
- struct device dev;
-};
-
-struct mISDNstack {
- u_long status;
- struct mISDNdevice *dev;
- struct task_struct *thread;
- struct completion *notify;
- wait_queue_head_t workq;
- struct sk_buff_head msgq;
- struct list_head layer2;
- struct mISDNchannel *layer1;
- struct mISDNchannel own;
- struct mutex lmutex; /* protect lists */
- struct mISDN_sock_list l1sock;
-#ifdef MISDN_MSG_STATS
- u_int msg_cnt;
- u_int sleep_cnt;
- u_int stopped_cnt;
-#endif
-};
-
-typedef int (clockctl_func_t)(void *, int);
-
-struct mISDNclock {
- struct list_head list;
- char name[64];
- int pri;
- clockctl_func_t *ctl;
- void *priv;
-};
-
-/* global alloc/queue functions */
-
-static inline struct sk_buff *
-mI_alloc_skb(unsigned int len, gfp_t gfp_mask)
-{
- struct sk_buff *skb;
-
- skb = alloc_skb(len + MISDN_HEADER_LEN, gfp_mask);
- if (likely(skb))
- skb_reserve(skb, MISDN_HEADER_LEN);
- return skb;
-}
-
-static inline struct sk_buff *
-_alloc_mISDN_skb(u_int prim, u_int id, u_int len, void *dp, gfp_t gfp_mask)
-{
- struct sk_buff *skb = mI_alloc_skb(len, gfp_mask);
- struct mISDNhead *hh;
-
- if (!skb)
- return NULL;
- if (len)
- skb_put_data(skb, dp, len);
- hh = mISDN_HEAD_P(skb);
- hh->prim = prim;
- hh->id = id;
- return skb;
-}
-
-static inline void
-_queue_data(struct mISDNchannel *ch, u_int prim,
- u_int id, u_int len, void *dp, gfp_t gfp_mask)
-{
- struct sk_buff *skb;
-
- if (!ch->peer)
- return;
- skb = _alloc_mISDN_skb(prim, id, len, dp, gfp_mask);
- if (!skb)
- return;
- if (ch->recv(ch->peer, skb))
- dev_kfree_skb(skb);
-}
-
-/* global register/unregister functions */
-
-extern int mISDN_register_device(struct mISDNdevice *,
- struct device *parent, char *name);
-extern void mISDN_unregister_device(struct mISDNdevice *);
-extern int mISDN_register_Bprotocol(struct Bprotocol *);
-extern void mISDN_unregister_Bprotocol(struct Bprotocol *);
-extern struct mISDNclock *mISDN_register_clock(char *, int, clockctl_func_t *,
- void *);
-extern void mISDN_unregister_clock(struct mISDNclock *);
-
-static inline struct mISDNdevice *dev_to_mISDN(const struct device *dev)
-{
- if (dev)
- return dev_get_drvdata(dev);
- else
- return NULL;
-}
-
-extern void set_channel_address(struct mISDNchannel *, u_int, u_int);
-extern void mISDN_clock_update(struct mISDNclock *, int, ktime_t *);
-extern unsigned short mISDN_clock_get(void);
-extern const char *mISDNDevName4ch(struct mISDNchannel *);
-
-#endif /* __KERNEL__ */
-#endif /* mISDNIF_H */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/* $Id: capi.h,v 1.4.6.1 2001/09/23 22:25:05 kai Exp $
- *
- * CAPI 2.0 Interface for Linux
- *
- * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef __LINUX_CAPI_H__
-#define __LINUX_CAPI_H__
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#ifndef __KERNEL__
-#include <linux/kernelcapi.h>
-#endif
-
-/*
- * CAPI_REGISTER
- */
-
-typedef struct capi_register_params { /* CAPI_REGISTER */
- __u32 level3cnt; /* No. of simulatneous user data connections */
- __u32 datablkcnt; /* No. of buffered data messages */
- __u32 datablklen; /* Size of buffered data messages */
-} capi_register_params;
-
-#define CAPI_REGISTER _IOW('C',0x01,struct capi_register_params)
-
-/*
- * CAPI_GET_MANUFACTURER
- */
-
-#define CAPI_MANUFACTURER_LEN 64
-
-#define CAPI_GET_MANUFACTURER _IOWR('C',0x06,int) /* broken: wanted size 64 (CAPI_MANUFACTURER_LEN) */
-
-/*
- * CAPI_GET_VERSION
- */
-
-typedef struct capi_version {
- __u32 majorversion;
- __u32 minorversion;
- __u32 majormanuversion;
- __u32 minormanuversion;
-} capi_version;
-
-#define CAPI_GET_VERSION _IOWR('C',0x07,struct capi_version)
-
-/*
- * CAPI_GET_SERIAL
- */
-
-#define CAPI_SERIAL_LEN 8
-#define CAPI_GET_SERIAL _IOWR('C',0x08,int) /* broken: wanted size 8 (CAPI_SERIAL_LEN) */
-
-/*
- * CAPI_GET_PROFILE
- */
-
-typedef struct capi_profile {
- __u16 ncontroller; /* number of installed controller */
- __u16 nbchannel; /* number of B-Channels */
- __u32 goptions; /* global options */
- __u32 support1; /* B1 protocols support */
- __u32 support2; /* B2 protocols support */
- __u32 support3; /* B3 protocols support */
- __u32 reserved[6]; /* reserved */
- __u32 manu[5]; /* manufacturer specific information */
-} capi_profile;
-
-#define CAPI_GET_PROFILE _IOWR('C',0x09,struct capi_profile)
-
-typedef struct capi_manufacturer_cmd {
- unsigned long cmd;
- void __user *data;
-} capi_manufacturer_cmd;
-
-/*
- * CAPI_MANUFACTURER_CMD
- */
-
-#define CAPI_MANUFACTURER_CMD _IOWR('C',0x20, struct capi_manufacturer_cmd)
-
-/*
- * CAPI_GET_ERRCODE
- * capi errcode is set, * if read, write, or ioctl returns EIO,
- * ioctl returns errcode directly, and in arg, if != 0
- */
-
-#define CAPI_GET_ERRCODE _IOR('C',0x21, __u16)
-
-/*
- * CAPI_INSTALLED
- */
-#define CAPI_INSTALLED _IOR('C',0x22, __u16)
-
-
-/*
- * member contr is input for
- * CAPI_GET_MANUFACTURER, CAPI_GET_VERSION, CAPI_GET_SERIAL
- * and CAPI_GET_PROFILE
- */
-typedef union capi_ioctl_struct {
- __u32 contr;
- capi_register_params rparams;
- __u8 manufacturer[CAPI_MANUFACTURER_LEN];
- capi_version version;
- __u8 serial[CAPI_SERIAL_LEN];
- capi_profile profile;
- capi_manufacturer_cmd cmd;
- __u16 errcode;
-} capi_ioctl_struct;
-
-/*
- * Middleware extension
- */
-
-#define CAPIFLAG_HIGHJACKING 0x0001
-
-#define CAPI_GET_FLAGS _IOR('C',0x23, unsigned)
-#define CAPI_SET_FLAGS _IOR('C',0x24, unsigned)
-#define CAPI_CLR_FLAGS _IOR('C',0x25, unsigned)
-
-#define CAPI_NCCI_OPENCOUNT _IOR('C',0x26, unsigned)
-
-#define CAPI_NCCI_GETUNIT _IOR('C',0x27, unsigned)
-
-#endif /* __LINUX_CAPI_H__ */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/* $Id: capicmd.h,v 1.2.6.2 2001/09/23 22:24:33 kai Exp $
- *
- * CAPI 2.0 Interface for Linux
- *
- * Copyright 1997 by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef __CAPICMD_H__
-#define __CAPICMD_H__
-
-#define CAPI_MSG_BASELEN 8
-#define CAPI_DATA_B3_REQ_LEN (CAPI_MSG_BASELEN+4+4+2+2+2)
-#define CAPI_DATA_B3_RESP_LEN (CAPI_MSG_BASELEN+4+2)
-#define CAPI_DISCONNECT_B3_RESP_LEN (CAPI_MSG_BASELEN+4)
-
-/*----- CAPI commands -----*/
-#define CAPI_ALERT 0x01
-#define CAPI_CONNECT 0x02
-#define CAPI_CONNECT_ACTIVE 0x03
-#define CAPI_CONNECT_B3_ACTIVE 0x83
-#define CAPI_CONNECT_B3 0x82
-#define CAPI_CONNECT_B3_T90_ACTIVE 0x88
-#define CAPI_DATA_B3 0x86
-#define CAPI_DISCONNECT_B3 0x84
-#define CAPI_DISCONNECT 0x04
-#define CAPI_FACILITY 0x80
-#define CAPI_INFO 0x08
-#define CAPI_LISTEN 0x05
-#define CAPI_MANUFACTURER 0xff
-#define CAPI_RESET_B3 0x87
-#define CAPI_SELECT_B_PROTOCOL 0x41
-
-/*----- CAPI subcommands -----*/
-
-#define CAPI_REQ 0x80
-#define CAPI_CONF 0x81
-#define CAPI_IND 0x82
-#define CAPI_RESP 0x83
-
-/*----- CAPI combined commands -----*/
-
-#define CAPICMD(cmd,subcmd) (((cmd)<<8)|(subcmd))
-
-#define CAPI_DISCONNECT_REQ CAPICMD(CAPI_DISCONNECT,CAPI_REQ)
-#define CAPI_DISCONNECT_CONF CAPICMD(CAPI_DISCONNECT,CAPI_CONF)
-#define CAPI_DISCONNECT_IND CAPICMD(CAPI_DISCONNECT,CAPI_IND)
-#define CAPI_DISCONNECT_RESP CAPICMD(CAPI_DISCONNECT,CAPI_RESP)
-
-#define CAPI_ALERT_REQ CAPICMD(CAPI_ALERT,CAPI_REQ)
-#define CAPI_ALERT_CONF CAPICMD(CAPI_ALERT,CAPI_CONF)
-
-#define CAPI_CONNECT_REQ CAPICMD(CAPI_CONNECT,CAPI_REQ)
-#define CAPI_CONNECT_CONF CAPICMD(CAPI_CONNECT,CAPI_CONF)
-#define CAPI_CONNECT_IND CAPICMD(CAPI_CONNECT,CAPI_IND)
-#define CAPI_CONNECT_RESP CAPICMD(CAPI_CONNECT,CAPI_RESP)
-
-#define CAPI_CONNECT_ACTIVE_REQ CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_REQ)
-#define CAPI_CONNECT_ACTIVE_CONF CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_CONF)
-#define CAPI_CONNECT_ACTIVE_IND CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_IND)
-#define CAPI_CONNECT_ACTIVE_RESP CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_RESP)
-
-#define CAPI_SELECT_B_PROTOCOL_REQ CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_REQ)
-#define CAPI_SELECT_B_PROTOCOL_CONF CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_CONF)
-
-#define CAPI_CONNECT_B3_ACTIVE_REQ CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_REQ)
-#define CAPI_CONNECT_B3_ACTIVE_CONF CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_CONF)
-#define CAPI_CONNECT_B3_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_IND)
-#define CAPI_CONNECT_B3_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_RESP)
-
-#define CAPI_CONNECT_B3_REQ CAPICMD(CAPI_CONNECT_B3,CAPI_REQ)
-#define CAPI_CONNECT_B3_CONF CAPICMD(CAPI_CONNECT_B3,CAPI_CONF)
-#define CAPI_CONNECT_B3_IND CAPICMD(CAPI_CONNECT_B3,CAPI_IND)
-#define CAPI_CONNECT_B3_RESP CAPICMD(CAPI_CONNECT_B3,CAPI_RESP)
-
-
-#define CAPI_CONNECT_B3_T90_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_IND)
-#define CAPI_CONNECT_B3_T90_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_RESP)
-
-#define CAPI_DATA_B3_REQ CAPICMD(CAPI_DATA_B3,CAPI_REQ)
-#define CAPI_DATA_B3_CONF CAPICMD(CAPI_DATA_B3,CAPI_CONF)
-#define CAPI_DATA_B3_IND CAPICMD(CAPI_DATA_B3,CAPI_IND)
-#define CAPI_DATA_B3_RESP CAPICMD(CAPI_DATA_B3,CAPI_RESP)
-
-#define CAPI_DISCONNECT_B3_REQ CAPICMD(CAPI_DISCONNECT_B3,CAPI_REQ)
-#define CAPI_DISCONNECT_B3_CONF CAPICMD(CAPI_DISCONNECT_B3,CAPI_CONF)
-#define CAPI_DISCONNECT_B3_IND CAPICMD(CAPI_DISCONNECT_B3,CAPI_IND)
-#define CAPI_DISCONNECT_B3_RESP CAPICMD(CAPI_DISCONNECT_B3,CAPI_RESP)
-
-#define CAPI_RESET_B3_REQ CAPICMD(CAPI_RESET_B3,CAPI_REQ)
-#define CAPI_RESET_B3_CONF CAPICMD(CAPI_RESET_B3,CAPI_CONF)
-#define CAPI_RESET_B3_IND CAPICMD(CAPI_RESET_B3,CAPI_IND)
-#define CAPI_RESET_B3_RESP CAPICMD(CAPI_RESET_B3,CAPI_RESP)
-
-#define CAPI_LISTEN_REQ CAPICMD(CAPI_LISTEN,CAPI_REQ)
-#define CAPI_LISTEN_CONF CAPICMD(CAPI_LISTEN,CAPI_CONF)
-
-#define CAPI_MANUFACTURER_REQ CAPICMD(CAPI_MANUFACTURER,CAPI_REQ)
-#define CAPI_MANUFACTURER_CONF CAPICMD(CAPI_MANUFACTURER,CAPI_CONF)
-#define CAPI_MANUFACTURER_IND CAPICMD(CAPI_MANUFACTURER,CAPI_IND)
-#define CAPI_MANUFACTURER_RESP CAPICMD(CAPI_MANUFACTURER,CAPI_RESP)
-
-#define CAPI_FACILITY_REQ CAPICMD(CAPI_FACILITY,CAPI_REQ)
-#define CAPI_FACILITY_CONF CAPICMD(CAPI_FACILITY,CAPI_CONF)
-#define CAPI_FACILITY_IND CAPICMD(CAPI_FACILITY,CAPI_IND)
-#define CAPI_FACILITY_RESP CAPICMD(CAPI_FACILITY,CAPI_RESP)
-
-#define CAPI_INFO_REQ CAPICMD(CAPI_INFO,CAPI_REQ)
-#define CAPI_INFO_CONF CAPICMD(CAPI_INFO,CAPI_CONF)
-#define CAPI_INFO_IND CAPICMD(CAPI_INFO,CAPI_IND)
-#define CAPI_INFO_RESP CAPICMD(CAPI_INFO,CAPI_RESP)
-
-#endif /* __CAPICMD_H__ */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * $Id: kernelcapi.h,v 1.8.6.2 2001/02/07 11:31:31 kai Exp $
- *
- * Kernel CAPI 2.0 Interface for Linux
- *
- * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
- *
- */
-
-#ifndef _UAPI__KERNELCAPI_H__
-#define _UAPI__KERNELCAPI_H__
-
-#define CAPI_MAXAPPL 240 /* maximum number of applications */
-#define CAPI_MAXCONTR 32 /* maximum number of controller */
-#define CAPI_MAXDATAWINDOW 8
-
-
-typedef struct kcapi_flagdef {
- int contr;
- int flag;
-} kcapi_flagdef;
-
-typedef struct kcapi_carddef {
- char driver[32];
- unsigned int port;
- unsigned irq;
- unsigned int membase;
- int cardnr;
-} kcapi_carddef;
-
-/* new ioctls >= 10 */
-#define KCAPI_CMD_TRACE 10
-#define KCAPI_CMD_ADDCARD 11 /* OBSOLETE */
-
-/*
- * flag > 2 => trace also data
- * flag & 1 => show trace
- */
-#define KCAPI_TRACE_OFF 0
-#define KCAPI_TRACE_SHORT_NO_DATA 1
-#define KCAPI_TRACE_FULL_NO_DATA 2
-#define KCAPI_TRACE_SHORT 3
-#define KCAPI_TRACE_FULL 4
-
-
-
-#endif /* _UAPI__KERNELCAPI_H__ */
HCI Device drivers (Interface to the hardware)
RFCOMM Module (RFCOMM Protocol)
BNEP Module (Bluetooth Network Encapsulation Protocol)
- CMTP Module (CAPI Message Transport Protocol)
HIDP Module (Human Interface Device Protocol)
Say Y here to compile Bluetooth support into the kernel or say M to
source "net/bluetooth/bnep/Kconfig"
-source "net/bluetooth/cmtp/Kconfig"
-
source "net/bluetooth/hidp/Kconfig"
config BT_LE
obj-$(CONFIG_BT) += bluetooth.o
obj-$(CONFIG_BT_RFCOMM) += rfcomm/
obj-$(CONFIG_BT_BNEP) += bnep/
-obj-$(CONFIG_BT_CMTP) += cmtp/
obj-$(CONFIG_BT_HIDP) += hidp/
obj-$(CONFIG_BT_6LOWPAN) += bluetooth_6lowpan.o
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0-only
-config BT_CMTP
- tristate "CMTP protocol support (DEPRECATED)"
- depends on BT_BREDR && ISDN_CAPI && DEPRECATED
- help
- CMTP (CAPI Message Transport Protocol) is a transport layer
- for CAPI messages. CMTP is required for the Bluetooth Common
- ISDN Access Profile.
-
- Say Y here to compile CMTP support into the kernel or say M to
- compile it as module (cmtp).
-
+++ /dev/null
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Linux Bluetooth CMTP layer
-#
-
-obj-$(CONFIG_BT_CMTP) += cmtp.o
-
-cmtp-objs := core.o sock.o capi.o
+++ /dev/null
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/export.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched/signal.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/wait.h>
-#include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/isdn/capilli.h>
-#include <linux/isdn/capicmd.h>
-#include <linux/isdn/capiutil.h>
-
-#include "cmtp.h"
-
-#define CAPI_INTEROPERABILITY 0x20
-
-#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
-#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
-#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
-#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
-
-#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
-#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4)
-#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
-#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2)
-
-#define CAPI_FUNCTION_REGISTER 0
-#define CAPI_FUNCTION_RELEASE 1
-#define CAPI_FUNCTION_GET_PROFILE 2
-#define CAPI_FUNCTION_GET_MANUFACTURER 3
-#define CAPI_FUNCTION_GET_VERSION 4
-#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
-#define CAPI_FUNCTION_MANUFACTURER 6
-#define CAPI_FUNCTION_LOOPBACK 7
-
-
-#define CMTP_MSGNUM 1
-#define CMTP_APPLID 2
-#define CMTP_MAPPING 3
-
-static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
-{
- struct cmtp_application *app = kzalloc_obj(*app);
-
- BT_DBG("session %p application %p appl %u", session, app, appl);
-
- if (!app)
- return NULL;
-
- app->state = BT_OPEN;
- app->appl = appl;
-
- list_add_tail(&app->list, &session->applications);
-
- return app;
-}
-
-static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
-{
- BT_DBG("session %p application %p", session, app);
-
- if (app) {
- list_del(&app->list);
- kfree(app);
- }
-}
-
-static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
-{
- struct cmtp_application *app;
-
- list_for_each_entry(app, &session->applications, list) {
- switch (pattern) {
- case CMTP_MSGNUM:
- if (app->msgnum == value)
- return app;
- break;
- case CMTP_APPLID:
- if (app->appl == value)
- return app;
- break;
- case CMTP_MAPPING:
- if (app->mapping == value)
- return app;
- break;
- }
- }
-
- return NULL;
-}
-
-static int cmtp_msgnum_get(struct cmtp_session *session)
-{
- session->msgnum++;
-
- if ((session->msgnum & 0xff) > 200)
- session->msgnum = CMTP_INITIAL_MSGNUM + 1;
-
- return session->msgnum;
-}
-
-static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-{
- struct cmtp_scb *scb = (void *) skb->cb;
-
- BT_DBG("session %p skb %p len %u", session, skb, skb->len);
-
- scb->id = -1;
- scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
-
- skb_queue_tail(&session->transmit, skb);
-
- wake_up_interruptible(sk_sleep(session->sock->sk));
-}
-
-static void cmtp_send_interopmsg(struct cmtp_session *session,
- __u8 subcmd, __u16 appl, __u16 msgnum,
- __u16 function, unsigned char *buf, int len)
-{
- struct sk_buff *skb;
- unsigned char *s;
-
- BT_DBG("session %p subcmd 0x%02x appl %u msgnum %u", session, subcmd, appl, msgnum);
-
- skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("Can't allocate memory for interoperability packet");
- return;
- }
-
- s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
-
- capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
- capimsg_setu16(s, 2, appl);
- capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
- capimsg_setu8 (s, 5, subcmd);
- capimsg_setu16(s, 6, msgnum);
-
- /* Interoperability selector (Bluetooth Device Management) */
- capimsg_setu16(s, 8, 0x0001);
-
- capimsg_setu8 (s, 10, 3 + len);
- capimsg_setu16(s, 11, function);
- capimsg_setu8 (s, 13, len);
-
- if (len > 0)
- memcpy(s + 14, buf, len);
-
- cmtp_send_capimsg(session, skb);
-}
-
-static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
-{
- struct capi_ctr *ctrl = &session->ctrl;
- struct cmtp_application *application;
- __u16 appl, msgnum, func, info;
- __u32 controller;
-
- BT_DBG("session %p skb %p len %u", session, skb, skb->len);
-
- switch (CAPIMSG_SUBCOMMAND(skb->data)) {
- case CAPI_CONF:
- if (skb->len < CAPI_MSG_BASELEN + 10)
- break;
-
- func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
- info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
-
- switch (func) {
- case CAPI_FUNCTION_REGISTER:
- msgnum = CAPIMSG_MSGID(skb->data);
-
- application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
- if (application) {
- application->state = BT_CONNECTED;
- application->msgnum = 0;
- application->mapping = CAPIMSG_APPID(skb->data);
- wake_up_interruptible(&session->wait);
- }
-
- break;
-
- case CAPI_FUNCTION_RELEASE:
- appl = CAPIMSG_APPID(skb->data);
-
- application = cmtp_application_get(session, CMTP_MAPPING, appl);
- if (application) {
- application->state = BT_CLOSED;
- application->msgnum = 0;
- wake_up_interruptible(&session->wait);
- }
-
- break;
-
- case CAPI_FUNCTION_GET_PROFILE:
- if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
- break;
-
- controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
- msgnum = CAPIMSG_MSGID(skb->data);
-
- if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
- session->ncontroller = controller;
- wake_up_interruptible(&session->wait);
- break;
- }
-
- if (!info && ctrl) {
- memcpy(&ctrl->profile,
- skb->data + CAPI_MSG_BASELEN + 11,
- sizeof(capi_profile));
- session->state = BT_CONNECTED;
- capi_ctr_ready(ctrl);
- }
-
- break;
-
- case CAPI_FUNCTION_GET_MANUFACTURER:
- if (!info && ctrl && skb->len > CAPI_MSG_BASELEN + 14)
- strscpy_pad(ctrl->manu,
- skb->data + CAPI_MSG_BASELEN + 15,
- skb->data[CAPI_MSG_BASELEN + 14]);
- break;
-
- case CAPI_FUNCTION_GET_VERSION:
- if (skb->len < CAPI_MSG_BASELEN + 32)
- break;
-
- if (!info && ctrl) {
- ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
- ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
- ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
- ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
- }
-
- break;
-
- case CAPI_FUNCTION_GET_SERIAL_NUMBER:
- if (!info && ctrl && skb->len > CAPI_MSG_BASELEN + 16)
- strscpy_pad(ctrl->serial,
- skb->data + CAPI_MSG_BASELEN + 17,
- skb->data[CAPI_MSG_BASELEN + 16]);
- break;
- }
-
- break;
-
- case CAPI_IND:
- if (skb->len < CAPI_MSG_BASELEN + 6)
- break;
-
- func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
-
- if (func == CAPI_FUNCTION_LOOPBACK) {
- int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
- skb->data[CAPI_MSG_BASELEN + 5]);
- appl = CAPIMSG_APPID(skb->data);
- msgnum = CAPIMSG_MSGID(skb->data);
- cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
- skb->data + CAPI_MSG_BASELEN + 6, len);
- }
-
- break;
- }
-
- kfree_skb(skb);
-}
-
-void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-{
- struct capi_ctr *ctrl = &session->ctrl;
- struct cmtp_application *application;
- __u16 appl;
- __u32 contr;
-
- BT_DBG("session %p skb %p len %u", session, skb, skb->len);
-
- if (skb->len < CAPI_MSG_BASELEN)
- return;
-
- if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
- cmtp_recv_interopmsg(session, skb);
- return;
- }
-
- if (session->flags & BIT(CMTP_LOOPBACK)) {
- kfree_skb(skb);
- return;
- }
-
- appl = CAPIMSG_APPID(skb->data);
- contr = CAPIMSG_CONTROL(skb->data);
-
- application = cmtp_application_get(session, CMTP_MAPPING, appl);
- if (application) {
- appl = application->appl;
- CAPIMSG_SETAPPID(skb->data, appl);
- } else {
- BT_ERR("Can't find application with id %u", appl);
- kfree_skb(skb);
- return;
- }
-
- if ((contr & 0x7f) == 0x01) {
- contr = (contr & 0xffffff80) | session->num;
- CAPIMSG_SETCONTROL(skb->data, contr);
- }
-
- capi_ctr_handle_message(ctrl, appl, skb);
-}
-
-static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
-{
- BT_DBG("ctrl %p data %p", ctrl, data);
-
- return 0;
-}
-
-static void cmtp_reset_ctr(struct capi_ctr *ctrl)
-{
- struct cmtp_session *session = ctrl->driverdata;
-
- BT_DBG("ctrl %p", ctrl);
-
- capi_ctr_down(ctrl);
-
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
-}
-
-static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *application;
- unsigned long timeo = CMTP_INTEROP_TIMEOUT;
- unsigned char buf[8];
- int err = 0, nconn, want = rp->level3cnt;
-
- BT_DBG("ctrl %p appl %u level3cnt %u datablkcnt %u datablklen %u",
- ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
-
- application = cmtp_application_add(session, appl);
- if (!application) {
- BT_ERR("Can't allocate memory for new application");
- return;
- }
-
- if (want < 0)
- nconn = ctrl->profile.nbchannel * -want;
- else
- nconn = want;
-
- if (nconn == 0)
- nconn = ctrl->profile.nbchannel;
-
- capimsg_setu16(buf, 0, nconn);
- capimsg_setu16(buf, 2, rp->datablkcnt);
- capimsg_setu16(buf, 4, rp->datablklen);
-
- application->state = BT_CONFIG;
- application->msgnum = cmtp_msgnum_get(session);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
- CAPI_FUNCTION_REGISTER, buf, 6);
-
- add_wait_queue(&session->wait, &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (!timeo) {
- err = -EAGAIN;
- break;
- }
-
- if (application->state == BT_CLOSED) {
- err = -application->err;
- break;
- }
-
- if (application->state == BT_CONNECTED)
- break;
-
- if (signal_pending(current)) {
- err = -EINTR;
- break;
- }
-
- timeo = schedule_timeout(timeo);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&session->wait, &wait);
-
- if (err) {
- cmtp_application_del(session, application);
- return;
- }
-}
-
-static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
-{
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *application;
-
- BT_DBG("ctrl %p appl %u", ctrl, appl);
-
- application = cmtp_application_get(session, CMTP_APPLID, appl);
- if (!application) {
- BT_ERR("Can't find application");
- return;
- }
-
- application->msgnum = cmtp_msgnum_get(session);
-
- cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
- CAPI_FUNCTION_RELEASE, NULL, 0);
-
- wait_event_interruptible_timeout(session->wait,
- (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
-
- cmtp_application_del(session, application);
-}
-
-static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
-{
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *application;
- __u16 appl;
- __u32 contr;
-
- BT_DBG("ctrl %p skb %p", ctrl, skb);
-
- appl = CAPIMSG_APPID(skb->data);
- contr = CAPIMSG_CONTROL(skb->data);
-
- application = cmtp_application_get(session, CMTP_APPLID, appl);
- if ((!application) || (application->state != BT_CONNECTED)) {
- BT_ERR("Can't find application with id %u", appl);
- return CAPI_ILLAPPNR;
- }
-
- CAPIMSG_SETAPPID(skb->data, application->mapping);
-
- if ((contr & 0x7f) == session->num) {
- contr = (contr & 0xffffff80) | 0x01;
- CAPIMSG_SETCONTROL(skb->data, contr);
- }
-
- cmtp_send_capimsg(session, skb);
-
- return CAPI_NOERROR;
-}
-
-static char *cmtp_procinfo(struct capi_ctr *ctrl)
-{
- return "CAPI Message Transport Protocol";
-}
-
-static int cmtp_proc_show(struct seq_file *m, void *v)
-{
- struct capi_ctr *ctrl = m->private;
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *app;
-
- seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
- seq_printf(m, "addr %s\n", session->name);
- seq_printf(m, "ctrl %d\n", session->num);
-
- list_for_each_entry(app, &session->applications, list) {
- seq_printf(m, "appl %u -> %u\n", app->appl, app->mapping);
- }
-
- return 0;
-}
-
-int cmtp_attach_device(struct cmtp_session *session)
-{
- unsigned char buf[4];
- long ret;
-
- BT_DBG("session %p", session);
-
- capimsg_setu32(buf, 0, 0);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
- CAPI_FUNCTION_GET_PROFILE, buf, 4);
-
- ret = wait_event_interruptible_timeout(session->wait,
- session->ncontroller, CMTP_INTEROP_TIMEOUT);
-
- BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
-
- if (!ret)
- return -ETIMEDOUT;
-
- if (!session->ncontroller)
- return -ENODEV;
-
- if (session->ncontroller > 1)
- BT_INFO("Setting up only CAPI controller 1");
-
- session->ctrl.owner = THIS_MODULE;
- session->ctrl.driverdata = session;
- strcpy(session->ctrl.name, session->name);
-
- session->ctrl.driver_name = "cmtp";
- session->ctrl.load_firmware = cmtp_load_firmware;
- session->ctrl.reset_ctr = cmtp_reset_ctr;
- session->ctrl.register_appl = cmtp_register_appl;
- session->ctrl.release_appl = cmtp_release_appl;
- session->ctrl.send_message = cmtp_send_message;
-
- session->ctrl.procinfo = cmtp_procinfo;
- session->ctrl.proc_show = cmtp_proc_show;
-
- if (attach_capi_ctr(&session->ctrl) < 0) {
- BT_ERR("Can't attach new controller");
- return -EBUSY;
- }
-
- session->num = session->ctrl.cnr;
-
- BT_DBG("session %p num %d", session, session->num);
-
- capimsg_setu32(buf, 0, 1);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_VERSION, buf, 4);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_PROFILE, buf, 4);
-
- return 0;
-}
-
-void cmtp_detach_device(struct cmtp_session *session)
-{
- BT_DBG("session %p", session);
-
- detach_capi_ctr(&session->ctrl);
-}
+++ /dev/null
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#ifndef __CMTP_H
-#define __CMTP_H
-
-#include <linux/types.h>
-#include <net/bluetooth/bluetooth.h>
-
-#define BTNAMSIZ 21
-
-/* CMTP ioctl defines */
-#define CMTPCONNADD _IOW('C', 200, int)
-#define CMTPCONNDEL _IOW('C', 201, int)
-#define CMTPGETCONNLIST _IOR('C', 210, int)
-#define CMTPGETCONNINFO _IOR('C', 211, int)
-
-#define CMTP_LOOPBACK 0
-
-struct cmtp_connadd_req {
- int sock; /* Connected socket */
- __u32 flags;
-};
-
-struct cmtp_conndel_req {
- bdaddr_t bdaddr;
- __u32 flags;
-};
-
-struct cmtp_conninfo {
- bdaddr_t bdaddr;
- __u32 flags;
- __u16 state;
- int num;
-};
-
-struct cmtp_connlist_req {
- __u32 cnum;
- struct cmtp_conninfo __user *ci;
-};
-
-int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock);
-int cmtp_del_connection(struct cmtp_conndel_req *req);
-int cmtp_get_connlist(struct cmtp_connlist_req *req);
-int cmtp_get_conninfo(struct cmtp_conninfo *ci);
-
-/* CMTP session defines */
-#define CMTP_INTEROP_TIMEOUT (HZ * 5)
-#define CMTP_INITIAL_MSGNUM 0xff00
-
-struct cmtp_session {
- struct list_head list;
-
- struct socket *sock;
-
- bdaddr_t bdaddr;
-
- unsigned long state;
- unsigned long flags;
-
- uint mtu;
-
- char name[BTNAMSIZ];
-
- atomic_t terminate;
- struct task_struct *task;
-
- wait_queue_head_t wait;
-
- int ncontroller;
- int num;
- struct capi_ctr ctrl;
-
- struct list_head applications;
-
- unsigned long blockids;
- int msgnum;
-
- struct sk_buff_head transmit;
-
- struct sk_buff *reassembly[16];
-};
-
-struct cmtp_application {
- struct list_head list;
-
- unsigned long state;
- int err;
-
- __u16 appl;
- __u16 mapping;
-
- __u16 msgnum;
-};
-
-struct cmtp_scb {
- int id;
- int data;
-};
-
-int cmtp_attach_device(struct cmtp_session *session);
-void cmtp_detach_device(struct cmtp_session *session);
-
-void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
-
-/* CMTP init defines */
-int cmtp_init_sockets(void);
-void cmtp_cleanup_sockets(void);
-
-#endif /* __CMTP_H */
+++ /dev/null
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/freezer.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/init.h>
-#include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/isdn/capilli.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/l2cap.h>
-
-#include "cmtp.h"
-
-#define VERSION "1.0"
-
-static DECLARE_RWSEM(cmtp_session_sem);
-static LIST_HEAD(cmtp_session_list);
-
-static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
-{
- struct cmtp_session *session;
-
- BT_DBG("");
-
- list_for_each_entry(session, &cmtp_session_list, list)
- if (!bacmp(bdaddr, &session->bdaddr))
- return session;
-
- return NULL;
-}
-
-static void __cmtp_link_session(struct cmtp_session *session)
-{
- list_add(&session->list, &cmtp_session_list);
-}
-
-static void __cmtp_unlink_session(struct cmtp_session *session)
-{
- list_del(&session->list);
-}
-
-static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
-{
- u32 valid_flags = BIT(CMTP_LOOPBACK);
- memset(ci, 0, sizeof(*ci));
- bacpy(&ci->bdaddr, &session->bdaddr);
-
- ci->flags = session->flags & valid_flags;
- ci->state = session->state;
-
- ci->num = session->num;
-}
-
-
-static inline int cmtp_alloc_block_id(struct cmtp_session *session)
-{
- int i, id = -1;
-
- for (i = 0; i < 16; i++)
- if (!test_and_set_bit(i, &session->blockids)) {
- id = i;
- break;
- }
-
- return id;
-}
-
-static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
-{
- clear_bit(id, &session->blockids);
-}
-
-static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
-{
- struct sk_buff *skb = session->reassembly[id], *nskb;
- int size;
-
- BT_DBG("session %p buf %p count %d", session, buf, count);
-
- size = (skb) ? skb->len + count : count;
-
- nskb = alloc_skb(size, GFP_ATOMIC);
- if (!nskb) {
- BT_ERR("Can't allocate memory for CAPI message");
- return;
- }
-
- if (skb && (skb->len > 0))
- skb_copy_from_linear_data(skb, skb_put(nskb, skb->len), skb->len);
-
- skb_put_data(nskb, buf, count);
-
- session->reassembly[id] = nskb;
-
- kfree_skb(skb);
-}
-
-static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
-{
- __u8 hdr, hdrlen, id;
- __u16 len;
-
- BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
- while (skb->len > 0) {
- hdr = skb->data[0];
-
- switch (hdr & 0xc0) {
- case 0x40:
- hdrlen = 2;
- len = skb->data[1];
- break;
- case 0x80:
- hdrlen = 3;
- len = skb->data[1] | (skb->data[2] << 8);
- break;
- default:
- hdrlen = 1;
- len = 0;
- break;
- }
-
- id = (hdr & 0x3c) >> 2;
-
- BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
-
- if (hdrlen + len > skb->len) {
- BT_ERR("Wrong size or header information in CMTP frame");
- break;
- }
-
- if (len == 0) {
- skb_pull(skb, hdrlen);
- continue;
- }
-
- switch (hdr & 0x03) {
- case 0x00:
- cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
- cmtp_recv_capimsg(session, session->reassembly[id]);
- session->reassembly[id] = NULL;
- break;
- case 0x01:
- cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
- break;
- default:
- kfree_skb(session->reassembly[id]);
- session->reassembly[id] = NULL;
- break;
- }
-
- skb_pull(skb, hdrlen + len);
- }
-
- kfree_skb(skb);
- return 0;
-}
-
-static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
-{
- struct socket *sock = session->sock;
- struct kvec iv = { data, len };
- struct msghdr msg;
-
- BT_DBG("session %p data %p len %d", session, data, len);
-
- if (!len)
- return 0;
-
- memset(&msg, 0, sizeof(msg));
-
- return kernel_sendmsg(sock, &msg, &iv, 1, len);
-}
-
-static void cmtp_process_transmit(struct cmtp_session *session)
-{
- struct sk_buff *skb, *nskb;
- unsigned char *hdr;
- unsigned int size, tail;
-
- BT_DBG("session %p", session);
-
- nskb = alloc_skb(session->mtu, GFP_ATOMIC);
- if (!nskb) {
- BT_ERR("Can't allocate memory for new frame");
- return;
- }
-
- while ((skb = skb_dequeue(&session->transmit))) {
- struct cmtp_scb *scb = (void *) skb->cb;
-
- tail = session->mtu - nskb->len;
- if (tail < 5) {
- cmtp_send_frame(session, nskb->data, nskb->len);
- skb_trim(nskb, 0);
- tail = session->mtu;
- }
-
- size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
-
- if (scb->id < 0) {
- scb->id = cmtp_alloc_block_id(session);
- if (scb->id < 0) {
- skb_queue_head(&session->transmit, skb);
- break;
- }
- }
-
- if (size < 256) {
- hdr = skb_put(nskb, 2);
- hdr[0] = 0x40
- | ((scb->id << 2) & 0x3c)
- | ((skb->len == size) ? 0x00 : 0x01);
- hdr[1] = size;
- } else {
- hdr = skb_put(nskb, 3);
- hdr[0] = 0x80
- | ((scb->id << 2) & 0x3c)
- | ((skb->len == size) ? 0x00 : 0x01);
- hdr[1] = size & 0xff;
- hdr[2] = size >> 8;
- }
-
- skb_copy_from_linear_data(skb, skb_put(nskb, size), size);
- skb_pull(skb, size);
-
- if (skb->len > 0) {
- skb_queue_head(&session->transmit, skb);
- } else {
- cmtp_free_block_id(session, scb->id);
- if (scb->data) {
- cmtp_send_frame(session, nskb->data, nskb->len);
- skb_trim(nskb, 0);
- }
- kfree_skb(skb);
- }
- }
-
- cmtp_send_frame(session, nskb->data, nskb->len);
-
- kfree_skb(nskb);
-}
-
-static int cmtp_session(void *arg)
-{
- struct cmtp_session *session = arg;
- struct sock *sk = session->sock->sk;
- struct sk_buff *skb;
- DEFINE_WAIT_FUNC(wait, woken_wake_function);
-
- BT_DBG("session %p", session);
-
- set_user_nice(current, -15);
-
- add_wait_queue(sk_sleep(sk), &wait);
- while (1) {
- if (atomic_read(&session->terminate))
- break;
- if (sk->sk_state != BT_CONNECTED)
- break;
-
- while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
- skb_orphan(skb);
- if (!skb_linearize(skb))
- cmtp_recv_frame(session, skb);
- else
- kfree_skb(skb);
- }
-
- cmtp_process_transmit(session);
-
- /*
- * wait_woken() performs the necessary memory barriers
- * for us; see the header comment for this primitive.
- */
- wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
- }
- remove_wait_queue(sk_sleep(sk), &wait);
-
- down_write(&cmtp_session_sem);
-
- if (!(session->flags & BIT(CMTP_LOOPBACK)))
- cmtp_detach_device(session);
-
- fput(session->sock->file);
-
- __cmtp_unlink_session(session);
-
- up_write(&cmtp_session_sem);
-
- kfree(session);
- module_put_and_kthread_exit(0);
- return 0;
-}
-
-int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
-{
- u32 valid_flags = BIT(CMTP_LOOPBACK);
- struct cmtp_session *session, *s;
- int i, err;
-
- BT_DBG("");
-
- if (!l2cap_is_socket(sock))
- return -EBADFD;
-
- if (req->flags & ~valid_flags)
- return -EINVAL;
-
- session = kzalloc_obj(struct cmtp_session);
- if (!session)
- return -ENOMEM;
-
- down_write(&cmtp_session_sem);
-
- s = __cmtp_get_session(&l2cap_pi(sock->sk)->chan->dst);
- if (s && s->state == BT_CONNECTED) {
- err = -EEXIST;
- goto failed;
- }
-
- bacpy(&session->bdaddr, &l2cap_pi(sock->sk)->chan->dst);
-
- session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu,
- l2cap_pi(sock->sk)->chan->imtu);
-
- BT_DBG("mtu %d", session->mtu);
-
- sprintf(session->name, "%pMR", &session->bdaddr);
-
- session->sock = sock;
- session->state = BT_CONFIG;
-
- init_waitqueue_head(&session->wait);
-
- session->msgnum = CMTP_INITIAL_MSGNUM;
-
- INIT_LIST_HEAD(&session->applications);
-
- skb_queue_head_init(&session->transmit);
-
- for (i = 0; i < 16; i++)
- session->reassembly[i] = NULL;
-
- session->flags = req->flags;
-
- __cmtp_link_session(session);
-
- __module_get(THIS_MODULE);
- session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d",
- session->num);
- if (IS_ERR(session->task)) {
- module_put(THIS_MODULE);
- err = PTR_ERR(session->task);
- goto unlink;
- }
-
- if (!(session->flags & BIT(CMTP_LOOPBACK))) {
- err = cmtp_attach_device(session);
- if (err < 0) {
- /* Caller will call fput in case of failure, and so
- * will cmtp_session kthread.
- */
- get_file(session->sock->file);
-
- atomic_inc(&session->terminate);
- wake_up_interruptible(sk_sleep(session->sock->sk));
- up_write(&cmtp_session_sem);
- return err;
- }
- }
-
- up_write(&cmtp_session_sem);
- return 0;
-
-unlink:
- __cmtp_unlink_session(session);
-
-failed:
- up_write(&cmtp_session_sem);
- kfree(session);
- return err;
-}
-
-int cmtp_del_connection(struct cmtp_conndel_req *req)
-{
- u32 valid_flags = 0;
- struct cmtp_session *session;
- int err = 0;
-
- BT_DBG("");
-
- if (req->flags & ~valid_flags)
- return -EINVAL;
-
- down_read(&cmtp_session_sem);
-
- session = __cmtp_get_session(&req->bdaddr);
- if (session) {
- /* Flush the transmit queue */
- skb_queue_purge(&session->transmit);
-
- /* Stop session thread */
- atomic_inc(&session->terminate);
-
- /*
- * See the comment preceding the call to wait_woken()
- * in cmtp_session().
- */
- wake_up_interruptible(sk_sleep(session->sock->sk));
- } else
- err = -ENOENT;
-
- up_read(&cmtp_session_sem);
- return err;
-}
-
-int cmtp_get_connlist(struct cmtp_connlist_req *req)
-{
- struct cmtp_session *session;
- int err = 0, n = 0;
-
- BT_DBG("");
-
- down_read(&cmtp_session_sem);
-
- list_for_each_entry(session, &cmtp_session_list, list) {
- struct cmtp_conninfo ci;
-
- __cmtp_copy_session(session, &ci);
-
- if (copy_to_user(req->ci, &ci, sizeof(ci))) {
- err = -EFAULT;
- break;
- }
-
- if (++n >= req->cnum)
- break;
-
- req->ci++;
- }
- req->cnum = n;
-
- up_read(&cmtp_session_sem);
- return err;
-}
-
-int cmtp_get_conninfo(struct cmtp_conninfo *ci)
-{
- struct cmtp_session *session;
- int err = 0;
-
- down_read(&cmtp_session_sem);
-
- session = __cmtp_get_session(&ci->bdaddr);
- if (session)
- __cmtp_copy_session(session, ci);
- else
- err = -ENOENT;
-
- up_read(&cmtp_session_sem);
- return err;
-}
-
-
-static int __init cmtp_init(void)
-{
- BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
-
- return cmtp_init_sockets();
-}
-
-static void __exit cmtp_exit(void)
-{
- cmtp_cleanup_sockets();
-}
-
-module_init(cmtp_init);
-module_exit(cmtp_exit);
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth CMTP ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("bt-proto-5");
+++ /dev/null
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/export.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <net/sock.h>
-
-#include <linux/isdn/capilli.h>
-
-
-#include "cmtp.h"
-
-static struct bt_sock_list cmtp_sk_list = {
- .lock = __RW_LOCK_UNLOCKED(cmtp_sk_list.lock)
-};
-
-static int cmtp_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- BT_DBG("sock %p sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- bt_sock_unlink(&cmtp_sk_list, sk);
-
- sock_orphan(sk);
- sock_put(sk);
-
- return 0;
-}
-
-static int do_cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
-{
- struct cmtp_connadd_req ca;
- struct cmtp_conndel_req cd;
- struct cmtp_connlist_req cl;
- struct cmtp_conninfo ci;
- struct socket *nsock;
- int err;
-
- BT_DBG("cmd %x arg %p", cmd, argp);
-
- switch (cmd) {
- case CMTPCONNADD:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (copy_from_user(&ca, argp, sizeof(ca)))
- return -EFAULT;
-
- nsock = sockfd_lookup(ca.sock, &err);
- if (!nsock)
- return err;
-
- if (nsock->sk->sk_state != BT_CONNECTED) {
- sockfd_put(nsock);
- return -EBADFD;
- }
-
- err = cmtp_add_connection(&ca, nsock);
- if (!err) {
- if (copy_to_user(argp, &ca, sizeof(ca)))
- err = -EFAULT;
- } else
- sockfd_put(nsock);
-
- return err;
-
- case CMTPCONNDEL:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (copy_from_user(&cd, argp, sizeof(cd)))
- return -EFAULT;
-
- return cmtp_del_connection(&cd);
-
- case CMTPGETCONNLIST:
- if (copy_from_user(&cl, argp, sizeof(cl)))
- return -EFAULT;
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = cmtp_get_connlist(&cl);
- if (!err && copy_to_user(argp, &cl, sizeof(cl)))
- return -EFAULT;
-
- return err;
-
- case CMTPGETCONNINFO:
- if (copy_from_user(&ci, argp, sizeof(ci)))
- return -EFAULT;
-
- err = cmtp_get_conninfo(&ci);
- if (!err && copy_to_user(argp, &ci, sizeof(ci)))
- return -EFAULT;
-
- return err;
- }
-
- return -EINVAL;
-}
-
-static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- return do_cmtp_sock_ioctl(sock, cmd, (void __user *)arg);
-}
-
-#ifdef CONFIG_COMPAT
-static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- void __user *argp = compat_ptr(arg);
- if (cmd == CMTPGETCONNLIST) {
- struct cmtp_connlist_req cl;
- u32 __user *p = argp;
- u32 uci;
- int err;
-
- if (get_user(cl.cnum, p) || get_user(uci, p + 1))
- return -EFAULT;
-
- cl.ci = compat_ptr(uci);
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = cmtp_get_connlist(&cl);
-
- if (!err && put_user(cl.cnum, p))
- err = -EFAULT;
-
- return err;
- }
-
- return do_cmtp_sock_ioctl(sock, cmd, argp);
-}
-#endif
-
-static const struct proto_ops cmtp_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = cmtp_sock_release,
- .ioctl = cmtp_sock_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = cmtp_sock_compat_ioctl,
-#endif
- .bind = sock_no_bind,
- .getname = sock_no_getname,
- .sendmsg = sock_no_sendmsg,
- .recvmsg = sock_no_recvmsg,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
-};
-
-static struct proto cmtp_proto = {
- .name = "CMTP",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct bt_sock)
-};
-
-static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- if (sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-
- sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, kern);
- if (!sk)
- return -ENOMEM;
-
- sock_init_data(sock, sk);
-
- sock->ops = &cmtp_sock_ops;
-
- sock->state = SS_UNCONNECTED;
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = protocol;
- sk->sk_state = BT_OPEN;
-
- bt_sock_link(&cmtp_sk_list, sk);
-
- return 0;
-}
-
-static const struct net_proto_family cmtp_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = cmtp_sock_create
-};
-
-int cmtp_init_sockets(void)
-{
- int err;
-
- err = proto_register(&cmtp_proto, 0);
- if (err < 0)
- return err;
-
- err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
- if (err < 0) {
- BT_ERR("Can't register CMTP socket");
- goto error;
- }
-
- err = bt_procfs_init(&init_net, "cmtp", &cmtp_sk_list, NULL);
- if (err < 0) {
- BT_ERR("Failed to create CMTP proc file");
- bt_sock_unregister(BTPROTO_HIDP);
- goto error;
- }
-
- BT_INFO("CMTP socket layer initialized");
-
- return 0;
-
-error:
- proto_unregister(&cmtp_proto);
- return err;
-}
-
-void cmtp_cleanup_sockets(void)
-{
- bt_procfs_cleanup(&init_net, "cmtp");
- bt_sock_unregister(BTPROTO_CMTP);
- proto_unregister(&cmtp_proto);
-}