diff options
Diffstat (limited to 'drivers/isdn')
64 files changed, 0 insertions, 41592 deletions
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig deleted file mode 100644 index 6fd1b3f84a29..000000000000 --- a/drivers/isdn/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# 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 diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile deleted file mode 100644 index d14334f4007e..000000000000 --- a/drivers/isdn/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# 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/ diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig deleted file mode 100644 index fdb43a632215..000000000000 --- a/drivers/isdn/capi/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# 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. diff --git a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile deleted file mode 100644 index 4fd3a4d7133f..000000000000 --- a/drivers/isdn/capi/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# 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 diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c deleted file mode 100644 index aa28b1d32c4e..000000000000 --- a/drivers/isdn/capi/capi.c +++ /dev/null @@ -1,1435 +0,0 @@ -/* $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); diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c deleted file mode 100644 index eec9b36343b7..000000000000 --- a/drivers/isdn/capi/capiutil.c +++ /dev/null @@ -1,677 +0,0 @@ -/* $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 diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c deleted file mode 100644 index f9fa17d68095..000000000000 --- a/drivers/isdn/capi/kcapi.c +++ /dev/null @@ -1,933 +0,0 @@ -/* $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); -} diff --git a/drivers/isdn/capi/kcapi.h b/drivers/isdn/capi/kcapi.h deleted file mode 100644 index 479623e1db2a..000000000000 --- a/drivers/isdn/capi/kcapi.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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); diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c deleted file mode 100644 index 77e951206809..000000000000 --- a/drivers/isdn/capi/kcapi_proc.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * 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); -} diff --git a/drivers/isdn/hardware/Makefile b/drivers/isdn/hardware/Makefile deleted file mode 100644 index 96f9eb2e46ba..000000000000 --- a/drivers/isdn/hardware/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Makefile for the CAPI hardware drivers - -# Object files in subdirectories - -obj-$(CONFIG_MISDN) += mISDN/ diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig deleted file mode 100644 index a35bff8a93f5..000000000000 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ /dev/null @@ -1,98 +0,0 @@ -# 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 - diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile deleted file mode 100644 index 3f50f8c4753f..000000000000 --- a/drivers/isdn/hardware/mISDN/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# 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 diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c deleted file mode 100644 index 55e0b9efa194..000000000000 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ /dev/null @@ -1,1164 +0,0 @@ -// 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); diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h deleted file mode 100644 index 5acf826d913c..000000000000 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ /dev/null @@ -1,1236 +0,0 @@ -/* 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 */ diff --git a/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h b/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h deleted file mode 100644 index 448ded8f9d24..000000000000 --- a/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h +++ /dev/null @@ -1,167 +0,0 @@ -/* 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; -} diff --git a/drivers/isdn/hardware/mISDN/hfc_pci.h b/drivers/isdn/hardware/mISDN/hfc_pci.h deleted file mode 100644 index a0e4806c11fa..000000000000 --- a/drivers/isdn/hardware/mISDN/hfc_pci.h +++ /dev/null @@ -1,214 +0,0 @@ -/* 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)) diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c deleted file mode 100644 index b3d28976b33a..000000000000 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ /dev/null @@ -1,5540 +0,0 @@ -// 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); diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c deleted file mode 100644 index 554a1c640321..000000000000 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ /dev/null @@ -1,2360 +0,0 @@ -// 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); diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c deleted file mode 100644 index 227babe83879..000000000000 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ /dev/null @@ -1,2157 +0,0 @@ -// 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); diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.h b/drivers/isdn/hardware/mISDN/hfcsusb.h deleted file mode 100644 index 7e2bc5068019..000000000000 --- a/drivers/isdn/hardware/mISDN/hfcsusb.h +++ /dev/null @@ -1,425 +0,0 @@ -/* 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__ */ diff --git a/drivers/isdn/hardware/mISDN/iohelper.h b/drivers/isdn/hardware/mISDN/iohelper.h deleted file mode 100644 index c81f7aba4b57..000000000000 --- a/drivers/isdn/hardware/mISDN/iohelper.h +++ /dev/null @@ -1,96 +0,0 @@ -/* 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 diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h deleted file mode 100644 index 2f0c4978a7a5..000000000000 --- a/drivers/isdn/hardware/mISDN/ipac.h +++ /dev/null @@ -1,393 +0,0 @@ -/* 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); diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h deleted file mode 100644 index 36a9fa564b17..000000000000 --- a/drivers/isdn/hardware/mISDN/isar.h +++ /dev/null @@ -1,256 +0,0 @@ -/* 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 *); diff --git a/drivers/isdn/hardware/mISDN/isdnhdlc.c b/drivers/isdn/hardware/mISDN/isdnhdlc.c deleted file mode 100644 index 985367e6711d..000000000000 --- a/drivers/isdn/hardware/mISDN/isdnhdlc.c +++ /dev/null @@ -1,617 +0,0 @@ -// 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); diff --git a/drivers/isdn/hardware/mISDN/isdnhdlc.h b/drivers/isdn/hardware/mISDN/isdnhdlc.h deleted file mode 100644 index fe2c1279c139..000000000000 --- a/drivers/isdn/hardware/mISDN/isdnhdlc.h +++ /dev/null @@ -1,69 +0,0 @@ -/* 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__ */ diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c deleted file mode 100644 index aaa639ad5526..000000000000 --- a/drivers/isdn/hardware/mISDN/mISDNinfineon.c +++ /dev/null @@ -1,1168 +0,0 @@ -// 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); diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c deleted file mode 100644 index a34ea6058960..000000000000 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ /dev/null @@ -1,1636 +0,0 @@ -// 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); diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c deleted file mode 100644 index dace91ba412b..000000000000 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ /dev/null @@ -1,1694 +0,0 @@ -// 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); diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c deleted file mode 100644 index 8d740d8eacec..000000000000 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ /dev/null @@ -1,1154 +0,0 @@ -// 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); diff --git a/drivers/isdn/hardware/mISDN/netjet.h b/drivers/isdn/hardware/mISDN/netjet.h deleted file mode 100644 index b23ad9f6d4d0..000000000000 --- a/drivers/isdn/hardware/mISDN/netjet.h +++ /dev/null @@ -1,44 +0,0 @@ -/* 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 */ diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c deleted file mode 100644 index ab24c3c460e6..000000000000 --- a/drivers/isdn/hardware/mISDN/speedfax.c +++ /dev/null @@ -1,520 +0,0 @@ -// 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); diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c deleted file mode 100644 index a341470c042f..000000000000 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ /dev/null @@ -1,1417 +0,0 @@ -// 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); diff --git a/drivers/isdn/hardware/mISDN/w6692.h b/drivers/isdn/hardware/mISDN/w6692.h deleted file mode 100644 index 45e1dc5d6c2d..000000000000 --- a/drivers/isdn/hardware/mISDN/w6692.h +++ /dev/null @@ -1,177 +0,0 @@ -/* 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 diff --git a/drivers/isdn/mISDN/Kconfig b/drivers/isdn/mISDN/Kconfig deleted file mode 100644 index c9a53c222472..000000000000 --- a/drivers/isdn/mISDN/Kconfig +++ /dev/null @@ -1,48 +0,0 @@ -# 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 diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile deleted file mode 100644 index f3b4b7fa85f8..000000000000 --- a/drivers/isdn/mISDN/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# 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 diff --git a/drivers/isdn/mISDN/clock.c b/drivers/isdn/mISDN/clock.c deleted file mode 100644 index 2668be9de20a..000000000000 --- a/drivers/isdn/mISDN/clock.c +++ /dev/null @@ -1,197 +0,0 @@ -// 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); diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c deleted file mode 100644 index 8ec2d4d4f135..000000000000 --- a/drivers/isdn/mISDN/core.c +++ /dev/null @@ -1,400 +0,0 @@ -// 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); diff --git a/drivers/isdn/mISDN/core.h b/drivers/isdn/mISDN/core.h deleted file mode 100644 index 5617c06de8e4..000000000000 --- a/drivers/isdn/mISDN/core.h +++ /dev/null @@ -1,69 +0,0 @@ -/* 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 diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h deleted file mode 100644 index baf31258f5c9..000000000000 --- a/drivers/isdn/mISDN/dsp.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * 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); diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c deleted file mode 100644 index bbef98e7a16e..000000000000 --- a/drivers/isdn/mISDN/dsp_audio.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * 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++; - } -} diff --git a/drivers/isdn/mISDN/dsp_biquad.h b/drivers/isdn/mISDN/dsp_biquad.h deleted file mode 100644 index f40d52a4c4ee..000000000000 --- a/drivers/isdn/mISDN/dsp_biquad.h +++ /dev/null @@ -1,51 +0,0 @@ -/* 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; -} diff --git a/drivers/isdn/mISDN/dsp_blowfish.c b/drivers/isdn/mISDN/dsp_blowfish.c deleted file mode 100644 index 0e77c282c862..000000000000 --- a/drivers/isdn/mISDN/dsp_blowfish.c +++ /dev/null @@ -1,667 +0,0 @@ -/* - * 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; -} diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c deleted file mode 100644 index d5eb2349c414..000000000000 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ /dev/null @@ -1,1949 +0,0 @@ -/* - * 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); - } - } - } -} diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c deleted file mode 100644 index d0aa415a6b09..000000000000 --- a/drivers/isdn/mISDN/dsp_core.c +++ /dev/null @@ -1,1227 +0,0 @@ -/* - * 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); diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c deleted file mode 100644 index 642f30be5ce2..000000000000 --- a/drivers/isdn/mISDN/dsp_dtmf.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * 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; -} diff --git a/drivers/isdn/mISDN/dsp_ecdis.h b/drivers/isdn/mISDN/dsp_ecdis.h deleted file mode 100644 index 4bcdf321875d..000000000000 --- a/drivers/isdn/mISDN/dsp_ecdis.h +++ /dev/null @@ -1,96 +0,0 @@ -/* 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 ------------------------------------------------------------*/ diff --git a/drivers/isdn/mISDN/dsp_hwec.c b/drivers/isdn/mISDN/dsp_hwec.c deleted file mode 100644 index 0cd216e28f00..000000000000 --- a/drivers/isdn/mISDN/dsp_hwec.c +++ /dev/null @@ -1,122 +0,0 @@ -// 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); -} diff --git a/drivers/isdn/mISDN/dsp_hwec.h b/drivers/isdn/mISDN/dsp_hwec.h deleted file mode 100644 index c9cb0ea249da..000000000000 --- a/drivers/isdn/mISDN/dsp_hwec.h +++ /dev/null @@ -1,10 +0,0 @@ -/* 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); diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c deleted file mode 100644 index 55693dc7206b..000000000000 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ /dev/null @@ -1,300 +0,0 @@ -// 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); -} diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c deleted file mode 100644 index fa7813ae8d97..000000000000 --- a/drivers/isdn/mISDN/dsp_tones.c +++ /dev/null @@ -1,550 +0,0 @@ -/* - * 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; -} diff --git a/drivers/isdn/mISDN/fsm.c b/drivers/isdn/mISDN/fsm.c deleted file mode 100644 index 825b686496d2..000000000000 --- a/drivers/isdn/mISDN/fsm.c +++ /dev/null @@ -1,176 +0,0 @@ -// 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); diff --git a/drivers/isdn/mISDN/fsm.h b/drivers/isdn/mISDN/fsm.h deleted file mode 100644 index 211554b997f8..000000000000 --- a/drivers/isdn/mISDN/fsm.h +++ /dev/null @@ -1,58 +0,0 @@ -/* 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 diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c deleted file mode 100644 index 8c93af06ed02..000000000000 --- a/drivers/isdn/mISDN/hwchannel.c +++ /dev/null @@ -1,516 +0,0 @@ -// 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); diff --git a/drivers/isdn/mISDN/l1oip.h b/drivers/isdn/mISDN/l1oip.h deleted file mode 100644 index 48133d022812..000000000000 --- a/drivers/isdn/mISDN/l1oip.h +++ /dev/null @@ -1,92 +0,0 @@ -/* 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); diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c deleted file mode 100644 index 1059234fbc67..000000000000 --- a/drivers/isdn/mISDN/l1oip_codec.c +++ /dev/null @@ -1,358 +0,0 @@ -// 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; -} diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c deleted file mode 100644 index 6866a0d6b382..000000000000 --- a/drivers/isdn/mISDN/l1oip_core.c +++ /dev/null @@ -1,1505 +0,0 @@ -// 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); diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c deleted file mode 100644 index 3fbc170acf9a..000000000000 --- a/drivers/isdn/mISDN/layer1.c +++ /dev/null @@ -1,415 +0,0 @@ -// 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); -} diff --git a/drivers/isdn/mISDN/layer1.h b/drivers/isdn/mISDN/layer1.h deleted file mode 100644 index f03e86450daf..000000000000 --- a/drivers/isdn/mISDN/layer1.h +++ /dev/null @@ -1,16 +0,0 @@ -/* 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 diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c deleted file mode 100644 index b75869c9f78f..000000000000 --- a/drivers/isdn/mISDN/layer2.c +++ /dev/null @@ -1,2266 +0,0 @@ -// 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); -} diff --git a/drivers/isdn/mISDN/layer2.h b/drivers/isdn/mISDN/layer2.h deleted file mode 100644 index c466fd94aa02..000000000000 --- a/drivers/isdn/mISDN/layer2.h +++ /dev/null @@ -1,131 +0,0 @@ -/* 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 diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c deleted file mode 100644 index 77b900db1cac..000000000000 --- a/drivers/isdn/mISDN/socket.c +++ /dev/null @@ -1,825 +0,0 @@ -// 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); -} diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c deleted file mode 100644 index 4e96684af0aa..000000000000 --- a/drivers/isdn/mISDN/stack.c +++ /dev/null @@ -1,654 +0,0 @@ -// 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; -} diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c deleted file mode 100644 index 2bad3083be90..000000000000 --- a/drivers/isdn/mISDN/tei.c +++ /dev/null @@ -1,1416 +0,0 @@ -// 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); -} diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c deleted file mode 100644 index a18845755633..000000000000 --- a/drivers/isdn/mISDN/timerdev.c +++ /dev/null @@ -1,295 +0,0 @@ -// 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); -} |
