isdn: deprecate non-mISDN drivers

When isdn4linux came up in the context of another patch series, I
 remembered that we had discussed removing it a while ago.
 
 It turns out that the suggestion from Karsten Keil wa to remove I4L
 in 2018 after the last public ISDN networks are shut down. This has
 happened now (with a very small number of exceptions), so I guess it's
 time to try again.
 
 We currently have three ISDN stacks in the kernel: the original
 isdn4linux (with the hisax driver), the newer CAPI (with four drivers),
 and finally the mISDN stack (supporting roughly the same hardware as
 hisax).
 
 As far as I can tell, anyone using ISDN with mainline kernel drivers in
 the past few years uses mISDN, and this is typically used for voice-only
 PBX installations that don't require a public network.
 
 The older stacks support additional features for data networks, but those
 typically make no sense any more if there is no network to connect to.
 
 My proposal for this time is to kill off isdn4linux entirely, as it seems
 to have been unusable for quite a while. This code has been abandoned
 for many years and it does cause problems for treewide maintenance as
 it tends to do everything that we try to stop doing.
 Birger Harzenetter mentioned that is is still using i4l in order to
 make use of the 'divert' feature that is not part of mISDN, but has
 otherwise moved on to mISDN for normal operation, like apparently
 everyone else.
 
 CAPI in turn is not quite as obsolete, but two of the drivers (avm
 and hysdn) don't seem to be used at all, while another one (gigaset)
 will stop being maintained as Paul Bolle is no longer able to
 test it after the network gets shut down in September.
 All three are now moved into drivers/staging to let others speak
 up in case there are remaining users.
 This leaves Bluetooth CMTP as the only remaining user of CAPI, but
 Marcel Holtmann wishes to keep maintaining it.
 
 For the discussion on version 1, see [2]
 Unfortunately, Karsten Keil as the maintainer has not participated in
 the discussion.
 
       Arnd
 
 [1] https://patchwork.kernel.org/patch/8484861/#17900371
 [2] https://listserv.isdn4linux.de/pipermail/isdn4linux/2019-April/thread.html
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJc8QxgAAoJEJpsee/mABjZriwQAKL4L62VUz9nbLdK1b0wHsT/
 ttHYRZwyzTqzzfXEEyTVynHdwW0qjXxmjfOP7gl1ZY62KtuuBC0XlpQ4Ho05h/DZ
 zqWSS+BunIHShbS/9Cv+/d2biGVa9+XPgbV2XptPC0zm+VuucnKIssPbawD65rQU
 BtiNFGqGNo5Wkjn5kdkFIIOdL+eNlW/+l8iuewhJfAoFJYMuKHy6jWUfUqDD/9nv
 EyrNdWgbPZqwLVKYcqQWpJ0Fy8w1uDhbKbL7PdK/O7aHkNOPLBLY28AEVW0gZ7P1
 WmlhChyk84Xp3/9A+aV2q/4rdtjJ1hkEGXyPTeR0TJ6OSKbs90xJA92sVnwBM3TH
 yaRiFDRFMbu39lxngYYKDcq3BCUUuSVZw9zvtIW+T38DeFT2DcNapDGSqpp3Fhbo
 QhU8iJK2TnUqbQSMCPuAa14bvowPvDIlmYBV/2aMiDEegjj2Zo1G/Y3oA2JuePwU
 FVhbYYQTBUF9Un/J5EyuejVBKv/N+8P17hzFADqnuMZ5HzfXtUz0Nv8WwLRsflYo
 5ZjNkhEqvLuTVaXtwdWh8nEsXmb1dIpQs4Z9fP3GPirOg9aN1MVIZ38qc9wBmGlk
 5V+Fk7kGqfvXMVeE91M4A+ojd06/fG7RGHW4FCmI+/jeYNt1ncPR0wEU5K5qKIC4
 qMwln0DfduKFLEE2wcX8
 =1ISP
 -----END PGP SIGNATURE-----

Merge tag 'isdn-removal' of https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground

Arnd Bergmann says:

====================
isdn: deprecate non-mISDN drivers

When isdn4linux came up in the context of another patch series, I
remembered that we had discussed removing it a while ago.

It turns out that the suggestion from Karsten Keil wa to remove I4L
in 2018 after the last public ISDN networks are shut down. This has
happened now (with a very small number of exceptions), so I guess it's
time to try again.

We currently have three ISDN stacks in the kernel: the original
isdn4linux (with the hisax driver), the newer CAPI (with four drivers),
and finally the mISDN stack (supporting roughly the same hardware as
hisax).

As far as I can tell, anyone using ISDN with mainline kernel drivers in
the past few years uses mISDN, and this is typically used for voice-only
PBX installations that don't require a public network.

The older stacks support additional features for data networks, but those
typically make no sense any more if there is no network to connect to.

My proposal for this time is to kill off isdn4linux entirely, as it seems
to have been unusable for quite a while. This code has been abandoned
for many years and it does cause problems for treewide maintenance as
it tends to do everything that we try to stop doing.
Birger Harzenetter mentioned that is is still using i4l in order to
make use of the 'divert' feature that is not part of mISDN, but has
otherwise moved on to mISDN for normal operation, like apparently
everyone else.

CAPI in turn is not quite as obsolete, but two of the drivers (avm
and hysdn) don't seem to be used at all, while another one (gigaset)
will stop being maintained as Paul Bolle is no longer able to
test it after the network gets shut down in September.
All three are now moved into drivers/staging to let others speak
up in case there are remaining users.
This leaves Bluetooth CMTP as the only remaining user of CAPI, but
Marcel Holtmann wishes to keep maintaining it.

For the discussion on version 1, see [2]
Unfortunately, Karsten Keil as the maintainer has not participated in
the discussion.

      Arnd

[1] https://patchwork.kernel.org/patch/8484861/#17900371
[2] https://listserv.isdn4linux.de/pipermail/isdn4linux/2019-April/thread.html
====================

Signed-off-by: David S. Miller <[email protected]>
This commit is contained in:
David S. Miller 2019-06-02 17:48:58 -07:00
commit 8a7e8ff8ce
216 changed files with 107 additions and 83884 deletions

View file

@ -21,59 +21,8 @@ menuconfig ISDN
if ISDN
menuconfig ISDN_I4L
tristate "Old ISDN4Linux (deprecated)"
depends on TTY
---help---
This driver allows you to use an ISDN adapter for networking
connections and as dialin/out device. The isdn-tty's have a built
in AT-compatible modem emulator. Network devices support autodial,
channel-bundling, callback and caller-authentication without having
a daemon running. A reduced T.70 protocol is supported with tty's
suitable for German BTX. On D-Channel, the protocols EDSS1
(Euro-ISDN) and 1TR6 (German style) are supported. See
<file:Documentation/isdn/README> for more information.
ISDN support in the linux kernel is moving towards a new API,
called CAPI (Common ISDN Application Programming Interface).
Therefore the old ISDN4Linux layer will eventually become obsolete.
It is still available, though, for use with adapters that are not
supported by the new CAPI subsystem yet.
source "drivers/isdn/i4l/Kconfig"
menuconfig ISDN_CAPI
tristate "CAPI 2.0 subsystem"
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
<http://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).
Select this option and the appropriate hardware driver below if
you have an ISDN adapter supported by the CAPI subsystem.
if ISDN_CAPI
source "drivers/isdn/capi/Kconfig"
source "drivers/isdn/hardware/Kconfig"
endif # ISDN_CAPI
source "drivers/isdn/gigaset/Kconfig"
source "drivers/isdn/hysdn/Kconfig"
source "drivers/isdn/mISDN/Kconfig"
config ISDN_HDLC
tristate
select CRC_CCITT
select BITREVERSE
endif # ISDN

View file

@ -3,12 +3,6 @@
# Object files in subdirectories
obj-$(CONFIG_ISDN_I4L) += i4l/
obj-$(CONFIG_ISDN_CAPI) += capi/
obj-$(CONFIG_MISDN) += mISDN/
obj-$(CONFIG_ISDN) += hardware/
obj-$(CONFIG_ISDN_DIVERSION) += divert/
obj-$(CONFIG_ISDN_DRV_HISAX) += hisax/
obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/
obj-$(CONFIG_HYSDN) += hysdn/
obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/

View file

@ -1,4 +1,22 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig ISDN_CAPI
tristate "CAPI 2.0 subsystem"
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
<http://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.
if ISDN_CAPI
config CAPI_TRACE
bool "CAPI trace support"
default y
@ -27,15 +45,6 @@ config ISDN_CAPI_MIDDLEWARE
device. If you want to use pppd with pppdcapiplugin to dial up to
your ISP, say Y here.
config ISDN_CAPI_CAPIDRV
tristate "CAPI2.0 capidrv interface support"
depends on ISDN_I4L
help
This option provides the glue code to hook up CAPI driven cards to
the legacy isdn4linux link layer. If you have a card which is
supported by a CAPI driver, but still want to use old features like
ippp interfaces or ttyI emulation, say Y/M here.
config ISDN_CAPI_CAPIDRV_VERBOSE
bool "Verbose reason code reporting"
depends on ISDN_CAPI_CAPIDRV
@ -43,3 +52,5 @@ config ISDN_CAPI_CAPIDRV_VERBOSE
If you say Y here, the capidrv interface will give verbose reasons
for disconnecting. This will increase the size of the kernel by 7 KB.
If unsure, say N.
endif

View file

@ -13,3 +13,5 @@ obj-$(CONFIG_ISDN_CAPI_CAPIDRV) += capidrv.o
kernelcapi-y := kcapi.o capiutil.o capilib.o
kernelcapi-$(CONFIG_PROC_FS) += kcapi_proc.o
ccflags-y += -I$(srctree)/$(src)/../include -I$(srctree)/$(src)/../include/uapi

File diff suppressed because it is too large Load diff

View file

@ -1,140 +0,0 @@
/* $Id: capidrv.h,v 1.2.8.2 2001/09/23 22:24:33 kai Exp $
*
* ISDN4Linux Driver, using capi20 interface (kernelcapi)
*
* Copyright 1997 by Carsten Paeth <calle@calle.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef __CAPIDRV_H__
#define __CAPIDRV_H__
/*
* LISTEN state machine
*/
#define ST_LISTEN_NONE 0 /* L-0 */
#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */
#define ST_LISTEN_ACTIVE 2 /* L-1 */
#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */
#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1
L-1 -> L-1.1 */
#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0
L-1.1 -> L-1 */
#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0
L-1.1 -> L-0 */
#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1
L-1.1 -> L.1 */
/*
* per plci state machine
*/
#define ST_PLCI_NONE 0 /* P-0 */
#define ST_PLCI_OUTGOING 1 /* P-0.1 */
#define ST_PLCI_ALLOCATED 2 /* P-1 */
#define ST_PLCI_ACTIVE 3 /* P-ACT */
#define ST_PLCI_INCOMING 4 /* P-2 */
#define ST_PLCI_FACILITY_IND 5 /* P-3 */
#define ST_PLCI_ACCEPTING 6 /* P-4 */
#define ST_PLCI_DISCONNECTING 7 /* P-5 */
#define ST_PLCI_DISCONNECTED 8 /* P-6 */
#define ST_PLCI_RESUMEING 9 /* P-0.Res */
#define ST_PLCI_RESUME 10 /* P-Res */
#define ST_PLCI_HELD 11 /* P-HELD */
#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1
*/
#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0
*/
#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1
*/
#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1
*/
#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2
*/
#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT
*/
#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5
P-3 -> P-5
*/
#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5
P-2 -> P-5
P-3 -> P-5
P-4 -> P-5
P-ACT -> P-5
P-Res -> P-5 (*)
P-HELD -> P-5 (*)
*/
#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6
P-2 -> P-6
P-3 -> P-6
P-4 -> P-6
P-5 -> P-6
P-ACT -> P-6
P-Res -> P-6 (*)
P-HELD -> P-6 (*)
*/
#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5
P-1 -> P-5
P-ACT -> P-5
P-2 -> P-5
P-3 -> P-5
P-4 -> P-5
*/
#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0
*/
#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0
*/
#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res
*/
#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res
*/
#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0
*/
#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT
*/
#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD
*/
#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT
*/
#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5
*/
#define EV_PLCI_CD_IND 20 /* P-2 -> P-5
*/
/*
* per ncci state machine
*/
#define ST_NCCI_PREVIOUS -1
#define ST_NCCI_NONE 0 /* N-0 */
#define ST_NCCI_OUTGOING 1 /* N-0.1 */
#define ST_NCCI_INCOMING 2 /* N-1 */
#define ST_NCCI_ALLOCATED 3 /* N-2 */
#define ST_NCCI_ACTIVE 4 /* N-ACT */
#define ST_NCCI_RESETING 5 /* N-3 */
#define ST_NCCI_DISCONNECTING 6 /* N-4 */
#define ST_NCCI_DISCONNECTED 7 /* N-5 */
#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */
#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */
#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */
#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */
#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */
#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */
#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */
#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */
#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */
#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */
#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */
#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4
N-2 -> N-4
N-3 -> N-4
N-ACT -> N-4 */
#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */
#endif /* __CAPIDRV_H__ */

View file

@ -1,10 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
# Makefile for the dss1_divert ISDN module
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o
# Multipart objects.
dss1_divert-y := isdn_divert.o divert_procfs.o divert_init.o

View file

@ -1,82 +0,0 @@
/* $Id divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $
*
* Module init for DSS1 diversion services for i4l.
*
* Copyright 1999 by Werner Cornelius (werner@isdn4linux.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/init.h>
#include <linux/kernel.h>
#include "isdn_divert.h"
MODULE_DESCRIPTION("ISDN4Linux: Call diversion support");
MODULE_AUTHOR("Werner Cornelius");
MODULE_LICENSE("GPL");
/****************************************/
/* structure containing interface to hl */
/****************************************/
isdn_divert_if divert_if = {
DIVERT_IF_MAGIC, /* magic value */
DIVERT_CMD_REG, /* register cmd */
ll_callback, /* callback routine from ll */
NULL, /* command still not specified */
NULL, /* drv_to_name */
NULL, /* name_to_drv */
};
/*************************/
/* Module interface code */
/* no cmd line parms */
/*************************/
static int __init divert_init(void)
{
int i;
if (divert_dev_init()) {
printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
return (-EIO);
}
if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
divert_dev_deinit();
printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n", i);
return (-EIO);
}
printk(KERN_INFO "dss1_divert module successfully installed\n");
return (0);
}
/**********************/
/* Module deinit code */
/**********************/
static void __exit divert_exit(void)
{
unsigned long flags;
int i;
spin_lock_irqsave(&divert_lock, flags);
divert_if.cmd = DIVERT_CMD_REL; /* release */
if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i);
spin_unlock_irqrestore(&divert_lock, flags);
return;
}
if (divert_dev_deinit()) {
printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
spin_unlock_irqrestore(&divert_lock, flags);
return;
}
spin_unlock_irqrestore(&divert_lock, flags);
deleterule(-1); /* delete all rules and free mem */
deleteprocs();
printk(KERN_INFO "dss1_divert module successfully removed \n");
}
module_init(divert_init);
module_exit(divert_exit);

View file

@ -1,336 +0,0 @@
/* $Id: divert_procfs.c,v 1.11.6.2 2001/09/23 22:24:36 kai Exp $
*
* Filesystem handling for the diversion supplementary services.
*
* Copyright 1998 by Werner Cornelius (werner@isdn4linux.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/poll.h>
#include <linux/slab.h>
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#else
#include <linux/fs.h>
#endif
#include <linux/sched.h>
#include <linux/isdnif.h>
#include <net/net_namespace.h>
#include <linux/mutex.h>
#include "isdn_divert.h"
/*********************************/
/* Variables for interface queue */
/*********************************/
ulong if_used = 0; /* number of interface users */
static DEFINE_MUTEX(isdn_divert_mutex);
static struct divert_info *divert_info_head = NULL; /* head of queue */
static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */
static DEFINE_SPINLOCK(divert_info_lock);/* lock for queue */
static wait_queue_head_t rd_queue;
/*********************************/
/* put an info buffer into queue */
/*********************************/
void
put_info_buffer(char *cp)
{
struct divert_info *ib;
unsigned long flags;
if (if_used <= 0)
return;
if (!cp)
return;
if (!*cp)
return;
if (!(ib = kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC)))
return; /* no memory */
strcpy(ib->info_start, cp); /* set output string */
ib->next = NULL;
spin_lock_irqsave(&divert_info_lock, flags);
ib->usage_cnt = if_used;
if (!divert_info_head)
divert_info_head = ib; /* new head */
else
divert_info_tail->next = ib; /* follows existing messages */
divert_info_tail = ib; /* new tail */
/* delete old entrys */
while (divert_info_head->next) {
if ((divert_info_head->usage_cnt <= 0) &&
(divert_info_head->next->usage_cnt <= 0)) {
ib = divert_info_head;
divert_info_head = divert_info_head->next;
kfree(ib);
} else
break;
} /* divert_info_head->next */
spin_unlock_irqrestore(&divert_info_lock, flags);
wake_up_interruptible(&(rd_queue));
} /* put_info_buffer */
#ifdef CONFIG_PROC_FS
/**********************************/
/* deflection device read routine */
/**********************************/
static ssize_t
isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t *off)
{
struct divert_info *inf;
int len;
if (!(inf = *((struct divert_info **) file->private_data))) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
wait_event_interruptible(rd_queue, (inf =
*((struct divert_info **) file->private_data)));
}
if (!inf)
return (0);
inf->usage_cnt--; /* new usage count */
file->private_data = &inf->next; /* next structure */
if ((len = strlen(inf->info_start)) <= count) {
if (copy_to_user(buf, inf->info_start, len))
return -EFAULT;
*off += len;
return (len);
}
return (0);
} /* isdn_divert_read */
/**********************************/
/* deflection device write routine */
/**********************************/
static ssize_t
isdn_divert_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
{
return (-ENODEV);
} /* isdn_divert_write */
/***************************************/
/* select routines for various kernels */
/***************************************/
static __poll_t
isdn_divert_poll(struct file *file, poll_table *wait)
{
__poll_t mask = 0;
poll_wait(file, &(rd_queue), wait);
/* mask = EPOLLOUT | EPOLLWRNORM; */
if (*((struct divert_info **) file->private_data)) {
mask |= EPOLLIN | EPOLLRDNORM;
}
return mask;
} /* isdn_divert_poll */
/****************/
/* Open routine */
/****************/
static int
isdn_divert_open(struct inode *ino, struct file *filep)
{
unsigned long flags;
spin_lock_irqsave(&divert_info_lock, flags);
if_used++;
if (divert_info_head)
filep->private_data = &(divert_info_tail->next);
else
filep->private_data = &divert_info_head;
spin_unlock_irqrestore(&divert_info_lock, flags);
/* start_divert(); */
return nonseekable_open(ino, filep);
} /* isdn_divert_open */
/*******************/
/* close routine */
/*******************/
static int
isdn_divert_close(struct inode *ino, struct file *filep)
{
struct divert_info *inf;
unsigned long flags;
spin_lock_irqsave(&divert_info_lock, flags);
if_used--;
inf = *((struct divert_info **) filep->private_data);
while (inf) {
inf->usage_cnt--;
inf = inf->next;
}
if (if_used <= 0)
while (divert_info_head) {
inf = divert_info_head;
divert_info_head = divert_info_head->next;
kfree(inf);
}
spin_unlock_irqrestore(&divert_info_lock, flags);
return (0);
} /* isdn_divert_close */
/*********/
/* IOCTL */
/*********/
static int isdn_divert_ioctl_unlocked(struct file *file, uint cmd, ulong arg)
{
divert_ioctl dioctl;
int i;
unsigned long flags;
divert_rule *rulep;
char *cp;
if (copy_from_user(&dioctl, (void __user *) arg, sizeof(dioctl)))
return -EFAULT;
switch (cmd) {
case IIOCGETVER:
dioctl.drv_version = DIVERT_IIOC_VERSION; /* set version */
break;
case IIOCGETDRV:
if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0)
return (-EINVAL);
break;
case IIOCGETNAM:
cp = divert_if.drv_to_name(dioctl.getid.drvid);
if (!cp)
return (-EINVAL);
if (!*cp)
return (-EINVAL);
strcpy(dioctl.getid.drvnam, cp);
break;
case IIOCGETRULE:
if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
return (-EINVAL);
dioctl.getsetrule.rule = *rulep; /* copy data */
break;
case IIOCMODRULE:
if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
return (-EINVAL);
spin_lock_irqsave(&divert_lock, flags);
*rulep = dioctl.getsetrule.rule; /* copy data */
spin_unlock_irqrestore(&divert_lock, flags);
return (0); /* no copy required */
break;
case IIOCINSRULE:
return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule));
break;
case IIOCDELRULE:
return (deleterule(dioctl.getsetrule.ruleidx));
break;
case IIOCDODFACT:
return (deflect_extern_action(dioctl.fwd_ctrl.subcmd,
dioctl.fwd_ctrl.callid,
dioctl.fwd_ctrl.to_nr));
case IIOCDOCFACT:
case IIOCDOCFDIS:
case IIOCDOCFINT:
if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid))
return (-EINVAL); /* invalid driver */
if (strnlen(dioctl.cf_ctrl.msn, sizeof(dioctl.cf_ctrl.msn)) ==
sizeof(dioctl.cf_ctrl.msn))
return -EINVAL;
if (strnlen(dioctl.cf_ctrl.fwd_nr, sizeof(dioctl.cf_ctrl.fwd_nr)) ==
sizeof(dioctl.cf_ctrl.fwd_nr))
return -EINVAL;
if ((i = cf_command(dioctl.cf_ctrl.drvid,
(cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2,
dioctl.cf_ctrl.cfproc,
dioctl.cf_ctrl.msn,
dioctl.cf_ctrl.service,
dioctl.cf_ctrl.fwd_nr,
&dioctl.cf_ctrl.procid)))
return (i);
break;
default:
return (-EINVAL);
} /* switch cmd */
return copy_to_user((void __user *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0;
} /* isdn_divert_ioctl */
static long isdn_divert_ioctl(struct file *file, uint cmd, ulong arg)
{
long ret;
mutex_lock(&isdn_divert_mutex);
ret = isdn_divert_ioctl_unlocked(file, cmd, arg);
mutex_unlock(&isdn_divert_mutex);
return ret;
}
static const struct file_operations isdn_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = isdn_divert_read,
.write = isdn_divert_write,
.poll = isdn_divert_poll,
.unlocked_ioctl = isdn_divert_ioctl,
.open = isdn_divert_open,
.release = isdn_divert_close,
};
/****************************/
/* isdn subdir in /proc/net */
/****************************/
static struct proc_dir_entry *isdn_proc_entry = NULL;
static struct proc_dir_entry *isdn_divert_entry = NULL;
#endif /* CONFIG_PROC_FS */
/***************************************************************************/
/* divert_dev_init must be called before the proc filesystem may be used */
/***************************************************************************/
int
divert_dev_init(void)
{
init_waitqueue_head(&rd_queue);
#ifdef CONFIG_PROC_FS
isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net);
if (!isdn_proc_entry)
return (-1);
isdn_divert_entry = proc_create("divert", S_IFREG | S_IRUGO,
isdn_proc_entry, &isdn_fops);
if (!isdn_divert_entry) {
remove_proc_entry("isdn", init_net.proc_net);
return (-1);
}
#endif /* CONFIG_PROC_FS */
return (0);
} /* divert_dev_init */
/***************************************************************************/
/* divert_dev_deinit must be called before leaving isdn when included as */
/* a module. */
/***************************************************************************/
int
divert_dev_deinit(void)
{
#ifdef CONFIG_PROC_FS
remove_proc_entry("divert", isdn_proc_entry);
remove_proc_entry("isdn", init_net.proc_net);
#endif /* CONFIG_PROC_FS */
return (0);
} /* divert_dev_deinit */

View file

@ -1,846 +0,0 @@
/* $Id: isdn_divert.c,v 1.6.6.3 2001/09/23 22:24:36 kai Exp $
*
* DSS1 main diversion supplementary handling for i4l.
*
* Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include "isdn_divert.h"
/**********************************/
/* structure keeping calling info */
/**********************************/
struct call_struc {
isdn_ctrl ics; /* delivered setup + driver parameters */
ulong divert_id; /* Id delivered to user */
unsigned char akt_state; /* actual state */
char deflect_dest[35]; /* deflection destination */
struct timer_list timer; /* timer control structure */
char info[90]; /* device info output */
struct call_struc *next; /* pointer to next entry */
struct call_struc *prev;
};
/********************************************/
/* structure keeping deflection table entry */
/********************************************/
struct deflect_struc {
struct deflect_struc *next, *prev;
divert_rule rule; /* used rule */
};
/*****************************************/
/* variables for main diversion services */
/*****************************************/
/* diversion/deflection processes */
static struct call_struc *divert_head = NULL; /* head of remembered entrys */
static ulong next_id = 1; /* next info id */
static struct deflect_struc *table_head = NULL;
static struct deflect_struc *table_tail = NULL;
static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */
DEFINE_SPINLOCK(divert_lock);
/***************************/
/* timer callback function */
/***************************/
static void deflect_timer_expire(struct timer_list *t)
{
unsigned long flags;
struct call_struc *cs = from_timer(cs, t, timer);
spin_lock_irqsave(&divert_lock, flags);
del_timer(&cs->timer); /* delete active timer */
spin_unlock_irqrestore(&divert_lock, flags);
switch (cs->akt_state) {
case DEFLECT_PROCEED:
cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
divert_if.ll_cmd(&cs->ics);
spin_lock_irqsave(&divert_lock, flags);
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
spin_unlock_irqrestore(&divert_lock, flags);
break;
case DEFLECT_ALERT:
cs->ics.command = ISDN_CMD_REDIR; /* protocol */
strlcpy(cs->ics.parm.setup.phone, cs->deflect_dest, sizeof(cs->ics.parm.setup.phone));
strcpy(cs->ics.parm.setup.eazmsn, "Testtext delayed");
divert_if.ll_cmd(&cs->ics);
spin_lock_irqsave(&divert_lock, flags);
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
spin_unlock_irqrestore(&divert_lock, flags);
break;
case DEFLECT_AUTODEL:
default:
spin_lock_irqsave(&divert_lock, flags);
if (cs->prev)
cs->prev->next = cs->next; /* forward link */
else
divert_head = cs->next;
if (cs->next)
cs->next->prev = cs->prev; /* back link */
spin_unlock_irqrestore(&divert_lock, flags);
kfree(cs);
return;
} /* switch */
} /* deflect_timer_func */
/*****************************************/
/* handle call forwarding de/activations */
/* 0 = deact, 1 = act, 2 = interrogate */
/*****************************************/
int cf_command(int drvid, int mode,
u_char proc, char *msn,
u_char service, char *fwd_nr, ulong *procid)
{
unsigned long flags;
int retval, msnlen;
int fwd_len;
char *p, *ielenp, tmp[60];
struct call_struc *cs;
if (strchr(msn, '.')) return (-EINVAL); /* subaddress not allowed in msn */
if ((proc & 0x7F) > 2) return (-EINVAL);
proc &= 3;
p = tmp;
*p++ = 0x30; /* enumeration */
ielenp = p++; /* remember total length position */
*p++ = 0xa; /* proc tag */
*p++ = 1; /* length */
*p++ = proc & 0x7F; /* procedure to de/activate/interrogate */
*p++ = 0xa; /* service tag */
*p++ = 1; /* length */
*p++ = service; /* service to handle */
if (mode == 1) {
if (!*fwd_nr) return (-EINVAL); /* destination missing */
if (strchr(fwd_nr, '.')) return (-EINVAL); /* subaddress not allowed */
fwd_len = strlen(fwd_nr);
*p++ = 0x30; /* number enumeration */
*p++ = fwd_len + 2; /* complete forward to len */
*p++ = 0x80; /* fwd to nr */
*p++ = fwd_len; /* length of number */
strcpy(p, fwd_nr); /* copy number */
p += fwd_len; /* pointer beyond fwd */
} /* activate */
msnlen = strlen(msn);
*p++ = 0x80; /* msn number */
if (msnlen > 1) {
*p++ = msnlen; /* length */
strcpy(p, msn);
p += msnlen;
} else
*p++ = 0;
*ielenp = p - ielenp - 1; /* set total IE length */
/* allocate mem for information struct */
if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
return (-ENOMEM); /* no memory */
timer_setup(&cs->timer, deflect_timer_expire, 0);
cs->info[0] = '\0';
cs->ics.driver = drvid;
cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */
cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */
cs->ics.parm.dss1_io.proc = (mode == 1) ? 7 : (mode == 2) ? 11 : 8; /* operation */
cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */
cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */
cs->ics.parm.dss1_io.data = tmp; /* start of buffer */
spin_lock_irqsave(&divert_lock, flags);
cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */
spin_unlock_irqrestore(&divert_lock, flags);
*procid = cs->ics.parm.dss1_io.ll_id;
sprintf(cs->info, "%d 0x%lx %s%s 0 %s %02x %d%s%s\n",
(!mode) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT,
cs->ics.parm.dss1_io.ll_id,
(mode != 2) ? "" : "0 ",
divert_if.drv_to_name(cs->ics.driver),
msn,
service & 0xFF,
proc,
(mode != 1) ? "" : " 0 ",
(mode != 1) ? "" : fwd_nr);
retval = divert_if.ll_cmd(&cs->ics); /* execute command */
if (!retval) {
cs->prev = NULL;
spin_lock_irqsave(&divert_lock, flags);
cs->next = divert_head;
divert_head = cs;
spin_unlock_irqrestore(&divert_lock, flags);
} else
kfree(cs);
return (retval);
} /* cf_command */
/****************************************/
/* handle a external deflection command */
/****************************************/
int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
{
struct call_struc *cs;
isdn_ctrl ic;
unsigned long flags;
int i;
if ((cmd & 0x7F) > 2) return (-EINVAL); /* invalid command */
cs = divert_head; /* start of parameter list */
while (cs) {
if (cs->divert_id == callid) break; /* found */
cs = cs->next;
} /* search entry */
if (!cs) return (-EINVAL); /* invalid callid */
ic.driver = cs->ics.driver;
ic.arg = cs->ics.arg;
i = -EINVAL;
if (cs->akt_state == DEFLECT_AUTODEL) return (i); /* no valid call */
switch (cmd & 0x7F) {
case 0: /* hangup */
del_timer(&cs->timer);
ic.command = ISDN_CMD_HANGUP;
i = divert_if.ll_cmd(&ic);
spin_lock_irqsave(&divert_lock, flags);
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
spin_unlock_irqrestore(&divert_lock, flags);
break;
case 1: /* alert */
if (cs->akt_state == DEFLECT_ALERT) return (0);
cmd &= 0x7F; /* never wait */
del_timer(&cs->timer);
ic.command = ISDN_CMD_ALERT;
if ((i = divert_if.ll_cmd(&ic))) {
spin_lock_irqsave(&divert_lock, flags);
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
spin_unlock_irqrestore(&divert_lock, flags);
} else
cs->akt_state = DEFLECT_ALERT;
break;
case 2: /* redir */
del_timer(&cs->timer);
strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone));
strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
ic.command = ISDN_CMD_REDIR;
if ((i = divert_if.ll_cmd(&ic))) {
spin_lock_irqsave(&divert_lock, flags);
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
spin_unlock_irqrestore(&divert_lock, flags);
} else
cs->akt_state = DEFLECT_ALERT;
break;
} /* switch */
return (i);
} /* deflect_extern_action */
/********************************/
/* insert a new rule before idx */
/********************************/
int insertrule(int idx, divert_rule *newrule)
{
struct deflect_struc *ds, *ds1 = NULL;
unsigned long flags;
if (!(ds = kmalloc(sizeof(struct deflect_struc), GFP_KERNEL)))
return (-ENOMEM); /* no memory */
ds->rule = *newrule; /* set rule */
spin_lock_irqsave(&divert_lock, flags);
if (idx >= 0) {
ds1 = table_head;
while ((ds1) && (idx > 0))
{ idx--;
ds1 = ds1->next;
}
if (!ds1) idx = -1;
}
if (idx < 0) {
ds->prev = table_tail; /* previous entry */
ds->next = NULL; /* end of chain */
if (ds->prev)
ds->prev->next = ds; /* last forward */
else
table_head = ds; /* is first entry */
table_tail = ds; /* end of queue */
} else {
ds->next = ds1; /* next entry */
ds->prev = ds1->prev; /* prev entry */
ds1->prev = ds; /* backward chain old element */
if (!ds->prev)
table_head = ds; /* first element */
}
spin_unlock_irqrestore(&divert_lock, flags);
return (0);
} /* insertrule */
/***********************************/
/* delete the rule at position idx */
/***********************************/
int deleterule(int idx)
{
struct deflect_struc *ds, *ds1;
unsigned long flags;
if (idx < 0) {
spin_lock_irqsave(&divert_lock, flags);
ds = table_head;
table_head = NULL;
table_tail = NULL;
spin_unlock_irqrestore(&divert_lock, flags);
while (ds) {
ds1 = ds;
ds = ds->next;
kfree(ds1);
}
return (0);
}
spin_lock_irqsave(&divert_lock, flags);
ds = table_head;
while ((ds) && (idx > 0)) {
idx--;
ds = ds->next;
}
if (!ds) {
spin_unlock_irqrestore(&divert_lock, flags);
return (-EINVAL);
}
if (ds->next)
ds->next->prev = ds->prev; /* backward chain */
else
table_tail = ds->prev; /* end of chain */
if (ds->prev)
ds->prev->next = ds->next; /* forward chain */
else
table_head = ds->next; /* start of chain */
spin_unlock_irqrestore(&divert_lock, flags);
kfree(ds);
return (0);
} /* deleterule */
/*******************************************/
/* get a pointer to a specific rule number */
/*******************************************/
divert_rule *getruleptr(int idx)
{
struct deflect_struc *ds = table_head;
if (idx < 0) return (NULL);
while ((ds) && (idx >= 0)) {
if (!(idx--)) {
return (&ds->rule);
break;
}
ds = ds->next;
}
return (NULL);
} /* getruleptr */
/*************************************************/
/* called from common module on an incoming call */
/*************************************************/
static int isdn_divert_icall(isdn_ctrl *ic)
{
int retval = 0;
unsigned long flags;
struct call_struc *cs = NULL;
struct deflect_struc *dv;
char *p, *p1;
u_char accept;
/* first check the internal deflection table */
for (dv = table_head; dv; dv = dv->next) {
/* scan table */
if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
continue; /* call option check */
if (!(dv->rule.drvid & (1L << ic->driver)))
continue; /* driver not matching */
if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1))
continue; /* si1 not matching */
if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2))
continue; /* si2 not matching */
p = dv->rule.my_msn;
p1 = ic->parm.setup.eazmsn;
accept = 0;
while (*p) {
/* complete compare */
if (*p == '-') {
accept = 1; /* call accepted */
break;
}
if (*p++ != *p1++)
break; /* not accepted */
if ((!*p) && (!*p1))
accept = 1;
} /* complete compare */
if (!accept) continue; /* not accepted */
if ((strcmp(dv->rule.caller, "0")) ||
(ic->parm.setup.phone[0])) {
p = dv->rule.caller;
p1 = ic->parm.setup.phone;
accept = 0;
while (*p) {
/* complete compare */
if (*p == '-') {
accept = 1; /* call accepted */
break;
}
if (*p++ != *p1++)
break; /* not accepted */
if ((!*p) && (!*p1))
accept = 1;
} /* complete compare */
if (!accept) continue; /* not accepted */
}
switch (dv->rule.action) {
case DEFLECT_IGNORE:
return 0;
case DEFLECT_ALERT:
case DEFLECT_PROCEED:
case DEFLECT_REPORT:
case DEFLECT_REJECT:
if (dv->rule.action == DEFLECT_PROCEED)
if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
return (0); /* no external deflection needed */
if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
return (0); /* no memory */
timer_setup(&cs->timer, deflect_timer_expire, 0);
cs->info[0] = '\0';
cs->ics = *ic; /* copy incoming data */
if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone, "0");
if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn, "0");
cs->ics.parm.setup.screen = dv->rule.screen;
if (dv->rule.waittime)
cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
else if (dv->rule.action == DEFLECT_PROCEED)
cs->timer.expires = jiffies + (HZ * extern_wait_max);
else
cs->timer.expires = 0;
cs->akt_state = dv->rule.action;
spin_lock_irqsave(&divert_lock, flags);
cs->divert_id = next_id++; /* new sequence number */
spin_unlock_irqrestore(&divert_lock, flags);
cs->prev = NULL;
if (cs->akt_state == DEFLECT_ALERT) {
strcpy(cs->deflect_dest, dv->rule.to_nr);
if (!cs->timer.expires) {
strcpy(ic->parm.setup.eazmsn,
"Testtext direct");
ic->parm.setup.screen = dv->rule.screen;
strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone));
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
retval = 5;
} else
retval = 1; /* alerting */
} else {
cs->deflect_dest[0] = '\0';
retval = 4; /* only proceed */
}
snprintf(cs->info, sizeof(cs->info),
"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
cs->akt_state,
cs->divert_id,
divert_if.drv_to_name(cs->ics.driver),
(ic->command == ISDN_STAT_ICALLW) ? "1" : "0",
cs->ics.parm.setup.phone,
cs->ics.parm.setup.eazmsn,
cs->ics.parm.setup.si1,
cs->ics.parm.setup.si2,
cs->ics.parm.setup.screen,
dv->rule.waittime,
cs->deflect_dest);
if ((dv->rule.action == DEFLECT_REPORT) ||
(dv->rule.action == DEFLECT_REJECT)) {
put_info_buffer(cs->info);
kfree(cs); /* remove */
return ((dv->rule.action == DEFLECT_REPORT) ? 0 : 2); /* nothing to do */
}
break;
default:
return 0; /* ignore call */
} /* switch action */
break; /* will break the 'for' looping */
} /* scan_table */
if (cs) {
cs->prev = NULL;
spin_lock_irqsave(&divert_lock, flags);
cs->next = divert_head;
divert_head = cs;
if (cs->timer.expires) add_timer(&cs->timer);
spin_unlock_irqrestore(&divert_lock, flags);
put_info_buffer(cs->info);
return (retval);
} else
return (0);
} /* isdn_divert_icall */
void deleteprocs(void)
{
struct call_struc *cs, *cs1;
unsigned long flags;
spin_lock_irqsave(&divert_lock, flags);
cs = divert_head;
divert_head = NULL;
while (cs) {
del_timer(&cs->timer);
cs1 = cs;
cs = cs->next;
kfree(cs1);
}
spin_unlock_irqrestore(&divert_lock, flags);
} /* deleteprocs */
/****************************************************/
/* put a address including address type into buffer */
/****************************************************/
static int put_address(char *st, u_char *p, int len)
{
u_char retval = 0;
u_char adr_typ = 0; /* network standard */
if (len < 2) return (retval);
if (*p == 0xA1) {
retval = *(++p) + 2; /* total length */
if (retval > len) return (0); /* too short */
len = retval - 2; /* remaining length */
if (len < 3) return (0);
if ((*(++p) != 0x0A) || (*(++p) != 1)) return (0);
adr_typ = *(++p);
len -= 3;
p++;
if (len < 2) return (0);
if (*p++ != 0x12) return (0);
if (*p > len) return (0); /* check number length */
len = *p++;
} else if (*p == 0x80) {
retval = *(++p) + 2; /* total length */
if (retval > len) return (0);
len = retval - 2;
p++;
} else
return (0); /* invalid address information */
sprintf(st, "%d ", adr_typ);
st += strlen(st);
if (!len)
*st++ = '-';
else
while (len--)
*st++ = *p++;
*st = '\0';
return (retval);
} /* put_address */
/*************************************/
/* report a successful interrogation */
/*************************************/
static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
{
char *src = ic->parm.dss1_io.data;
int restlen = ic->parm.dss1_io.datalen;
int cnt = 1;
u_char n, n1;
char st[90], *p, *stp;
if (restlen < 2) return (-100); /* frame too short */
if (*src++ != 0x30) return (-101);
if ((n = *src++) > 0x81) return (-102); /* invalid length field */
restlen -= 2; /* remaining bytes */
if (n == 0x80) {
if (restlen < 2) return (-103);
if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-104);
restlen -= 2;
} else if (n == 0x81) {
n = *src++;
restlen--;
if (n > restlen) return (-105);
restlen = n;
} else if (n > restlen)
return (-106);
else
restlen = n; /* standard format */
if (restlen < 3) return (-107); /* no procedure */
if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return (-108);
restlen -= 3;
if (restlen < 2) return (-109); /* list missing */
if (*src == 0x31) {
src++;
if ((n = *src++) > 0x81) return (-110); /* invalid length field */
restlen -= 2; /* remaining bytes */
if (n == 0x80) {
if (restlen < 2) return (-111);
if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-112);
restlen -= 2;
} else if (n == 0x81) {
n = *src++;
restlen--;
if (n > restlen) return (-113);
restlen = n;
} else if (n > restlen)
return (-114);
else
restlen = n; /* standard format */
} /* result list header */
while (restlen >= 2) {
stp = st;
sprintf(stp, "%d 0x%lx %d %s ", DIVERT_REPORT, ic->parm.dss1_io.ll_id,
cnt++, divert_if.drv_to_name(ic->driver));
stp += strlen(stp);
if (*src++ != 0x30) return (-115); /* invalid enum */
n = *src++;
restlen -= 2;
if (n > restlen) return (-116); /* enum length wrong */
restlen -= n;
p = src; /* one entry */
src += n;
if (!(n1 = put_address(stp, p, n & 0xFF))) continue;
stp += strlen(stp);
p += n1;
n -= n1;
if (n < 6) continue; /* no service and proc */
if ((*p++ != 0x0A) || (*p++ != 1)) continue;
sprintf(stp, " 0x%02x ", (*p++) & 0xFF);
stp += strlen(stp);
if ((*p++ != 0x0A) || (*p++ != 1)) continue;
sprintf(stp, "%d ", (*p++) & 0xFF);
stp += strlen(stp);
n -= 6;
if (n > 2) {
if (*p++ != 0x30) continue;
if (*p > (n - 2)) continue;
n = *p++;
if (!(n1 = put_address(stp, p, n & 0xFF))) continue;
stp += strlen(stp);
}
sprintf(stp, "\n");
put_info_buffer(st);
} /* while restlen */
if (restlen) return (-117);
return (0);
} /* interrogate_success */
/*********************************************/
/* callback for protocol specific extensions */
/*********************************************/
static int prot_stat_callback(isdn_ctrl *ic)
{
struct call_struc *cs, *cs1;
int i;
unsigned long flags;
cs = divert_head; /* start of list */
cs1 = NULL;
while (cs) {
if (ic->driver == cs->ics.driver) {
switch (cs->ics.arg) {
case DSS1_CMD_INVOKE:
if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
(cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id)) {
switch (ic->arg) {
case DSS1_STAT_INVOKE_ERR:
sprintf(cs->info, "128 0x%lx 0x%x\n",
ic->parm.dss1_io.ll_id,
ic->parm.dss1_io.timeout);
put_info_buffer(cs->info);
break;
case DSS1_STAT_INVOKE_RES:
switch (cs->ics.parm.dss1_io.proc) {
case 7:
case 8:
put_info_buffer(cs->info);
break;
case 11:
i = interrogate_success(ic, cs);
if (i)
sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT,
ic->parm.dss1_io.ll_id, i);
put_info_buffer(cs->info);
break;
default:
printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc);
break;
}
break;
default:
printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg);
break;
}
cs1 = cs; /* remember structure */
cs = NULL;
continue; /* abort search */
} /* id found */
break;
case DSS1_CMD_INVOKE_ABORT:
printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
break;
default:
printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n", cs->ics.arg);
break;
} /* switch ics.arg */
cs = cs->next;
} /* driver ok */
}
if (!cs1) {
printk(KERN_WARNING "dss1_divert unhandled process\n");
return (0);
}
if (cs1->ics.driver == -1) {
spin_lock_irqsave(&divert_lock, flags);
del_timer(&cs1->timer);
if (cs1->prev)
cs1->prev->next = cs1->next; /* forward link */
else
divert_head = cs1->next;
if (cs1->next)
cs1->next->prev = cs1->prev; /* back link */
spin_unlock_irqrestore(&divert_lock, flags);
kfree(cs1);
}
return (0);
} /* prot_stat_callback */
/***************************/
/* status callback from HL */
/***************************/
static int isdn_divert_stat_callback(isdn_ctrl *ic)
{
struct call_struc *cs, *cs1;
unsigned long flags;
int retval;
retval = -1;
cs = divert_head; /* start of list */
while (cs) {
if ((ic->driver == cs->ics.driver) &&
(ic->arg == cs->ics.arg)) {
switch (ic->command) {
case ISDN_STAT_DHUP:
sprintf(cs->info, "129 0x%lx\n", cs->divert_id);
del_timer(&cs->timer);
cs->ics.driver = -1;
break;
case ISDN_STAT_CAUSE:
sprintf(cs->info, "130 0x%lx %s\n", cs->divert_id, ic->parm.num);
break;
case ISDN_STAT_REDIR:
sprintf(cs->info, "131 0x%lx\n", cs->divert_id);
del_timer(&cs->timer);
cs->ics.driver = -1;
break;
default:
sprintf(cs->info, "999 0x%lx 0x%x\n", cs->divert_id, (int)(ic->command));
break;
}
put_info_buffer(cs->info);
retval = 0;
}
cs1 = cs;
cs = cs->next;
if (cs1->ics.driver == -1) {
spin_lock_irqsave(&divert_lock, flags);
if (cs1->prev)
cs1->prev->next = cs1->next; /* forward link */
else
divert_head = cs1->next;
if (cs1->next)
cs1->next->prev = cs1->prev; /* back link */
spin_unlock_irqrestore(&divert_lock, flags);
kfree(cs1);
}
}
return (retval); /* not found */
} /* isdn_divert_stat_callback */
/********************/
/* callback from ll */
/********************/
int ll_callback(isdn_ctrl *ic)
{
switch (ic->command) {
case ISDN_STAT_ICALL:
case ISDN_STAT_ICALLW:
return (isdn_divert_icall(ic));
break;
case ISDN_STAT_PROT:
if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO) {
if (ic->arg != DSS1_STAT_INVOKE_BRD)
return (prot_stat_callback(ic));
else
return (0); /* DSS1 invoke broadcast */
} else
return (-1); /* protocol not euro */
default:
return (isdn_divert_stat_callback(ic));
}
} /* ll_callback */

View file

@ -1,132 +0,0 @@
/* $Id: isdn_divert.h,v 1.5.6.1 2001/09/23 22:24:36 kai Exp $
*
* Header for the diversion supplementary ioctl interface.
*
* Copyright 1998 by Werner Cornelius (werner@ikt.de)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/ioctl.h>
#include <linux/types.h>
/******************************************/
/* IOCTL codes for interface to user prog */
/******************************************/
#define DIVERT_IIOC_VERSION 0x01 /* actual version */
#define IIOCGETVER _IO('I', 1) /* get version of interface */
#define IIOCGETDRV _IO('I', 2) /* get driver number */
#define IIOCGETNAM _IO('I', 3) /* get driver name */
#define IIOCGETRULE _IO('I', 4) /* read one rule */
#define IIOCMODRULE _IO('I', 5) /* modify/replace a rule */
#define IIOCINSRULE _IO('I', 6) /* insert/append one rule */
#define IIOCDELRULE _IO('I', 7) /* delete a rule */
#define IIOCDODFACT _IO('I', 8) /* hangup/reject/alert/immediately deflect a call */
#define IIOCDOCFACT _IO('I', 9) /* activate control forwarding in PBX */
#define IIOCDOCFDIS _IO('I', 10) /* deactivate control forwarding in PBX */
#define IIOCDOCFINT _IO('I', 11) /* interrogate control forwarding in PBX */
/*************************************/
/* states reported through interface */
/*************************************/
#define DEFLECT_IGNORE 0 /* ignore incoming call */
#define DEFLECT_REPORT 1 /* only report */
#define DEFLECT_PROCEED 2 /* deflect when externally triggered */
#define DEFLECT_ALERT 3 /* alert and deflect after delay */
#define DEFLECT_REJECT 4 /* reject immediately */
#define DIVERT_ACTIVATE 5 /* diversion activate */
#define DIVERT_DEACTIVATE 6 /* diversion deactivate */
#define DIVERT_REPORT 7 /* interrogation result */
#define DEFLECT_AUTODEL 255 /* only for internal use */
#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */
typedef struct {
ulong drvid; /* driver ids, bit mapped */
char my_msn[35]; /* desired msn, subaddr allowed */
char caller[35]; /* caller id, partial string with * + subaddr allowed */
char to_nr[35]; /* deflected to number incl. subaddress */
u_char si1, si2; /* service indicators, si1=bitmask, si1+2 0 = all */
u_char screen; /* screening: 0 = no info, 1 = info, 2 = nfo with nr */
u_char callopt; /* option for call handling:
0 = all calls
1 = only non waiting calls
2 = only waiting calls */
u_char action; /* desired action:
0 = don't report call -> ignore
1 = report call, do not allow/proceed for deflection
2 = report call, send proceed, wait max waittime secs
3 = report call, alert and deflect after waittime
4 = report call, reject immediately
actions 1-2 only take place if interface is opened
*/
u_char waittime; /* maximum wait time for proceeding */
} divert_rule;
typedef union {
int drv_version; /* return of driver version */
struct {
int drvid; /* id of driver */
char drvnam[30]; /* name of driver */
} getid;
struct {
int ruleidx; /* index of rule */
divert_rule rule; /* rule parms */
} getsetrule;
struct {
u_char subcmd; /* 0 = hangup/reject,
1 = alert,
2 = deflect */
ulong callid; /* id of call delivered by ascii output */
char to_nr[35]; /* destination when deflect,
else uus1 string (maxlen 31),
data from rule used if empty */
} fwd_ctrl;
struct {
int drvid; /* id of driver */
u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */
ulong procid; /* process id returned when no error */
u_char service; /* basically coded service, 0 = all */
char msn[25]; /* desired msn, empty = all */
char fwd_nr[35];/* forwarded to number + subaddress */
} cf_ctrl;
} divert_ioctl;
#ifdef __KERNEL__
#include <linux/isdnif.h>
#include <linux/isdn_divertif.h>
#define AUTODEL_TIME 30 /* timeout in s to delete internal entries */
/**************************************************/
/* structure keeping ascii info for device output */
/**************************************************/
struct divert_info {
struct divert_info *next;
ulong usage_cnt; /* number of files still to work */
char info_start[2]; /* info string start */
};
/**************/
/* Prototypes */
/**************/
extern spinlock_t divert_lock;
extern ulong if_used; /* number of interface users */
extern int divert_dev_deinit(void);
extern int divert_dev_init(void);
extern void put_info_buffer(char *);
extern int ll_callback(isdn_ctrl *);
extern isdn_divert_if divert_if;
extern divert_rule *getruleptr(int);
extern int insertrule(int, divert_rule *);
extern int deleterule(int);
extern void deleteprocs(void);
extern int deflect_extern_action(u_char, ulong, char *);
extern int cf_command(int, int, u_char, char *, u_char, char *, ulong *);
#endif /* __KERNEL__ */

View file

@ -1,71 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig ISDN_DRV_GIGASET
tristate "Siemens Gigaset support"
depends on TTY
select CRC_CCITT
select BITREVERSE
help
This driver supports the Siemens Gigaset SX205/255 family of
ISDN DECT bases, including the predecessors Gigaset 3070/3075
and 4170/4175 and their T-Com versions Sinus 45isdn and Sinus
721X.
If you have one of these devices, say M here and for at least
one of the connection specific parts that follow.
This will build a module called "gigaset".
Note: If you build your ISDN subsystem (ISDN_CAPI or ISDN_I4L)
as a module, you have to build this driver as a module too,
otherwise the Gigaset device won't show up as an ISDN device.
if ISDN_DRV_GIGASET
config GIGASET_CAPI
bool "Gigaset CAPI support"
depends on ISDN_CAPI='y'||(ISDN_CAPI='m'&&ISDN_DRV_GIGASET='m')
default 'y'
help
Build the Gigaset driver as a CAPI 2.0 driver interfacing with
the Kernel CAPI subsystem. To use it with the old ISDN4Linux
subsystem you'll have to enable the capidrv glue driver.
(select ISDN_CAPI_CAPIDRV.)
Say N to build the old native ISDN4Linux variant.
If unsure, say Y.
config GIGASET_I4L
bool
depends on ISDN_I4L='y'||(ISDN_I4L='m'&&ISDN_DRV_GIGASET='m')
default !GIGASET_CAPI
config GIGASET_DUMMYLL
bool
default !GIGASET_CAPI&&!GIGASET_I4L
config GIGASET_BASE
tristate "Gigaset base station support"
depends on USB
help
Say M here if you want to use the USB interface of the Gigaset
base for connection to your system.
This will build a module called "bas_gigaset".
config GIGASET_M105
tristate "Gigaset M105 support"
depends on USB
help
Say M here if you want to connect to the Gigaset base via DECT
using a Gigaset M105 (Sinus 45 Data 2) USB DECT device.
This will build a module called "usb_gigaset".
config GIGASET_M101
tristate "Gigaset M101 support"
help
Say M here if you want to connect to the Gigaset base via DECT
using a Gigaset M101 (Sinus 45 Data 1) RS232 DECT device.
This will build a module called "ser_gigaset".
config GIGASET_DEBUG
bool "Gigaset debugging"
help
This enables debugging code in the Gigaset drivers.
If in doubt, say yes.
endif # ISDN_DRV_GIGASET

View file

@ -1,13 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
gigaset-y := common.o interface.o proc.o ev-layer.o asyncdata.o
gigaset-$(CONFIG_GIGASET_CAPI) += capi.o
gigaset-$(CONFIG_GIGASET_I4L) += i4l.o
gigaset-$(CONFIG_GIGASET_DUMMYLL) += dummyll.o
usb_gigaset-y := usb-gigaset.o
ser_gigaset-y := ser-gigaset.o
bas_gigaset-y := bas-gigaset.o isocdata.o
obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset.o
obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o
obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o
obj-$(CONFIG_GIGASET_M101) += ser_gigaset.o

View file

@ -1,609 +0,0 @@
/*
* Common data handling layer for ser_gigaset and usb_gigaset
*
* Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>,
* Hansjoerg Lipp <hjlipp@web.de>,
* Stefan Eilers.
*
* =====================================================================
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
*/
#include "gigaset.h"
#include <linux/crc-ccitt.h>
#include <linux/bitrev.h>
#include <linux/export.h>
/* check if byte must be stuffed/escaped
* I'm not sure which data should be encoded.
* Therefore I will go the hard way and encode every value
* less than 0x20, the flag sequence and the control escape char.
*/
static inline int muststuff(unsigned char c)
{
if (c < PPP_TRANS) return 1;
if (c == PPP_FLAG) return 1;
if (c == PPP_ESCAPE) return 1;
/* other possible candidates: */
/* 0x91: XON with parity set */
/* 0x93: XOFF with parity set */
return 0;
}
/* == data input =========================================================== */
/* process a block of received bytes in command mode
* (mstate != MS_LOCKED && (inputstate & INS_command))
* Append received bytes to the command response buffer and forward them
* line by line to the response handler. Exit whenever a mode/state change
* might have occurred.
* Note: Received lines may be terminated by CR, LF, or CR LF, which will be
* removed before passing the line to the response handler.
* Return value:
* number of processed bytes
*/
static unsigned cmd_loop(unsigned numbytes, struct inbuf_t *inbuf)
{
unsigned char *src = inbuf->data + inbuf->head;
struct cardstate *cs = inbuf->cs;
unsigned cbytes = cs->cbytes;
unsigned procbytes = 0;
unsigned char c;
while (procbytes < numbytes) {
c = *src++;
procbytes++;
switch (c) {
case '\n':
if (cbytes == 0 && cs->respdata[0] == '\r') {
/* collapse LF with preceding CR */
cs->respdata[0] = 0;
break;
}
/* fall through */
case '\r':
/* end of message line, pass to response handler */
if (cbytes >= MAX_RESP_SIZE) {
dev_warn(cs->dev, "response too large (%d)\n",
cbytes);
cbytes = MAX_RESP_SIZE;
}
cs->cbytes = cbytes;
gigaset_dbg_buffer(DEBUG_TRANSCMD, "received response",
cbytes, cs->respdata);
gigaset_handle_modem_response(cs);
cbytes = 0;
/* store EOL byte for CRLF collapsing */
cs->respdata[0] = c;
/* cs->dle may have changed */
if (cs->dle && !(inbuf->inputstate & INS_DLE_command))
inbuf->inputstate &= ~INS_command;
/* return for reevaluating state */
goto exit;
case DLE_FLAG:
if (inbuf->inputstate & INS_DLE_char) {
/* quoted DLE: clear quote flag */
inbuf->inputstate &= ~INS_DLE_char;
} else if (cs->dle ||
(inbuf->inputstate & INS_DLE_command)) {
/* DLE escape, pass up for handling */
inbuf->inputstate |= INS_DLE_char;
goto exit;
}
/* quoted or not in DLE mode: treat as regular data */
/* fall through */
default:
/* append to line buffer if possible */
if (cbytes < MAX_RESP_SIZE)
cs->respdata[cbytes] = c;
cbytes++;
}
}
exit:
cs->cbytes = cbytes;
return procbytes;
}
/* process a block of received bytes in lock mode
* All received bytes are passed unmodified to the tty i/f.
* Return value:
* number of processed bytes
*/
static unsigned lock_loop(unsigned numbytes, struct inbuf_t *inbuf)
{
unsigned char *src = inbuf->data + inbuf->head;
gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", numbytes, src);
gigaset_if_receive(inbuf->cs, src, numbytes);
return numbytes;
}
/* process a block of received bytes in HDLC data mode
* (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 == L2_HDLC)
* Collect HDLC frames, undoing byte stuffing and watching for DLE escapes.
* When a frame is complete, check the FCS and pass valid frames to the LL.
* If DLE is encountered, return immediately to let the caller handle it.
* Return value:
* number of processed bytes
*/
static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf)
{
struct cardstate *cs = inbuf->cs;
struct bc_state *bcs = cs->bcs;
int inputstate = bcs->inputstate;
__u16 fcs = bcs->rx_fcs;
struct sk_buff *skb = bcs->rx_skb;
unsigned char *src = inbuf->data + inbuf->head;
unsigned procbytes = 0;
unsigned char c;
if (inputstate & INS_byte_stuff) {
if (!numbytes)
return 0;
inputstate &= ~INS_byte_stuff;
goto byte_stuff;
}
while (procbytes < numbytes) {
c = *src++;
procbytes++;
if (c == DLE_FLAG) {
if (inputstate & INS_DLE_char) {
/* quoted DLE: clear quote flag */
inputstate &= ~INS_DLE_char;
} else if (cs->dle || (inputstate & INS_DLE_command)) {
/* DLE escape, pass up for handling */
inputstate |= INS_DLE_char;
break;
}
}
if (c == PPP_ESCAPE) {
/* byte stuffing indicator: pull in next byte */
if (procbytes >= numbytes) {
/* end of buffer, save for later processing */
inputstate |= INS_byte_stuff;
break;
}
byte_stuff:
c = *src++;
procbytes++;
if (c == DLE_FLAG) {
if (inputstate & INS_DLE_char) {
/* quoted DLE: clear quote flag */
inputstate &= ~INS_DLE_char;
} else if (cs->dle ||
(inputstate & INS_DLE_command)) {
/* DLE escape, pass up for handling */
inputstate |=
INS_DLE_char | INS_byte_stuff;
break;
}
}
c ^= PPP_TRANS;
#ifdef CONFIG_GIGASET_DEBUG
if (!muststuff(c))
gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c);
#endif
} else if (c == PPP_FLAG) {
/* end of frame: process content if any */
if (inputstate & INS_have_data) {
gig_dbg(DEBUG_HDLC,
"7e----------------------------");
/* check and pass received frame */
if (!skb) {
/* skipped frame */
gigaset_isdn_rcv_err(bcs);
} else if (skb->len < 2) {
/* frame too short for FCS */
dev_warn(cs->dev,
"short frame (%d)\n",
skb->len);
gigaset_isdn_rcv_err(bcs);
dev_kfree_skb_any(skb);
} else if (fcs != PPP_GOODFCS) {
/* frame check error */
dev_err(cs->dev,
"Checksum failed, %u bytes corrupted!\n",
skb->len);
gigaset_isdn_rcv_err(bcs);
dev_kfree_skb_any(skb);
} else {
/* good frame */
__skb_trim(skb, skb->len - 2);
gigaset_skb_rcvd(bcs, skb);
}
/* prepare reception of next frame */
inputstate &= ~INS_have_data;
skb = gigaset_new_rx_skb(bcs);
} else {
/* empty frame (7E 7E) */
#ifdef CONFIG_GIGASET_DEBUG
++bcs->emptycount;
#endif
if (!skb) {
/* skipped (?) */
gigaset_isdn_rcv_err(bcs);
skb = gigaset_new_rx_skb(bcs);
}
}
fcs = PPP_INITFCS;
continue;
#ifdef CONFIG_GIGASET_DEBUG
} else if (muststuff(c)) {
/* Should not happen. Possible after ZDLE=1<CR><LF>. */
gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
#endif
}
/* regular data byte, append to skb */
#ifdef CONFIG_GIGASET_DEBUG
if (!(inputstate & INS_have_data)) {
gig_dbg(DEBUG_HDLC, "7e (%d x) ================",
bcs->emptycount);
bcs->emptycount = 0;
}
#endif
inputstate |= INS_have_data;
if (skb) {
if (skb->len >= bcs->rx_bufsize) {
dev_warn(cs->dev, "received packet too long\n");
dev_kfree_skb_any(skb);
/* skip remainder of packet */
bcs->rx_skb = skb = NULL;
} else {
__skb_put_u8(skb, c);
fcs = crc_ccitt_byte(fcs, c);
}
}
}
bcs->inputstate = inputstate;
bcs->rx_fcs = fcs;
return procbytes;
}
/* process a block of received bytes in transparent data mode
* (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 != L2_HDLC)
* Invert bytes, undoing byte stuffing and watching for DLE escapes.
* If DLE is encountered, return immediately to let the caller handle it.
* Return value:
* number of processed bytes
*/
static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf)
{
struct cardstate *cs = inbuf->cs;
struct bc_state *bcs = cs->bcs;
int inputstate = bcs->inputstate;
struct sk_buff *skb = bcs->rx_skb;
unsigned char *src = inbuf->data + inbuf->head;
unsigned procbytes = 0;
unsigned char c;
if (!skb) {
/* skip this block */
gigaset_new_rx_skb(bcs);
return numbytes;
}
while (procbytes < numbytes && skb->len < bcs->rx_bufsize) {
c = *src++;
procbytes++;
if (c == DLE_FLAG) {
if (inputstate & INS_DLE_char) {
/* quoted DLE: clear quote flag */
inputstate &= ~INS_DLE_char;
} else if (cs->dle || (inputstate & INS_DLE_command)) {
/* DLE escape, pass up for handling */
inputstate |= INS_DLE_char;
break;
}
}
/* regular data byte: append to current skb */
inputstate |= INS_have_data;
__skb_put_u8(skb, bitrev8(c));
}
/* pass data up */
if (inputstate & INS_have_data) {
gigaset_skb_rcvd(bcs, skb);
inputstate &= ~INS_have_data;
gigaset_new_rx_skb(bcs);
}
bcs->inputstate = inputstate;
return procbytes;
}
/* process DLE escapes
* Called whenever a DLE sequence might be encountered in the input stream.
* Either processes the entire DLE sequence or, if that isn't possible,
* notes the fact that an initial DLE has been received in the INS_DLE_char
* inputstate flag and resumes processing of the sequence on the next call.
*/
static void handle_dle(struct inbuf_t *inbuf)
{
struct cardstate *cs = inbuf->cs;
if (cs->mstate == MS_LOCKED)
return; /* no DLE processing in lock mode */
if (!(inbuf->inputstate & INS_DLE_char)) {
/* no DLE pending */
if (inbuf->data[inbuf->head] == DLE_FLAG &&
(cs->dle || inbuf->inputstate & INS_DLE_command)) {
/* start of DLE sequence */
inbuf->head++;
if (inbuf->head == inbuf->tail ||
inbuf->head == RBUFSIZE) {
/* end of buffer, save for later processing */
inbuf->inputstate |= INS_DLE_char;
return;
}
} else {
/* regular data byte */
return;
}
}
/* consume pending DLE */
inbuf->inputstate &= ~INS_DLE_char;
switch (inbuf->data[inbuf->head]) {
case 'X': /* begin of event message */
if (inbuf->inputstate & INS_command)
dev_notice(cs->dev,
"received <DLE>X in command mode\n");
inbuf->inputstate |= INS_command | INS_DLE_command;
inbuf->head++; /* byte consumed */
break;
case '.': /* end of event message */
if (!(inbuf->inputstate & INS_DLE_command))
dev_notice(cs->dev,
"received <DLE>. without <DLE>X\n");
inbuf->inputstate &= ~INS_DLE_command;
/* return to data mode if in DLE mode */
if (cs->dle)
inbuf->inputstate &= ~INS_command;
inbuf->head++; /* byte consumed */
break;
case DLE_FLAG: /* DLE in data stream */
/* mark as quoted */
inbuf->inputstate |= INS_DLE_char;
if (!(cs->dle || inbuf->inputstate & INS_DLE_command))
dev_notice(cs->dev,
"received <DLE><DLE> not in DLE mode\n");
break; /* quoted byte left in buffer */
default:
dev_notice(cs->dev, "received <DLE><%02x>\n",
inbuf->data[inbuf->head]);
/* quoted byte left in buffer */
}
}
/**
* gigaset_m10x_input() - process a block of data received from the device
* @inbuf: received data and device descriptor structure.
*
* Called by hardware module {ser,usb}_gigaset with a block of received
* bytes. Separates the bytes received over the serial data channel into
* user data and command replies (locked/unlocked) according to the
* current state of the interface.
*/
void gigaset_m10x_input(struct inbuf_t *inbuf)
{
struct cardstate *cs = inbuf->cs;
unsigned numbytes, procbytes;
gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", inbuf->head, inbuf->tail);
while (inbuf->head != inbuf->tail) {
/* check for DLE escape */
handle_dle(inbuf);
/* process a contiguous block of bytes */
numbytes = (inbuf->head > inbuf->tail ?
RBUFSIZE : inbuf->tail) - inbuf->head;
gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
/*
* numbytes may be 0 if handle_dle() ate the last byte.
* This does no harm, *_loop() will just return 0 immediately.
*/
if (cs->mstate == MS_LOCKED)
procbytes = lock_loop(numbytes, inbuf);
else if (inbuf->inputstate & INS_command)
procbytes = cmd_loop(numbytes, inbuf);
else if (cs->bcs->proto2 == L2_HDLC)
procbytes = hdlc_loop(numbytes, inbuf);
else
procbytes = iraw_loop(numbytes, inbuf);
inbuf->head += procbytes;
/* check for buffer wraparound */
if (inbuf->head >= RBUFSIZE)
inbuf->head = 0;
gig_dbg(DEBUG_INTR, "head set to %u", inbuf->head);
}
}
EXPORT_SYMBOL_GPL(gigaset_m10x_input);
/* == data output ========================================================== */
/*
* Encode a data packet into an octet stuffed HDLC frame with FCS,
* opening and closing flags, preserving headroom data.
* parameters:
* skb skb containing original packet (freed upon return)
* Return value:
* pointer to newly allocated skb containing the result frame
* and the original link layer header, NULL on error
*/
static struct sk_buff *HDLC_Encode(struct sk_buff *skb)
{
struct sk_buff *hdlc_skb;
__u16 fcs;
unsigned char c;
unsigned char *cp;
int len;
unsigned int stuf_cnt;
stuf_cnt = 0;
fcs = PPP_INITFCS;
cp = skb->data;
len = skb->len;
while (len--) {
if (muststuff(*cp))
stuf_cnt++;
fcs = crc_ccitt_byte(fcs, *cp++);
}
fcs ^= 0xffff; /* complement */
/* size of new buffer: original size + number of stuffing bytes
* + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
* + room for link layer header
*/
hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + skb->mac_len);
if (!hdlc_skb) {
dev_kfree_skb_any(skb);
return NULL;
}
/* Copy link layer header into new skb */
skb_reset_mac_header(hdlc_skb);
skb_reserve(hdlc_skb, skb->mac_len);
memcpy(skb_mac_header(hdlc_skb), skb_mac_header(skb), skb->mac_len);
hdlc_skb->mac_len = skb->mac_len;
/* Add flag sequence in front of everything.. */
skb_put_u8(hdlc_skb, PPP_FLAG);
/* Perform byte stuffing while copying data. */
while (skb->len--) {
if (muststuff(*skb->data)) {
skb_put_u8(hdlc_skb, PPP_ESCAPE);
skb_put_u8(hdlc_skb, (*skb->data++) ^ PPP_TRANS);
} else
skb_put_u8(hdlc_skb, *skb->data++);
}
/* Finally add FCS (byte stuffed) and flag sequence */
c = (fcs & 0x00ff); /* least significant byte first */
if (muststuff(c)) {
skb_put_u8(hdlc_skb, PPP_ESCAPE);
c ^= PPP_TRANS;
}
skb_put_u8(hdlc_skb, c);
c = ((fcs >> 8) & 0x00ff);
if (muststuff(c)) {
skb_put_u8(hdlc_skb, PPP_ESCAPE);
c ^= PPP_TRANS;
}
skb_put_u8(hdlc_skb, c);
skb_put_u8(hdlc_skb, PPP_FLAG);
dev_kfree_skb_any(skb);
return hdlc_skb;
}
/*
* Encode a data packet into an octet stuffed raw bit inverted frame,
* preserving headroom data.
* parameters:
* skb skb containing original packet (freed upon return)
* Return value:
* pointer to newly allocated skb containing the result frame
* and the original link layer header, NULL on error
*/
static struct sk_buff *iraw_encode(struct sk_buff *skb)
{
struct sk_buff *iraw_skb;
unsigned char c;
unsigned char *cp;
int len;
/* size of new buffer (worst case = every byte must be stuffed):
* 2 * original size + room for link layer header
*/
iraw_skb = dev_alloc_skb(2 * skb->len + skb->mac_len);
if (!iraw_skb) {
dev_kfree_skb_any(skb);
return NULL;
}
/* copy link layer header into new skb */
skb_reset_mac_header(iraw_skb);
skb_reserve(iraw_skb, skb->mac_len);
memcpy(skb_mac_header(iraw_skb), skb_mac_header(skb), skb->mac_len);
iraw_skb->mac_len = skb->mac_len;
/* copy and stuff data */
cp = skb->data;
len = skb->len;
while (len--) {
c = bitrev8(*cp++);
if (c == DLE_FLAG)
skb_put_u8(iraw_skb, c);
skb_put_u8(iraw_skb, c);
}
dev_kfree_skb_any(skb);
return iraw_skb;
}
/**
* gigaset_m10x_send_skb() - queue an skb for sending
* @bcs: B channel descriptor structure.
* @skb: data to send.
*
* Called by LL to encode and queue an skb for sending, and start
* transmission if necessary.
* Once the payload data has been transmitted completely, gigaset_skb_sent()
* will be called with the skb's link layer header preserved.
*
* Return value:
* number of bytes accepted for sending (skb->len) if ok,
* error code < 0 (eg. -ENOMEM) on error
*/
int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
{
struct cardstate *cs = bcs->cs;
unsigned len = skb->len;
unsigned long flags;
if (bcs->proto2 == L2_HDLC)
skb = HDLC_Encode(skb);
else
skb = iraw_encode(skb);
if (!skb) {
dev_err(cs->dev,
"unable to allocate memory for encoding!\n");
return -ENOMEM;
}
skb_queue_tail(&bcs->squeue, skb);
spin_lock_irqsave(&cs->lock, flags);
if (cs->connected)
tasklet_schedule(&cs->write_tasklet);
spin_unlock_irqrestore(&cs->lock, flags);
return len; /* ok so far */
}
EXPORT_SYMBOL_GPL(gigaset_m10x_send_skb);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,77 +0,0 @@
/*
* Dummy LL interface for the Gigaset driver
*
* Copyright (c) 2009 by Tilman Schmidt <tilman@imap.cc>.
*
* =====================================================================
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
*/
#include <linux/export.h>
#include "gigaset.h"
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
{
}
EXPORT_SYMBOL_GPL(gigaset_skb_sent);
void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
{
}
EXPORT_SYMBOL_GPL(gigaset_skb_rcvd);
void gigaset_isdn_rcv_err(struct bc_state *bcs)
{
}
EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err);
int gigaset_isdn_icall(struct at_state_t *at_state)
{
return ICALL_IGNORE;
}
void gigaset_isdn_connD(struct bc_state *bcs)
{
}
void gigaset_isdn_hupD(struct bc_state *bcs)
{
}
void gigaset_isdn_connB(struct bc_state *bcs)
{
}
void gigaset_isdn_hupB(struct bc_state *bcs)
{
}
void gigaset_isdn_start(struct cardstate *cs)
{
}
void gigaset_isdn_stop(struct cardstate *cs)
{
}
int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
{
return 0;
}
void gigaset_isdn_unregdev(struct cardstate *cs)
{
}
void gigaset_isdn_regdrv(void)
{
pr_info("no ISDN subsystem interface\n");
}
void gigaset_isdn_unregdrv(void)
{
}

File diff suppressed because it is too large Load diff

View file

@ -1,830 +0,0 @@
/*
* Siemens Gigaset 307x driver
* Common header file for all connection variants
*
* Written by Stefan Eilers
* and Hansjoerg Lipp <hjlipp@web.de>
*
* =====================================================================
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
*/
#ifndef GIGASET_H
#define GIGASET_H
/* define global prefix for pr_ macros in linux/kernel.h */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/ppp_defs.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/list.h>
#include <linux/atomic.h>
#define GIG_VERSION {0, 5, 0, 0}
#define GIG_COMPAT {0, 4, 0, 0}
#define MAX_REC_PARAMS 10 /* Max. number of params in response string */
#define MAX_RESP_SIZE 511 /* Max. size of a response string */
#define MAX_EVENTS 64 /* size of event queue */
#define RBUFSIZE 8192
#define GIG_TICK 100 /* in milliseconds */
/* timeout values (unit: 1 sec) */
#define INIT_TIMEOUT 1
/* timeout values (unit: 0.1 sec) */
#define RING_TIMEOUT 3 /* for additional parameters to RING */
#define BAS_TIMEOUT 20 /* for response to Base USB ops */
#define ATRDY_TIMEOUT 3 /* for HD_READY_SEND_ATDATA */
#define BAS_RETRY 3 /* max. retries for base USB ops */
#define MAXACT 3
extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */
/* debug flags, combine by adding/bitwise OR */
enum debuglevel {
DEBUG_INTR = 0x00008, /* interrupt processing */
DEBUG_CMD = 0x00020, /* sent/received LL commands */
DEBUG_STREAM = 0x00040, /* application data stream I/O events */
DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */
DEBUG_LLDATA = 0x00100, /* sent/received LL data */
DEBUG_EVENT = 0x00200, /* event processing */
DEBUG_HDLC = 0x00800, /* M10x HDLC processing */
DEBUG_CHANNEL = 0x01000, /* channel allocation/deallocation */
DEBUG_TRANSCMD = 0x02000, /* AT-COMMANDS+RESPONSES */
DEBUG_MCMD = 0x04000, /* COMMANDS THAT ARE SENT VERY OFTEN */
DEBUG_INIT = 0x08000, /* (de)allocation+initialization of data
structures */
DEBUG_SUSPEND = 0x10000, /* suspend/resume processing */
DEBUG_OUTPUT = 0x20000, /* output to device */
DEBUG_ISO = 0x40000, /* isochronous transfers */
DEBUG_IF = 0x80000, /* character device operations */
DEBUG_USBREQ = 0x100000, /* USB communication (except payload
data) */
DEBUG_LOCKCMD = 0x200000, /* AT commands and responses when
MS_LOCKED */
DEBUG_ANY = 0x3fffff, /* print message if any of the others is
activated */
};
#ifdef CONFIG_GIGASET_DEBUG
#define gig_dbg(level, format, arg...) \
do { \
if (unlikely(((enum debuglevel)gigaset_debuglevel) & (level))) \
printk(KERN_DEBUG KBUILD_MODNAME ": " format "\n", \
## arg); \
} while (0)
#define DEBUG_DEFAULT (DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ)
#else
#define gig_dbg(level, format, arg...) do {} while (0)
#define DEBUG_DEFAULT 0
#endif
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
size_t len, const unsigned char *buf);
/* connection state */
#define ZSAU_NONE 0
#define ZSAU_PROCEEDING 1
#define ZSAU_CALL_DELIVERED 2
#define ZSAU_ACTIVE 3
#define ZSAU_DISCONNECT_IND 4
#define ZSAU_NULL 5
#define ZSAU_DISCONNECT_REQ 6
#define ZSAU_UNKNOWN -1
/* USB control transfer requests */
#define OUT_VENDOR_REQ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
#define IN_VENDOR_REQ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
/* interrupt pipe messages */
#define HD_B1_FLOW_CONTROL 0x80
#define HD_B2_FLOW_CONTROL 0x81
#define HD_RECEIVEATDATA_ACK (0x35) /* 3070 */
#define HD_READY_SEND_ATDATA (0x36) /* 3070 */
#define HD_OPEN_ATCHANNEL_ACK (0x37) /* 3070 */
#define HD_CLOSE_ATCHANNEL_ACK (0x38) /* 3070 */
#define HD_DEVICE_INIT_OK (0x11) /* ISurf USB + 3070 */
#define HD_OPEN_B1CHANNEL_ACK (0x51) /* ISurf USB + 3070 */
#define HD_OPEN_B2CHANNEL_ACK (0x52) /* ISurf USB + 3070 */
#define HD_CLOSE_B1CHANNEL_ACK (0x53) /* ISurf USB + 3070 */
#define HD_CLOSE_B2CHANNEL_ACK (0x54) /* ISurf USB + 3070 */
#define HD_SUSPEND_END (0x61) /* ISurf USB */
#define HD_RESET_INTERRUPT_PIPE_ACK (0xFF) /* ISurf USB + 3070 */
/* control requests */
#define HD_OPEN_B1CHANNEL (0x23) /* ISurf USB + 3070 */
#define HD_CLOSE_B1CHANNEL (0x24) /* ISurf USB + 3070 */
#define HD_OPEN_B2CHANNEL (0x25) /* ISurf USB + 3070 */
#define HD_CLOSE_B2CHANNEL (0x26) /* ISurf USB + 3070 */
#define HD_RESET_INTERRUPT_PIPE (0x27) /* ISurf USB + 3070 */
#define HD_DEVICE_INIT_ACK (0x34) /* ISurf USB + 3070 */
#define HD_WRITE_ATMESSAGE (0x12) /* 3070 */
#define HD_READ_ATMESSAGE (0x13) /* 3070 */
#define HD_OPEN_ATCHANNEL (0x28) /* 3070 */
#define HD_CLOSE_ATCHANNEL (0x29) /* 3070 */
/* number of B channels supported by base driver */
#define BAS_CHANNELS 2
/* USB frames for isochronous transfer */
#define BAS_FRAMETIME 1 /* number of milliseconds between frames */
#define BAS_NUMFRAMES 8 /* number of frames per URB */
#define BAS_MAXFRAME 16 /* allocated bytes per frame */
#define BAS_NORMFRAME 8 /* send size without flow control */
#define BAS_HIGHFRAME 10 /* " " with positive flow control */
#define BAS_LOWFRAME 5 /* " " with negative flow control */
#define BAS_CORRFRAMES 4 /* flow control multiplicator */
#define BAS_INBUFSIZE (BAS_MAXFRAME * BAS_NUMFRAMES) /* size of isoc in buf
* per URB */
#define BAS_OUTBUFSIZE 4096 /* size of common isoc out buffer */
#define BAS_OUTBUFPAD BAS_MAXFRAME /* size of pad area for isoc out buf */
#define BAS_INURBS 3
#define BAS_OUTURBS 3
/* variable commands in struct bc_state */
#define AT_ISO 0
#define AT_DIAL 1
#define AT_MSN 2
#define AT_BC 3
#define AT_PROTO 4
#define AT_TYPE 5
#define AT_CLIP 6
/* total number */
#define AT_NUM 7
/* variables in struct at_state_t */
/* - numeric */
#define VAR_ZSAU 0
#define VAR_ZDLE 1
#define VAR_ZCTP 2
/* total number */
#define VAR_NUM 3
/* - string */
#define STR_NMBR 0
#define STR_ZCPN 1
#define STR_ZCON 2
#define STR_ZBC 3
#define STR_ZHLC 4
/* total number */
#define STR_NUM 5
/* event types */
#define EV_TIMEOUT -105
#define EV_IF_VER -106
#define EV_PROC_CIDMODE -107
#define EV_SHUTDOWN -108
#define EV_START -110
#define EV_STOP -111
#define EV_IF_LOCK -112
#define EV_ACCEPT -114
#define EV_DIAL -115
#define EV_HUP -116
#define EV_BC_OPEN -117
#define EV_BC_CLOSED -118
/* input state */
#define INS_command 0x0001 /* receiving messages (not payload data) */
#define INS_DLE_char 0x0002 /* DLE flag received (in DLE mode) */
#define INS_byte_stuff 0x0004
#define INS_have_data 0x0008
#define INS_DLE_command 0x0020 /* DLE message start (<DLE> X) received */
#define INS_flag_hunt 0x0040
/* channel state */
#define CHS_D_UP 0x01
#define CHS_B_UP 0x02
#define CHS_NOTIFY_LL 0x04
#define ICALL_REJECT 0
#define ICALL_ACCEPT 1
#define ICALL_IGNORE 2
/* device state */
#define MS_UNINITIALIZED 0
#define MS_INIT 1
#define MS_LOCKED 2
#define MS_SHUTDOWN 3
#define MS_RECOVER 4
#define MS_READY 5
/* mode */
#define M_UNKNOWN 0
#define M_CONFIG 1
#define M_UNIMODEM 2
#define M_CID 3
/* start mode */
#define SM_LOCKED 0
#define SM_ISDN 1 /* default */
/* layer 2 protocols (AT^SBPR=...) */
#define L2_BITSYNC 0
#define L2_HDLC 1
#define L2_VOICE 2
struct gigaset_ops;
struct gigaset_driver;
struct usb_cardstate;
struct ser_cardstate;
struct bas_cardstate;
struct bc_state;
struct usb_bc_state;
struct ser_bc_state;
struct bas_bc_state;
struct reply_t {
int resp_code; /* RSP_XXXX */
int min_ConState; /* <0 => ignore */
int max_ConState; /* <0 => ignore */
int parameter; /* e.g. ZSAU_XXXX <0: ignore*/
int new_ConState; /* <0 => ignore */
int timeout; /* >0 => *HZ; <=0 => TOUT_XXXX*/
int action[MAXACT]; /* ACT_XXXX */
char *command; /* NULL==none */
};
extern struct reply_t gigaset_tab_cid[];
extern struct reply_t gigaset_tab_nocid[];
struct inbuf_t {
struct cardstate *cs;
int inputstate;
int head, tail;
unsigned char data[RBUFSIZE];
};
/* isochronous write buffer structure
* circular buffer with pad area for extraction of complete USB frames
* - data[read..nextread-1] is valid data already submitted to the USB subsystem
* - data[nextread..write-1] is valid data yet to be sent
* - data[write] is the next byte to write to
* - in byte-oriented L2 procotols, it is completely free
* - in bit-oriented L2 procotols, it may contain a partial byte of valid data
* - data[write+1..read-1] is free
* - wbits is the number of valid data bits in data[write], starting at the LSB
* - writesem is the semaphore for writing to the buffer:
* if writesem <= 0, data[write..read-1] is currently being written to
* - idle contains the byte value to repeat when the end of valid data is
* reached; if nextread==write (buffer contains no data to send), either the
* BAS_OUTBUFPAD bytes immediately before data[write] (if
* write>=BAS_OUTBUFPAD) or those of the pad area (if write<BAS_OUTBUFPAD)
* are also filled with that value
*/
struct isowbuf_t {
int read;
int nextread;
int write;
atomic_t writesem;
int wbits;
unsigned char data[BAS_OUTBUFSIZE + BAS_OUTBUFPAD];
unsigned char idle;
};
/* isochronous write URB context structure
* data to be stored along with the URB and retrieved when it is returned
* as completed by the USB subsystem
* - urb: pointer to the URB itself
* - bcs: pointer to the B Channel control structure
* - limit: end of write buffer area covered by this URB
* - status: URB completion status
*/
struct isow_urbctx_t {
struct urb *urb;
struct bc_state *bcs;
int limit;
int status;
};
/* AT state structure
* data associated with the state of an ISDN connection, whether or not
* it is currently assigned a B channel
*/
struct at_state_t {
struct list_head list;
int waiting;
int getstring;
unsigned timer_index;
unsigned long timer_expires;
int timer_active;
unsigned int ConState; /* State of connection */
struct reply_t *replystruct;
int cid;
int int_var[VAR_NUM]; /* see VAR_XXXX */
char *str_var[STR_NUM]; /* see STR_XXXX */
unsigned pending_commands; /* see PC_XXXX */
unsigned seq_index;
struct cardstate *cs;
struct bc_state *bcs;
};
struct event_t {
int type;
void *ptr, *arg;
int parameter;
int cid;
struct at_state_t *at_state;
};
/* This buffer holds all information about the used B-Channel */
struct bc_state {
struct sk_buff *tx_skb; /* Current transfer buffer to modem */
struct sk_buff_head squeue; /* B-Channel send Queue */
/* Variables for debugging .. */
int corrupted; /* Counter for corrupted packages */
int trans_down; /* Counter of packages (downstream) */
int trans_up; /* Counter of packages (upstream) */
struct at_state_t at_state;
/* receive buffer */
unsigned rx_bufsize; /* max size accepted by application */
struct sk_buff *rx_skb;
__u16 rx_fcs;
int inputstate; /* see INS_XXXX */
int channel;
struct cardstate *cs;
unsigned chstate; /* bitmap (CHS_*) */
int ignore;
unsigned proto2; /* layer 2 protocol (L2_*) */
char *commands[AT_NUM]; /* see AT_XXXX */
#ifdef CONFIG_GIGASET_DEBUG
int emptycount;
#endif
int busy;
int use_count;
/* private data of hardware drivers */
union {
struct ser_bc_state *ser; /* serial hardware driver */
struct usb_bc_state *usb; /* usb hardware driver (m105) */
struct bas_bc_state *bas; /* usb hardware driver (base) */
} hw;
void *ap; /* associated LL application */
int apconnstate; /* LL application connection state */
spinlock_t aplock;
};
struct cardstate {
struct gigaset_driver *driver;
unsigned minor_index;
struct device *dev;
struct device *tty_dev;
unsigned flags;
const struct gigaset_ops *ops;
/* Stuff to handle communication */
wait_queue_head_t waitqueue;
int waiting;
int mode; /* see M_XXXX */
int mstate; /* Modem state: see MS_XXXX */
/* only changed by the event layer */
int cmd_result;
int channels;
struct bc_state *bcs; /* Array of struct bc_state */
int onechannel; /* data and commands transmitted in one
stream (M10x) */
spinlock_t lock;
struct at_state_t at_state; /* at_state_t for cid == 0 */
struct list_head temp_at_states;/* list of temporary "struct
at_state_t"s without B channel */
struct inbuf_t *inbuf;
struct cmdbuf_t *cmdbuf, *lastcmdbuf;
spinlock_t cmdlock;
unsigned curlen, cmdbytes;
struct tty_port port;
struct tasklet_struct if_wake_tasklet;
unsigned control_state;
unsigned fwver[4];
int gotfwver;
unsigned running; /* !=0 if events are handled */
unsigned connected; /* !=0 if hardware is connected */
unsigned isdn_up; /* !=0 after gigaset_isdn_start() */
unsigned cidmode;
int myid; /* id for communication with LL */
void *iif; /* LL interface structure */
unsigned short hw_hdr_len; /* headroom needed in data skbs */
struct reply_t *tabnocid;
struct reply_t *tabcid;
int cs_init;
int ignoreframes; /* frames to ignore after setting up the
B channel */
struct mutex mutex; /* locks this structure:
* connected is not changed,
* hardware_up is not changed,
* MState is not changed to or from
* MS_LOCKED */
struct timer_list timer;
int retry_count;
int dle; /* !=0 if DLE mode is active
(ZDLE=1 received -- M10x only) */
int cur_at_seq; /* sequence of AT commands being
processed */
int curchannel; /* channel those commands are meant
for */
int commands_pending; /* flag(s) in xxx.commands_pending have
been set */
struct tasklet_struct
event_tasklet; /* tasklet for serializing AT commands.
* Scheduled
* -> for modem reponses (and
* incoming data for M10x)
* -> on timeout
* -> after setting bits in
* xxx.at_state.pending_command
* (e.g. command from LL) */
struct tasklet_struct
write_tasklet; /* tasklet for serial output
* (not used in base driver) */
/* event queue */
struct event_t events[MAX_EVENTS];
unsigned ev_tail, ev_head;
spinlock_t ev_lock;
/* current modem response */
unsigned char respdata[MAX_RESP_SIZE + 1];
unsigned cbytes;
/* private data of hardware drivers */
union {
struct usb_cardstate *usb; /* USB hardware driver (m105) */
struct ser_cardstate *ser; /* serial hardware driver */
struct bas_cardstate *bas; /* USB hardware driver (base) */
} hw;
};
struct gigaset_driver {
struct list_head list;
spinlock_t lock; /* locks minor tables and blocked */
struct tty_driver *tty;
unsigned have_tty;
unsigned minor;
unsigned minors;
struct cardstate *cs;
int blocked;
const struct gigaset_ops *ops;
struct module *owner;
};
struct cmdbuf_t {
struct cmdbuf_t *next, *prev;
int len, offset;
struct tasklet_struct *wake_tasklet;
unsigned char buf[0];
};
struct bas_bc_state {
/* isochronous output state */
int running;
atomic_t corrbytes;
spinlock_t isooutlock;
struct isow_urbctx_t isoouturbs[BAS_OUTURBS];
struct isow_urbctx_t *isooutdone, *isooutfree, *isooutovfl;
struct isowbuf_t *isooutbuf;
unsigned numsub; /* submitted URB counter
(for diagnostic messages only) */
struct tasklet_struct sent_tasklet;
/* isochronous input state */
spinlock_t isoinlock;
struct urb *isoinurbs[BAS_INURBS];
unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS];
struct urb *isoindone; /* completed isoc read URB */
int isoinstatus; /* status of completed URB */
int loststatus; /* status of dropped URB */
unsigned isoinlost; /* number of bytes lost */
/* state of bit unstuffing algorithm
(in addition to BC_state.inputstate) */
unsigned seqlen; /* number of '1' bits not yet
unstuffed */
unsigned inbyte, inbits; /* collected bits for next byte */
/* statistics */
unsigned goodbytes; /* bytes correctly received */
unsigned alignerrs; /* frames with incomplete byte at end */
unsigned fcserrs; /* FCS errors */
unsigned frameerrs; /* framing errors */
unsigned giants; /* long frames */
unsigned runts; /* short frames */
unsigned aborts; /* HDLC aborts */
unsigned shared0s; /* '0' bits shared between flags */
unsigned stolen0s; /* '0' stuff bits also serving as
leading flag bits */
struct tasklet_struct rcvd_tasklet;
};
struct gigaset_ops {
/* Called from ev-layer.c/interface.c for sending AT commands to the
device */
int (*write_cmd)(struct cardstate *cs, struct cmdbuf_t *cb);
/* Called from interface.c for additional device control */
int (*write_room)(struct cardstate *cs);
int (*chars_in_buffer)(struct cardstate *cs);
int (*brkchars)(struct cardstate *cs, const unsigned char buf[6]);
/* Called from ev-layer.c after setting up connection
* Should call gigaset_bchannel_up(), when finished. */
int (*init_bchannel)(struct bc_state *bcs);
/* Called from ev-layer.c after hanging up
* Should call gigaset_bchannel_down(), when finished. */
int (*close_bchannel)(struct bc_state *bcs);
/* Called by gigaset_initcs() for setting up bcs->hw.xxx */
int (*initbcshw)(struct bc_state *bcs);
/* Called by gigaset_freecs() for freeing bcs->hw.xxx */
void (*freebcshw)(struct bc_state *bcs);
/* Called by gigaset_bchannel_down() for resetting bcs->hw.xxx */
void (*reinitbcshw)(struct bc_state *bcs);
/* Called by gigaset_initcs() for setting up cs->hw.xxx */
int (*initcshw)(struct cardstate *cs);
/* Called by gigaset_freecs() for freeing cs->hw.xxx */
void (*freecshw)(struct cardstate *cs);
/* Called from common.c/interface.c for additional serial port
control */
int (*set_modem_ctrl)(struct cardstate *cs, unsigned old_state,
unsigned new_state);
int (*baud_rate)(struct cardstate *cs, unsigned cflag);
int (*set_line_ctrl)(struct cardstate *cs, unsigned cflag);
/* Called from LL interface to put an skb into the send-queue.
* After sending is completed, gigaset_skb_sent() must be called
* with the skb's link layer header preserved. */
int (*send_skb)(struct bc_state *bcs, struct sk_buff *skb);
/* Called from ev-layer.c to process a block of data
* received through the common/control channel. */
void (*handle_input)(struct inbuf_t *inbuf);
};
/* = Common structures and definitions =======================================
*/
/* Parser states for DLE-Event:
* <DLE-EVENT>: <DLE_FLAG> "X" <EVENT> <DLE_FLAG> "."
* <DLE_FLAG>: 0x10
* <EVENT>: ((a-z)* | (A-Z)* | (0-10)*)+
*/
#define DLE_FLAG 0x10
/* ===========================================================================
* Functions implemented in asyncdata.c
*/
/* Called from LL interface to put an skb into the send queue. */
int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb);
/* Called from ev-layer.c to process a block of data
* received through the common/control channel. */
void gigaset_m10x_input(struct inbuf_t *inbuf);
/* ===========================================================================
* Functions implemented in isocdata.c
*/
/* Called from LL interface to put an skb into the send queue. */
int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb);
/* Called from ev-layer.c to process a block of data
* received through the common/control channel. */
void gigaset_isoc_input(struct inbuf_t *inbuf);
/* Called from bas-gigaset.c to process a block of data
* received through the isochronous channel */
void gigaset_isoc_receive(unsigned char *src, unsigned count,
struct bc_state *bcs);
/* Called from bas-gigaset.c to put a block of data
* into the isochronous output buffer */
int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len);
/* Called from bas-gigaset.c to initialize the isochronous output buffer */
void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle);
/* Called from bas-gigaset.c to retrieve a block of bytes for sending */
int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size);
/* ===========================================================================
* Functions implemented in LL interface
*/
/* Called from common.c for setting up/shutting down with the ISDN subsystem */
void gigaset_isdn_regdrv(void);
void gigaset_isdn_unregdrv(void);
int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid);
void gigaset_isdn_unregdev(struct cardstate *cs);
/* Called from hardware module to indicate completion of an skb */
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb);
void gigaset_isdn_rcv_err(struct bc_state *bcs);
/* Called from common.c/ev-layer.c to indicate events relevant to the LL */
void gigaset_isdn_start(struct cardstate *cs);
void gigaset_isdn_stop(struct cardstate *cs);
int gigaset_isdn_icall(struct at_state_t *at_state);
void gigaset_isdn_connD(struct bc_state *bcs);
void gigaset_isdn_hupD(struct bc_state *bcs);
void gigaset_isdn_connB(struct bc_state *bcs);
void gigaset_isdn_hupB(struct bc_state *bcs);
/* ===========================================================================
* Functions implemented in ev-layer.c
*/
/* tasklet called from common.c to process queued events */
void gigaset_handle_event(unsigned long data);
/* called from isocdata.c / asyncdata.c
* when a complete modem response line has been received */
void gigaset_handle_modem_response(struct cardstate *cs);
/* ===========================================================================
* Functions implemented in proc.c
*/
/* initialize sysfs for device */
void gigaset_init_dev_sysfs(struct cardstate *cs);
void gigaset_free_dev_sysfs(struct cardstate *cs);
/* ===========================================================================
* Functions implemented in common.c/gigaset.h
*/
void gigaset_bcs_reinit(struct bc_state *bcs);
void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
struct cardstate *cs, int cid);
int gigaset_get_channel(struct bc_state *bcs);
struct bc_state *gigaset_get_free_channel(struct cardstate *cs);
void gigaset_free_channel(struct bc_state *bcs);
int gigaset_get_channels(struct cardstate *cs);
void gigaset_free_channels(struct cardstate *cs);
void gigaset_block_channels(struct cardstate *cs);
/* Allocate and initialize driver structure. */
struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
const char *procname,
const char *devname,
const struct gigaset_ops *ops,
struct module *owner);
/* Deallocate driver structure. */
void gigaset_freedriver(struct gigaset_driver *drv);
struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty);
struct cardstate *gigaset_get_cs_by_id(int id);
void gigaset_blockdriver(struct gigaset_driver *drv);
/* Allocate and initialize card state. Calls hardware dependent
gigaset_init[b]cs(). */
struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
int onechannel, int ignoreframes,
int cidmode, const char *modulename);
/* Free card state. Calls hardware dependent gigaset_free[b]cs(). */
void gigaset_freecs(struct cardstate *cs);
/* Tell common.c that hardware and driver are ready. */
int gigaset_start(struct cardstate *cs);
/* Tell common.c that the device is not present any more. */
void gigaset_stop(struct cardstate *cs);
/* Tell common.c that the driver is being unloaded. */
int gigaset_shutdown(struct cardstate *cs);
/* Append event to the queue.
* Returns NULL on failure or a pointer to the event on success.
* ptr must be kmalloc()ed (and not be freed by the caller).
*/
struct event_t *gigaset_add_event(struct cardstate *cs,
struct at_state_t *at_state, int type,
void *ptr, int parameter, void *arg);
/* Called on CONFIG1 command from frontend. */
int gigaset_enterconfigmode(struct cardstate *cs);
/* cs->lock must not be locked */
static inline void gigaset_schedule_event(struct cardstate *cs)
{
unsigned long flags;
spin_lock_irqsave(&cs->lock, flags);
if (cs->running)
tasklet_schedule(&cs->event_tasklet);
spin_unlock_irqrestore(&cs->lock, flags);
}
/* Tell common.c that B channel has been closed. */
/* cs->lock must not be locked */
static inline void gigaset_bchannel_down(struct bc_state *bcs)
{
gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_CLOSED, NULL, 0, NULL);
gigaset_schedule_event(bcs->cs);
}
/* Tell common.c that B channel has been opened. */
/* cs->lock must not be locked */
static inline void gigaset_bchannel_up(struct bc_state *bcs)
{
gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_OPEN, NULL, 0, NULL);
gigaset_schedule_event(bcs->cs);
}
/* set up next receive skb for data mode */
static inline struct sk_buff *gigaset_new_rx_skb(struct bc_state *bcs)
{
struct cardstate *cs = bcs->cs;
unsigned short hw_hdr_len = cs->hw_hdr_len;
if (bcs->ignore) {
bcs->rx_skb = NULL;
} else {
bcs->rx_skb = dev_alloc_skb(bcs->rx_bufsize + hw_hdr_len);
if (bcs->rx_skb == NULL)
dev_warn(cs->dev, "could not allocate skb\n");
else
skb_reserve(bcs->rx_skb, hw_hdr_len);
}
return bcs->rx_skb;
}
/* append received bytes to inbuf */
int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
unsigned numbytes);
/* ===========================================================================
* Functions implemented in interface.c
*/
/* initialize interface */
void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
const char *devname);
/* release interface */
void gigaset_if_freedriver(struct gigaset_driver *drv);
/* add minor */
void gigaset_if_init(struct cardstate *cs);
/* remove minor */
void gigaset_if_free(struct cardstate *cs);
/* device received data */
void gigaset_if_receive(struct cardstate *cs,
unsigned char *buffer, size_t len);
#endif

View file

@ -1,695 +0,0 @@
/*
* Stuff used by all variants of the driver
*
* Copyright (c) 2001 by Stefan Eilers,
* Hansjoerg Lipp <hjlipp@web.de>,
* Tilman Schmidt <tilman@imap.cc>.
*
* =====================================================================
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
*/
#include "gigaset.h"
#include <linux/isdnif.h>
#include <linux/export.h>
#define SBUFSIZE 4096 /* sk_buff payload size */
#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */
#define HW_HDR_LEN 2 /* Header size used to store ack info */
#define MAX_BUF_SIZE (SBUFSIZE - HW_HDR_LEN) /* max data packet from LL */
/* == Handling of I4L IO =====================================================*/
/* writebuf_from_LL
* called by LL to transmit data on an open channel
* inserts the buffer data into the send queue and starts the transmission
* Note that this operation must not sleep!
* When the buffer is processed completely, gigaset_skb_sent() should be called.
* parameters:
* driverID driver ID as assigned by LL
* channel channel number
* ack if != 0 LL wants to be notified on completion via
* statcallb(ISDN_STAT_BSENT)
* skb skb containing data to send
* return value:
* number of accepted bytes
* 0 if temporarily unable to accept data (out of buffer space)
* <0 on error (eg. -EINVAL)
*/
static int writebuf_from_LL(int driverID, int channel, int ack,
struct sk_buff *skb)
{
struct cardstate *cs = gigaset_get_cs_by_id(driverID);
struct bc_state *bcs;
unsigned char *ack_header;
unsigned len;
if (!cs) {
pr_err("%s: invalid driver ID (%d)\n", __func__, driverID);
return -ENODEV;
}
if (channel < 0 || channel >= cs->channels) {
dev_err(cs->dev, "%s: invalid channel ID (%d)\n",
__func__, channel);
return -ENODEV;
}
bcs = &cs->bcs[channel];
/* can only handle linear sk_buffs */
if (skb_linearize(skb) < 0) {
dev_err(cs->dev, "%s: skb_linearize failed\n", __func__);
return -ENOMEM;
}
len = skb->len;
gig_dbg(DEBUG_LLDATA,
"Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)",
driverID, channel, ack, len);
if (!len) {
if (ack)
dev_notice(cs->dev, "%s: not ACKing empty packet\n",
__func__);
return 0;
}
if (len > MAX_BUF_SIZE) {
dev_err(cs->dev, "%s: packet too large (%d bytes)\n",
__func__, len);
return -EINVAL;
}
/* set up acknowledgement header */
if (skb_headroom(skb) < HW_HDR_LEN) {
/* should never happen */
dev_err(cs->dev, "%s: insufficient skb headroom\n", __func__);
return -ENOMEM;
}
skb_set_mac_header(skb, -HW_HDR_LEN);
skb->mac_len = HW_HDR_LEN;
ack_header = skb_mac_header(skb);
if (ack) {
ack_header[0] = len & 0xff;
ack_header[1] = len >> 8;
} else {
ack_header[0] = ack_header[1] = 0;
}
gig_dbg(DEBUG_MCMD, "skb: len=%u, ack=%d: %02x %02x",
len, ack, ack_header[0], ack_header[1]);
/* pass to device-specific module */
return cs->ops->send_skb(bcs, skb);
}
/**
* gigaset_skb_sent() - acknowledge sending an skb
* @bcs: B channel descriptor structure.
* @skb: sent data.
*
* Called by hardware module {bas,ser,usb}_gigaset when the data in a
* skb has been successfully sent, for signalling completion to the LL.
*/
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
{
isdn_if *iif = bcs->cs->iif;
unsigned char *ack_header = skb_mac_header(skb);
unsigned len;
isdn_ctrl response;
++bcs->trans_up;
if (skb->len)
dev_warn(bcs->cs->dev, "%s: skb->len==%d\n",
__func__, skb->len);
len = ack_header[0] + ((unsigned) ack_header[1] << 8);
if (len) {
gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)",
bcs->cs->myid, bcs->channel, len);
response.driver = bcs->cs->myid;
response.command = ISDN_STAT_BSENT;
response.arg = bcs->channel;
response.parm.length = len;
iif->statcallb(&response);
}
}
EXPORT_SYMBOL_GPL(gigaset_skb_sent);
/**
* gigaset_skb_rcvd() - pass received skb to LL
* @bcs: B channel descriptor structure.
* @skb: received data.
*
* Called by hardware module {bas,ser,usb}_gigaset when user data has
* been successfully received, for passing to the LL.
* Warning: skb must not be accessed anymore!
*/
void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
{
isdn_if *iif = bcs->cs->iif;
iif->rcvcallb_skb(bcs->cs->myid, bcs->channel, skb);
bcs->trans_down++;
}
EXPORT_SYMBOL_GPL(gigaset_skb_rcvd);
/**
* gigaset_isdn_rcv_err() - signal receive error
* @bcs: B channel descriptor structure.
*
* Called by hardware module {bas,ser,usb}_gigaset when a receive error
* has occurred, for signalling to the LL.
*/
void gigaset_isdn_rcv_err(struct bc_state *bcs)
{
isdn_if *iif = bcs->cs->iif;
isdn_ctrl response;
/* if currently ignoring packets, just count down */
if (bcs->ignore) {
bcs->ignore--;
return;
}
/* update statistics */
bcs->corrupted++;
/* error -> LL */
gig_dbg(DEBUG_CMD, "sending L1ERR");
response.driver = bcs->cs->myid;
response.command = ISDN_STAT_L1ERR;
response.arg = bcs->channel;
response.parm.errcode = ISDN_STAT_L1ERR_RECV;
iif->statcallb(&response);
}
EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err);
/* This function will be called by LL to send commands
* NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL,
* so don't put too much effort into it.
*/
static int command_from_LL(isdn_ctrl *cntrl)
{
struct cardstate *cs;
struct bc_state *bcs;
int retval = 0;
char **commands;
int ch;
int i;
size_t l;
gig_dbg(DEBUG_CMD, "driver: %d, command: %d, arg: 0x%lx",
cntrl->driver, cntrl->command, cntrl->arg);
cs = gigaset_get_cs_by_id(cntrl->driver);
if (cs == NULL) {
pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver);
return -ENODEV;
}
ch = cntrl->arg & 0xff;
switch (cntrl->command) {
case ISDN_CMD_IOCTL:
dev_warn(cs->dev, "ISDN_CMD_IOCTL not supported\n");
return -EINVAL;
case ISDN_CMD_DIAL:
gig_dbg(DEBUG_CMD,
"ISDN_CMD_DIAL (phone: %s, msn: %s, si1: %d, si2: %d)",
cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
cntrl->parm.setup.si1, cntrl->parm.setup.si2);
if (ch >= cs->channels) {
dev_err(cs->dev,
"ISDN_CMD_DIAL: invalid channel (%d)\n", ch);
return -EINVAL;
}
bcs = cs->bcs + ch;
if (gigaset_get_channel(bcs) < 0) {
dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n");
return -EBUSY;
}
switch (bcs->proto2) {
case L2_HDLC:
bcs->rx_bufsize = SBUFSIZE;
break;
default: /* assume transparent */
bcs->rx_bufsize = TRANSBUFSIZE;
}
dev_kfree_skb(bcs->rx_skb);
gigaset_new_rx_skb(bcs);
commands = kcalloc(AT_NUM, sizeof(*commands), GFP_ATOMIC);
if (!commands) {
gigaset_free_channel(bcs);
dev_err(cs->dev, "ISDN_CMD_DIAL: out of memory\n");
return -ENOMEM;
}
l = 3 + strlen(cntrl->parm.setup.phone);
commands[AT_DIAL] = kmalloc(l, GFP_ATOMIC);
if (!commands[AT_DIAL])
goto oom;
if (cntrl->parm.setup.phone[0] == '*' &&
cntrl->parm.setup.phone[1] == '*') {
/* internal call: translate ** prefix to CTP value */
commands[AT_TYPE] = kstrdup("^SCTP=0\r", GFP_ATOMIC);
if (!commands[AT_TYPE])
goto oom;
snprintf(commands[AT_DIAL], l,
"D%s\r", cntrl->parm.setup.phone + 2);
} else {
commands[AT_TYPE] = kstrdup("^SCTP=1\r", GFP_ATOMIC);
if (!commands[AT_TYPE])
goto oom;
snprintf(commands[AT_DIAL], l,
"D%s\r", cntrl->parm.setup.phone);
}
l = strlen(cntrl->parm.setup.eazmsn);
if (l) {
l += 8;
commands[AT_MSN] = kmalloc(l, GFP_ATOMIC);
if (!commands[AT_MSN])
goto oom;
snprintf(commands[AT_MSN], l, "^SMSN=%s\r",
cntrl->parm.setup.eazmsn);
}
switch (cntrl->parm.setup.si1) {
case 1: /* audio */
/* BC = 9090A3: 3.1 kHz audio, A-law */
commands[AT_BC] = kstrdup("^SBC=9090A3\r", GFP_ATOMIC);
if (!commands[AT_BC])
goto oom;
break;
case 7: /* data */
default: /* hope the app knows what it is doing */
/* BC = 8890: unrestricted digital information */
commands[AT_BC] = kstrdup("^SBC=8890\r", GFP_ATOMIC);
if (!commands[AT_BC])
goto oom;
}
/* ToDo: other si1 values, inspect si2, set HLC/LLC */
commands[AT_PROTO] = kmalloc(9, GFP_ATOMIC);
if (!commands[AT_PROTO])
goto oom;
snprintf(commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2);
commands[AT_ISO] = kmalloc(9, GFP_ATOMIC);
if (!commands[AT_ISO])
goto oom;
snprintf(commands[AT_ISO], 9, "^SISO=%u\r",
(unsigned) bcs->channel + 1);
if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, commands,
bcs->at_state.seq_index, NULL)) {
for (i = 0; i < AT_NUM; ++i)
kfree(commands[i]);
kfree(commands);
gigaset_free_channel(bcs);
return -ENOMEM;
}
gigaset_schedule_event(cs);
break;
case ISDN_CMD_ACCEPTD:
gig_dbg(DEBUG_CMD, "ISDN_CMD_ACCEPTD");
if (ch >= cs->channels) {
dev_err(cs->dev,
"ISDN_CMD_ACCEPTD: invalid channel (%d)\n", ch);
return -EINVAL;
}
bcs = cs->bcs + ch;
switch (bcs->proto2) {
case L2_HDLC:
bcs->rx_bufsize = SBUFSIZE;
break;
default: /* assume transparent */
bcs->rx_bufsize = TRANSBUFSIZE;
}
dev_kfree_skb(bcs->rx_skb);
gigaset_new_rx_skb(bcs);
if (!gigaset_add_event(cs, &bcs->at_state,
EV_ACCEPT, NULL, 0, NULL))
return -ENOMEM;
gigaset_schedule_event(cs);
break;
case ISDN_CMD_HANGUP:
gig_dbg(DEBUG_CMD, "ISDN_CMD_HANGUP");
if (ch >= cs->channels) {
dev_err(cs->dev,
"ISDN_CMD_HANGUP: invalid channel (%d)\n", ch);
return -EINVAL;
}
bcs = cs->bcs + ch;
if (!gigaset_add_event(cs, &bcs->at_state,
EV_HUP, NULL, 0, NULL))
return -ENOMEM;
gigaset_schedule_event(cs);
break;
case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */
dev_info(cs->dev, "ignoring ISDN_CMD_CLREAZ\n");
break;
case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */
dev_info(cs->dev, "ignoring ISDN_CMD_SETEAZ (%s)\n",
cntrl->parm.num);
break;
case ISDN_CMD_SETL2: /* Set L2 to given protocol */
if (ch >= cs->channels) {
dev_err(cs->dev,
"ISDN_CMD_SETL2: invalid channel (%d)\n", ch);
return -EINVAL;
}
bcs = cs->bcs + ch;
if (bcs->chstate & CHS_D_UP) {
dev_err(cs->dev,
"ISDN_CMD_SETL2: channel active (%d)\n", ch);
return -EINVAL;
}
switch (cntrl->arg >> 8) {
case ISDN_PROTO_L2_HDLC:
gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_HDLC");
bcs->proto2 = L2_HDLC;
break;
case ISDN_PROTO_L2_TRANS:
gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_VOICE");
bcs->proto2 = L2_VOICE;
break;
default:
dev_err(cs->dev,
"ISDN_CMD_SETL2: unsupported protocol (%lu)\n",
cntrl->arg >> 8);
return -EINVAL;
}
break;
case ISDN_CMD_SETL3: /* Set L3 to given protocol */
gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL3");
if (ch >= cs->channels) {
dev_err(cs->dev,
"ISDN_CMD_SETL3: invalid channel (%d)\n", ch);
return -EINVAL;
}
if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) {
dev_err(cs->dev,
"ISDN_CMD_SETL3: unsupported protocol (%lu)\n",
cntrl->arg >> 8);
return -EINVAL;
}
break;
default:
gig_dbg(DEBUG_CMD, "unknown command %d from LL",
cntrl->command);
return -EINVAL;
}
return retval;
oom:
dev_err(bcs->cs->dev, "out of memory\n");
for (i = 0; i < AT_NUM; ++i)
kfree(commands[i]);
kfree(commands);
gigaset_free_channel(bcs);
return -ENOMEM;
}
static void gigaset_i4l_cmd(struct cardstate *cs, int cmd)
{
isdn_if *iif = cs->iif;
isdn_ctrl command;
command.driver = cs->myid;
command.command = cmd;
command.arg = 0;
iif->statcallb(&command);
}
static void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd)
{
isdn_if *iif = bcs->cs->iif;
isdn_ctrl command;
command.driver = bcs->cs->myid;
command.command = cmd;
command.arg = bcs->channel;
iif->statcallb(&command);
}
/**
* gigaset_isdn_icall() - signal incoming call
* @at_state: connection state structure.
*
* Called by main module to notify the LL that an incoming call has been
* received. @at_state contains the parameters of the call.
*
* Return value: call disposition (ICALL_*)
*/
int gigaset_isdn_icall(struct at_state_t *at_state)
{
struct cardstate *cs = at_state->cs;
struct bc_state *bcs = at_state->bcs;
isdn_if *iif = cs->iif;
isdn_ctrl response;
int retval;
/* fill ICALL structure */
response.parm.setup.si1 = 0; /* default: unknown */
response.parm.setup.si2 = 0;
response.parm.setup.screen = 0;
response.parm.setup.plan = 0;
if (!at_state->str_var[STR_ZBC]) {
/* no BC (internal call): assume speech, A-law */
response.parm.setup.si1 = 1;
} else if (!strcmp(at_state->str_var[STR_ZBC], "8890")) {
/* unrestricted digital information */
response.parm.setup.si1 = 7;
} else if (!strcmp(at_state->str_var[STR_ZBC], "8090A3")) {
/* speech, A-law */
response.parm.setup.si1 = 1;
} else if (!strcmp(at_state->str_var[STR_ZBC], "9090A3")) {
/* 3,1 kHz audio, A-law */
response.parm.setup.si1 = 1;
response.parm.setup.si2 = 2;
} else {
dev_warn(cs->dev, "RING ignored - unsupported BC %s\n",
at_state->str_var[STR_ZBC]);
return ICALL_IGNORE;
}
if (at_state->str_var[STR_NMBR]) {
strlcpy(response.parm.setup.phone, at_state->str_var[STR_NMBR],
sizeof response.parm.setup.phone);
} else
response.parm.setup.phone[0] = 0;
if (at_state->str_var[STR_ZCPN]) {
strlcpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN],
sizeof response.parm.setup.eazmsn);
} else
response.parm.setup.eazmsn[0] = 0;
if (!bcs) {
dev_notice(cs->dev, "no channel for incoming call\n");
response.command = ISDN_STAT_ICALLW;
response.arg = 0;
} else {
gig_dbg(DEBUG_CMD, "Sending ICALL");
response.command = ISDN_STAT_ICALL;
response.arg = bcs->channel;
}
response.driver = cs->myid;
retval = iif->statcallb(&response);
gig_dbg(DEBUG_CMD, "Response: %d", retval);
switch (retval) {
case 0: /* no takers */
return ICALL_IGNORE;
case 1: /* alerting */
bcs->chstate |= CHS_NOTIFY_LL;
return ICALL_ACCEPT;
case 2: /* reject */
return ICALL_REJECT;
case 3: /* incomplete */
dev_warn(cs->dev,
"LL requested unsupported feature: Incomplete Number\n");
return ICALL_IGNORE;
case 4: /* proceeding */
/* Gigaset will send ALERTING anyway.
* There doesn't seem to be a way to avoid this.
*/
return ICALL_ACCEPT;
case 5: /* deflect */
dev_warn(cs->dev,
"LL requested unsupported feature: Call Deflection\n");
return ICALL_IGNORE;
default:
dev_err(cs->dev, "LL error %d on ICALL\n", retval);
return ICALL_IGNORE;
}
}
/**
* gigaset_isdn_connD() - signal D channel connect
* @bcs: B channel descriptor structure.
*
* Called by main module to notify the LL that the D channel connection has
* been established.
*/
void gigaset_isdn_connD(struct bc_state *bcs)
{
gig_dbg(DEBUG_CMD, "sending DCONN");
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
}
/**
* gigaset_isdn_hupD() - signal D channel hangup
* @bcs: B channel descriptor structure.
*
* Called by main module to notify the LL that the D channel connection has
* been shut down.
*/
void gigaset_isdn_hupD(struct bc_state *bcs)
{
gig_dbg(DEBUG_CMD, "sending DHUP");
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP);
}
/**
* gigaset_isdn_connB() - signal B channel connect
* @bcs: B channel descriptor structure.
*
* Called by main module to notify the LL that the B channel connection has
* been established.
*/
void gigaset_isdn_connB(struct bc_state *bcs)
{
gig_dbg(DEBUG_CMD, "sending BCONN");
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN);
}
/**
* gigaset_isdn_hupB() - signal B channel hangup
* @bcs: B channel descriptor structure.
*
* Called by main module to notify the LL that the B channel connection has
* been shut down.
*/
void gigaset_isdn_hupB(struct bc_state *bcs)
{
gig_dbg(DEBUG_CMD, "sending BHUP");
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP);
}
/**
* gigaset_isdn_start() - signal device availability
* @cs: device descriptor structure.
*
* Called by main module to notify the LL that the device is available for
* use.
*/
void gigaset_isdn_start(struct cardstate *cs)
{
gig_dbg(DEBUG_CMD, "sending RUN");
gigaset_i4l_cmd(cs, ISDN_STAT_RUN);
}
/**
* gigaset_isdn_stop() - signal device unavailability
* @cs: device descriptor structure.
*
* Called by main module to notify the LL that the device is no longer
* available for use.
*/
void gigaset_isdn_stop(struct cardstate *cs)
{
gig_dbg(DEBUG_CMD, "sending STOP");
gigaset_i4l_cmd(cs, ISDN_STAT_STOP);
}
/**
* gigaset_isdn_regdev() - register to LL
* @cs: device descriptor structure.
* @isdnid: device name.
*
* Return value: 0 on success, error code < 0 on failure
*/
int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
{
isdn_if *iif;
iif = kmalloc(sizeof *iif, GFP_KERNEL);
if (!iif) {
pr_err("out of memory\n");
return -ENOMEM;
}
if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index)
>= sizeof iif->id) {
pr_err("ID too long: %s\n", isdnid);
kfree(iif);
return -EINVAL;
}
iif->owner = THIS_MODULE;
iif->channels = cs->channels;
iif->maxbufsize = MAX_BUF_SIZE;
iif->features = ISDN_FEATURE_L2_TRANS |
ISDN_FEATURE_L2_HDLC |
ISDN_FEATURE_L2_X75I |
ISDN_FEATURE_L3_TRANS |
ISDN_FEATURE_P_EURO;
iif->hl_hdrlen = HW_HDR_LEN; /* Area for storing ack */
iif->command = command_from_LL;
iif->writebuf_skb = writebuf_from_LL;
iif->writecmd = NULL; /* Don't support isdnctrl */
iif->readstat = NULL; /* Don't support isdnctrl */
iif->rcvcallb_skb = NULL; /* Will be set by LL */
iif->statcallb = NULL; /* Will be set by LL */
if (!register_isdn(iif)) {
pr_err("register_isdn failed\n");
kfree(iif);
return -EINVAL;
}
cs->iif = iif;
cs->myid = iif->channels; /* Set my device id */
cs->hw_hdr_len = HW_HDR_LEN;
return 0;
}
/**
* gigaset_isdn_unregdev() - unregister device from LL
* @cs: device descriptor structure.
*/
void gigaset_isdn_unregdev(struct cardstate *cs)
{
gig_dbg(DEBUG_CMD, "sending UNLOAD");
gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
kfree(cs->iif);
cs->iif = NULL;
}
/**
* gigaset_isdn_regdrv() - register driver to LL
*/
void gigaset_isdn_regdrv(void)
{
pr_info("ISDN4Linux interface\n");
/* nothing to do */
}
/**
* gigaset_isdn_unregdrv() - unregister driver from LL
*/
void gigaset_isdn_unregdrv(void)
{
/* nothing to do */
}

View file

@ -1,616 +0,0 @@
/*
* interface to user space for the gigaset driver
*
* Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de>
*
* =====================================================================
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
*/
#include "gigaset.h"
#include <linux/gigaset_dev.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
/*** our ioctls ***/
static int if_lock(struct cardstate *cs, int *arg)
{
int cmd = *arg;
gig_dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd);
if (cmd > 1)
return -EINVAL;
if (cmd < 0) {
*arg = cs->mstate == MS_LOCKED;
return 0;
}
if (!cmd && cs->mstate == MS_LOCKED && cs->connected) {
cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR | TIOCM_RTS);
cs->ops->baud_rate(cs, B115200);
cs->ops->set_line_ctrl(cs, CS8);
cs->control_state = TIOCM_DTR | TIOCM_RTS;
}
cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK,
NULL, cmd, NULL)) {
cs->waiting = 0;
return -ENOMEM;
}
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
if (cs->cmd_result >= 0) {
*arg = cs->cmd_result;
return 0;
}
return cs->cmd_result;
}
static int if_version(struct cardstate *cs, unsigned arg[4])
{
static const unsigned version[4] = GIG_VERSION;
static const unsigned compat[4] = GIG_COMPAT;
unsigned cmd = arg[0];
gig_dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd);
switch (cmd) {
case GIGVER_DRIVER:
memcpy(arg, version, sizeof version);
return 0;
case GIGVER_COMPAT:
memcpy(arg, compat, sizeof compat);
return 0;
case GIGVER_FWBASE:
cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER,
NULL, 0, arg)) {
cs->waiting = 0;
return -ENOMEM;
}
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
if (cs->cmd_result >= 0)
return 0;
return cs->cmd_result;
default:
return -EINVAL;
}
}
static int if_config(struct cardstate *cs, int *arg)
{
gig_dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg);
if (*arg != 1)
return -EINVAL;
if (cs->mstate != MS_LOCKED)
return -EBUSY;
if (!cs->connected) {
pr_err("%s: not connected\n", __func__);
return -ENODEV;
}
*arg = 0;
return gigaset_enterconfigmode(cs);
}
/*** the terminal driver ***/
static int if_open(struct tty_struct *tty, struct file *filp)
{
struct cardstate *cs;
gig_dbg(DEBUG_IF, "%d+%d: %s()",
tty->driver->minor_start, tty->index, __func__);
cs = gigaset_get_cs_by_tty(tty);
if (!cs || !try_module_get(cs->driver->owner))
return -ENODEV;
if (mutex_lock_interruptible(&cs->mutex)) {
module_put(cs->driver->owner);
return -ERESTARTSYS;
}
tty->driver_data = cs;
++cs->port.count;
if (cs->port.count == 1) {
tty_port_tty_set(&cs->port, tty);
cs->port.low_latency = 1;
}
mutex_unlock(&cs->mutex);
return 0;
}
static void if_close(struct tty_struct *tty, struct file *filp)
{
struct cardstate *cs = tty->driver_data;
if (!cs) { /* happens if we didn't find cs in open */
gig_dbg(DEBUG_IF, "%s: no cardstate", __func__);
return;
}
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
mutex_lock(&cs->mutex);
if (!cs->connected)
gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */
else if (!cs->port.count)
dev_warn(cs->dev, "%s: device not opened\n", __func__);
else if (!--cs->port.count)
tty_port_tty_set(&cs->port, NULL);
mutex_unlock(&cs->mutex);
module_put(cs->driver->owner);
}
static int if_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct cardstate *cs = tty->driver_data;
int retval = -ENODEV;
int int_arg;
unsigned char buf[6];
unsigned version[4];
gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS;
if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected");
retval = -ENODEV;
} else {
retval = 0;
switch (cmd) {
case GIGASET_REDIR:
retval = get_user(int_arg, (int __user *) arg);
if (retval >= 0)
retval = if_lock(cs, &int_arg);
if (retval >= 0)
retval = put_user(int_arg, (int __user *) arg);
break;
case GIGASET_CONFIG:
retval = get_user(int_arg, (int __user *) arg);
if (retval >= 0)
retval = if_config(cs, &int_arg);
if (retval >= 0)
retval = put_user(int_arg, (int __user *) arg);
break;
case GIGASET_BRKCHARS:
retval = copy_from_user(&buf,
(const unsigned char __user *) arg, 6)
? -EFAULT : 0;
if (retval >= 0) {
gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
6, buf);
retval = cs->ops->brkchars(cs, buf);
}
break;
case GIGASET_VERSION:
retval = copy_from_user(version,
(unsigned __user *) arg, sizeof version)
? -EFAULT : 0;
if (retval >= 0)
retval = if_version(cs, version);
if (retval >= 0)
retval = copy_to_user((unsigned __user *) arg,
version, sizeof version)
? -EFAULT : 0;
break;
default:
gig_dbg(DEBUG_IF, "%s: arg not supported - 0x%04x",
__func__, cmd);
retval = -ENOIOCTLCMD;
}
}
mutex_unlock(&cs->mutex);
return retval;
}
#ifdef CONFIG_COMPAT
static long if_compat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
return if_ioctl(tty, cmd, (unsigned long)compat_ptr(arg));
}
#endif
static int if_tiocmget(struct tty_struct *tty)
{
struct cardstate *cs = tty->driver_data;
int retval;
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS;
retval = cs->control_state & (TIOCM_RTS | TIOCM_DTR);
mutex_unlock(&cs->mutex);
return retval;
}
static int if_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct cardstate *cs = tty->driver_data;
int retval;
unsigned mc;
gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)",
cs->minor_index, __func__, set, clear);
if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS;
if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected");
retval = -ENODEV;
} else {
mc = (cs->control_state | set) & ~clear & (TIOCM_RTS | TIOCM_DTR);
retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc);
cs->control_state = mc;
}
mutex_unlock(&cs->mutex);
return retval;
}
static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
struct cardstate *cs = tty->driver_data;
struct cmdbuf_t *cb;
int retval;
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS;
if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected");
retval = -ENODEV;
goto done;
}
if (cs->mstate != MS_LOCKED) {
dev_warn(cs->dev, "can't write to unlocked device\n");
retval = -EBUSY;
goto done;
}
if (count <= 0) {
/* nothing to do */
retval = 0;
goto done;
}
cb = kmalloc(sizeof(struct cmdbuf_t) + count, GFP_KERNEL);
if (!cb) {
dev_err(cs->dev, "%s: out of memory\n", __func__);
retval = -ENOMEM;
goto done;
}
memcpy(cb->buf, buf, count);
cb->len = count;
cb->offset = 0;
cb->next = NULL;
cb->wake_tasklet = &cs->if_wake_tasklet;
retval = cs->ops->write_cmd(cs, cb);
done:
mutex_unlock(&cs->mutex);
return retval;
}
static int if_write_room(struct tty_struct *tty)
{
struct cardstate *cs = tty->driver_data;
int retval;
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS;
if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected");
retval = -ENODEV;
} else if (cs->mstate != MS_LOCKED) {
dev_warn(cs->dev, "can't write to unlocked device\n");
retval = -EBUSY;
} else
retval = cs->ops->write_room(cs);
mutex_unlock(&cs->mutex);
return retval;
}
static int if_chars_in_buffer(struct tty_struct *tty)
{
struct cardstate *cs = tty->driver_data;
int retval = 0;
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
mutex_lock(&cs->mutex);
if (!cs->connected)
gig_dbg(DEBUG_IF, "not connected");
else if (cs->mstate != MS_LOCKED)
dev_warn(cs->dev, "can't write to unlocked device\n");
else
retval = cs->ops->chars_in_buffer(cs);
mutex_unlock(&cs->mutex);
return retval;
}
static void if_throttle(struct tty_struct *tty)
{
struct cardstate *cs = tty->driver_data;
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
mutex_lock(&cs->mutex);
if (!cs->connected)
gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */
else
gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
mutex_unlock(&cs->mutex);
}
static void if_unthrottle(struct tty_struct *tty)
{
struct cardstate *cs = tty->driver_data;
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
mutex_lock(&cs->mutex);
if (!cs->connected)
gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */
else
gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
mutex_unlock(&cs->mutex);
}
static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
{
struct cardstate *cs = tty->driver_data;
unsigned int iflag;
unsigned int cflag;
unsigned int old_cflag;
unsigned int control_state, new_state;
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
mutex_lock(&cs->mutex);
if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected");
goto out;
}
iflag = tty->termios.c_iflag;
cflag = tty->termios.c_cflag;
old_cflag = old ? old->c_cflag : cflag;
gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
cs->minor_index, iflag, cflag, old_cflag);
/* get a local copy of the current port settings */
control_state = cs->control_state;
/*
* Update baud rate.
* Do not attempt to cache old rates and skip settings,
* disconnects screw such tricks up completely.
* Premature optimization is the root of all evil.
*/
/* reassert DTR and (maybe) RTS on transition from B0 */
if ((old_cflag & CBAUD) == B0) {
new_state = control_state | TIOCM_DTR;
/* don't set RTS if using hardware flow control */
if (!(old_cflag & CRTSCTS))
new_state |= TIOCM_RTS;
gig_dbg(DEBUG_IF, "%u: from B0 - set DTR%s",
cs->minor_index,
(new_state & TIOCM_RTS) ? " only" : "/RTS");
cs->ops->set_modem_ctrl(cs, control_state, new_state);
control_state = new_state;
}
cs->ops->baud_rate(cs, cflag & CBAUD);
if ((cflag & CBAUD) == B0) {
/* Drop RTS and DTR */
gig_dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index);
new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS);
cs->ops->set_modem_ctrl(cs, control_state, new_state);
control_state = new_state;
}
/*
* Update line control register (LCR)
*/
cs->ops->set_line_ctrl(cs, cflag);
/* save off the modified port settings */
cs->control_state = control_state;
out:
mutex_unlock(&cs->mutex);
}
static const struct tty_operations if_ops = {
.open = if_open,
.close = if_close,
.ioctl = if_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = if_compat_ioctl,
#endif
.write = if_write,
.write_room = if_write_room,
.chars_in_buffer = if_chars_in_buffer,
.set_termios = if_set_termios,
.throttle = if_throttle,
.unthrottle = if_unthrottle,
.tiocmget = if_tiocmget,
.tiocmset = if_tiocmset,
};
/* wakeup tasklet for the write operation */
static void if_wake(unsigned long data)
{
struct cardstate *cs = (struct cardstate *)data;
tty_port_tty_wakeup(&cs->port);
}
/*** interface to common ***/
void gigaset_if_init(struct cardstate *cs)
{
struct gigaset_driver *drv;
drv = cs->driver;
if (!drv->have_tty)
return;
tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs);
mutex_lock(&cs->mutex);
cs->tty_dev = tty_port_register_device(&cs->port, drv->tty,
cs->minor_index, NULL);
if (!IS_ERR(cs->tty_dev))
dev_set_drvdata(cs->tty_dev, cs);
else {
pr_warning("could not register device to the tty subsystem\n");
cs->tty_dev = NULL;
}
mutex_unlock(&cs->mutex);
}
void gigaset_if_free(struct cardstate *cs)
{
struct gigaset_driver *drv;
drv = cs->driver;
if (!drv->have_tty)
return;
tasklet_disable(&cs->if_wake_tasklet);
tasklet_kill(&cs->if_wake_tasklet);
cs->tty_dev = NULL;
tty_unregister_device(drv->tty, cs->minor_index);
}
/**
* gigaset_if_receive() - pass a received block of data to the tty device
* @cs: device descriptor structure.
* @buffer: received data.
* @len: number of bytes received.
*
* Called by asyncdata/isocdata if a block of data received from the
* device must be sent to userspace through the ttyG* device.
*/
void gigaset_if_receive(struct cardstate *cs,
unsigned char *buffer, size_t len)
{
tty_insert_flip_string(&cs->port, buffer, len);
tty_flip_buffer_push(&cs->port);
}
EXPORT_SYMBOL_GPL(gigaset_if_receive);
/* gigaset_if_initdriver
* Initialize tty interface.
* parameters:
* drv Driver
* procname Name of the driver (e.g. for /proc/tty/drivers)
* devname Name of the device files (prefix without minor number)
*/
void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
const char *devname)
{
int ret;
struct tty_driver *tty;
drv->have_tty = 0;
drv->tty = tty = alloc_tty_driver(drv->minors);
if (tty == NULL)
goto enomem;
tty->type = TTY_DRIVER_TYPE_SERIAL;
tty->subtype = SERIAL_TYPE_NORMAL;
tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty->driver_name = procname;
tty->name = devname;
tty->minor_start = drv->minor;
tty->init_termios = tty_std_termios;
tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(tty, &if_ops);
ret = tty_register_driver(tty);
if (ret < 0) {
pr_err("error %d registering tty driver\n", ret);
goto error;
}
gig_dbg(DEBUG_IF, "tty driver initialized");
drv->have_tty = 1;
return;
enomem:
pr_err("out of memory\n");
error:
if (drv->tty)
put_tty_driver(drv->tty);
}
void gigaset_if_freedriver(struct gigaset_driver *drv)
{
if (!drv->have_tty)
return;
drv->have_tty = 0;
tty_unregister_driver(drv->tty);
put_tty_driver(drv->tty);
}

File diff suppressed because it is too large Load diff

View file

@ -1,80 +0,0 @@
/*
* Stuff used by all variants of the driver
*
* Copyright (c) 2001 by Stefan Eilers,
* Hansjoerg Lipp <hjlipp@web.de>,
* Tilman Schmidt <tilman@imap.cc>.
*
* =====================================================================
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
*/
#include "gigaset.h"
static ssize_t show_cidmode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cardstate *cs = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", cs->cidmode);
}
static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cardstate *cs = dev_get_drvdata(dev);
long int value;
char *end;
value = simple_strtol(buf, &end, 0);
while (*end)
if (!isspace(*end++))
return -EINVAL;
if (value < 0 || value > 1)
return -EINVAL;
if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS;
cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_PROC_CIDMODE,
NULL, value, NULL)) {
cs->waiting = 0;
mutex_unlock(&cs->mutex);
return -ENOMEM;
}
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
mutex_unlock(&cs->mutex);
return count;
}
static DEVICE_ATTR(cidmode, S_IRUGO | S_IWUSR, show_cidmode, set_cidmode);
/* free sysfs for device */
void gigaset_free_dev_sysfs(struct cardstate *cs)
{
if (!cs->tty_dev)
return;
gig_dbg(DEBUG_INIT, "removing sysfs entries");
device_remove_file(cs->tty_dev, &dev_attr_cidmode);
}
/* initialize sysfs for device */
void gigaset_init_dev_sysfs(struct cardstate *cs)
{
if (!cs->tty_dev)
return;
gig_dbg(DEBUG_INIT, "setting up sysfs");
if (device_create_file(cs->tty_dev, &dev_attr_cidmode))
pr_err("could not create sysfs attribute\n");
}

View file

@ -1,799 +0,0 @@
/* This is the serial hardware link layer (HLL) for the Gigaset 307x isdn
* DECT base (aka Sinus 45 isdn) using the RS232 DECT data module M101,
* written as a line discipline.
*
* =====================================================================
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
*/
#include "gigaset.h"
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/completion.h>
/* Version Information */
#define DRIVER_AUTHOR "Tilman Schmidt"
#define DRIVER_DESC "Serial Driver for Gigaset 307x using Siemens M101"
#define GIGASET_MINORS 1
#define GIGASET_MINOR 0
#define GIGASET_MODULENAME "ser_gigaset"
#define GIGASET_DEVNAME "ttyGS"
/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */
#define IF_WRITEBUF 264
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_GIGASET_M101);
static int startmode = SM_ISDN;
module_param(startmode, int, S_IRUGO);
MODULE_PARM_DESC(startmode, "initial operation mode");
static int cidmode = 1;
module_param(cidmode, int, S_IRUGO);
MODULE_PARM_DESC(cidmode, "stay in CID mode when idle");
static struct gigaset_driver *driver;
struct ser_cardstate {
struct platform_device dev;
struct tty_struct *tty;
atomic_t refcnt;
struct completion dead_cmp;
};
static struct platform_driver device_driver = {
.driver = {
.name = GIGASET_MODULENAME,
},
};
static void flush_send_queue(struct cardstate *);
/* transmit data from current open skb
* result: number of bytes sent or error code < 0
*/
static int write_modem(struct cardstate *cs)
{
struct tty_struct *tty = cs->hw.ser->tty;
struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
struct sk_buff *skb = bcs->tx_skb;
int sent = -EOPNOTSUPP;
WARN_ON(!tty || !tty->ops || !skb);
if (!skb->len) {
dev_kfree_skb_any(skb);
bcs->tx_skb = NULL;
return -EINVAL;
}
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
if (tty->ops->write)
sent = tty->ops->write(tty, skb->data, skb->len);
gig_dbg(DEBUG_OUTPUT, "write_modem: sent %d", sent);
if (sent < 0) {
/* error */
flush_send_queue(cs);
return sent;
}
skb_pull(skb, sent);
if (!skb->len) {
/* skb sent completely */
gigaset_skb_sent(bcs, skb);
gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!",
(unsigned long) skb);
dev_kfree_skb_any(skb);
bcs->tx_skb = NULL;
}
return sent;
}
/*
* transmit first queued command buffer
* result: number of bytes sent or error code < 0
*/
static int send_cb(struct cardstate *cs)
{
struct tty_struct *tty = cs->hw.ser->tty;
struct cmdbuf_t *cb, *tcb;
unsigned long flags;
int sent = 0;
WARN_ON(!tty || !tty->ops);
cb = cs->cmdbuf;
if (!cb)
return 0; /* nothing to do */
if (cb->len) {
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
sent = tty->ops->write(tty, cb->buf + cb->offset, cb->len);
if (sent < 0) {
/* error */
gig_dbg(DEBUG_OUTPUT, "send_cb: write error %d", sent);
flush_send_queue(cs);
return sent;
}
cb->offset += sent;
cb->len -= sent;
gig_dbg(DEBUG_OUTPUT, "send_cb: sent %d, left %u, queued %u",
sent, cb->len, cs->cmdbytes);
}
while (cb && !cb->len) {
spin_lock_irqsave(&cs->cmdlock, flags);
cs->cmdbytes -= cs->curlen;
tcb = cb;
cs->cmdbuf = cb = cb->next;
if (cb) {
cb->prev = NULL;
cs->curlen = cb->len;
} else {
cs->lastcmdbuf = NULL;
cs->curlen = 0;
}
spin_unlock_irqrestore(&cs->cmdlock, flags);
if (tcb->wake_tasklet)
tasklet_schedule(tcb->wake_tasklet);
kfree(tcb);
}
return sent;
}
/*
* send queue tasklet
* If there is already a skb opened, put data to the transfer buffer
* by calling "write_modem".
* Otherwise take a new skb out of the queue.
*/
static void gigaset_modem_fill(unsigned long data)
{
struct cardstate *cs = (struct cardstate *) data;
struct bc_state *bcs;
struct sk_buff *nextskb;
int sent = 0;
if (!cs) {
gig_dbg(DEBUG_OUTPUT, "%s: no cardstate", __func__);
return;
}
bcs = cs->bcs;
if (!bcs) {
gig_dbg(DEBUG_OUTPUT, "%s: no cardstate", __func__);
return;
}
if (!bcs->tx_skb) {
/* no skb is being sent; send command if any */
sent = send_cb(cs);
gig_dbg(DEBUG_OUTPUT, "%s: send_cb -> %d", __func__, sent);
if (sent)
/* something sent or error */
return;
/* no command to send; get skb */
nextskb = skb_dequeue(&bcs->squeue);
if (!nextskb)
/* no skb either, nothing to do */
return;
bcs->tx_skb = nextskb;
gig_dbg(DEBUG_INTR, "Dequeued skb (Adr: %lx)",
(unsigned long) bcs->tx_skb);
}
/* send skb */
gig_dbg(DEBUG_OUTPUT, "%s: tx_skb", __func__);
if (write_modem(cs) < 0)
gig_dbg(DEBUG_OUTPUT, "%s: write_modem failed", __func__);
}
/*
* throw away all data queued for sending
*/
static void flush_send_queue(struct cardstate *cs)
{
struct sk_buff *skb;
struct cmdbuf_t *cb;
unsigned long flags;
/* command queue */
spin_lock_irqsave(&cs->cmdlock, flags);
while ((cb = cs->cmdbuf) != NULL) {
cs->cmdbuf = cb->next;
if (cb->wake_tasklet)
tasklet_schedule(cb->wake_tasklet);
kfree(cb);
}
cs->cmdbuf = cs->lastcmdbuf = NULL;
cs->cmdbytes = cs->curlen = 0;
spin_unlock_irqrestore(&cs->cmdlock, flags);
/* data queue */
if (cs->bcs->tx_skb)
dev_kfree_skb_any(cs->bcs->tx_skb);
while ((skb = skb_dequeue(&cs->bcs->squeue)) != NULL)
dev_kfree_skb_any(skb);
}
/* Gigaset Driver Interface */
/* ======================== */
/*
* queue an AT command string for transmission to the Gigaset device
* parameters:
* cs controller state structure
* buf buffer containing the string to send
* len number of characters to send
* wake_tasklet tasklet to run when transmission is complete, or NULL
* return value:
* number of bytes queued, or error code < 0
*/
static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
{
unsigned long flags;
gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
"CMD Transmit", cb->len, cb->buf);
spin_lock_irqsave(&cs->cmdlock, flags);
cb->prev = cs->lastcmdbuf;
if (cs->lastcmdbuf)
cs->lastcmdbuf->next = cb;
else {
cs->cmdbuf = cb;
cs->curlen = cb->len;
}
cs->cmdbytes += cb->len;
cs->lastcmdbuf = cb;
spin_unlock_irqrestore(&cs->cmdlock, flags);
spin_lock_irqsave(&cs->lock, flags);
if (cs->connected)
tasklet_schedule(&cs->write_tasklet);
spin_unlock_irqrestore(&cs->lock, flags);
return cb->len;
}
/*
* tty_driver.write_room interface routine
* return number of characters the driver will accept to be written
* parameter:
* controller state structure
* return value:
* number of characters
*/
static int gigaset_write_room(struct cardstate *cs)
{
unsigned bytes;
bytes = cs->cmdbytes;
return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0;
}
/*
* tty_driver.chars_in_buffer interface routine
* return number of characters waiting to be sent
* parameter:
* controller state structure
* return value:
* number of characters
*/
static int gigaset_chars_in_buffer(struct cardstate *cs)
{
return cs->cmdbytes;
}
/*
* implementation of ioctl(GIGASET_BRKCHARS)
* parameter:
* controller state structure
* return value:
* -EINVAL (unimplemented function)
*/
static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
{
/* not implemented */
return -EINVAL;
}
/*
* Open B channel
* Called by "do_action" in ev-layer.c
*/
static int gigaset_init_bchannel(struct bc_state *bcs)
{
/* nothing to do for M10x */
gigaset_bchannel_up(bcs);
return 0;
}
/*
* Close B channel
* Called by "do_action" in ev-layer.c
*/
static int gigaset_close_bchannel(struct bc_state *bcs)
{
/* nothing to do for M10x */
gigaset_bchannel_down(bcs);
return 0;
}
/*
* Set up B channel structure
* This is called by "gigaset_initcs" in common.c
*/
static int gigaset_initbcshw(struct bc_state *bcs)
{
/* unused */
bcs->hw.ser = NULL;
return 0;
}
/*
* Free B channel structure
* Called by "gigaset_freebcs" in common.c
*/
static void gigaset_freebcshw(struct bc_state *bcs)
{
/* unused */
}
/*
* Reinitialize B channel structure
* This is called by "bcs_reinit" in common.c
*/
static void gigaset_reinitbcshw(struct bc_state *bcs)
{
/* nothing to do for M10x */
}
/*
* Free hardware specific device data
* This will be called by "gigaset_freecs" in common.c
*/
static void gigaset_freecshw(struct cardstate *cs)
{
tasklet_kill(&cs->write_tasklet);
if (!cs->hw.ser)
return;
platform_device_unregister(&cs->hw.ser->dev);
}
static void gigaset_device_release(struct device *dev)
{
kfree(container_of(dev, struct ser_cardstate, dev.dev));
}
/*
* Set up hardware specific device data
* This is called by "gigaset_initcs" in common.c
*/
static int gigaset_initcshw(struct cardstate *cs)
{
int rc;
struct ser_cardstate *scs;
scs = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL);
if (!scs) {
pr_err("out of memory\n");
return -ENOMEM;
}
cs->hw.ser = scs;
cs->hw.ser->dev.name = GIGASET_MODULENAME;
cs->hw.ser->dev.id = cs->minor_index;
cs->hw.ser->dev.dev.release = gigaset_device_release;
rc = platform_device_register(&cs->hw.ser->dev);
if (rc != 0) {
pr_err("error %d registering platform device\n", rc);
kfree(cs->hw.ser);
cs->hw.ser = NULL;
return rc;
}
tasklet_init(&cs->write_tasklet,
gigaset_modem_fill, (unsigned long) cs);
return 0;
}
/*
* set modem control lines
* Parameters:
* card state structure
* modem control line state ([TIOCM_DTR]|[TIOCM_RTS])
* Called by "gigaset_start" and "gigaset_enterconfigmode" in common.c
* and by "if_lock" and "if_termios" in interface.c
*/
static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
unsigned new_state)
{
struct tty_struct *tty = cs->hw.ser->tty;
unsigned int set, clear;
WARN_ON(!tty || !tty->ops);
/* tiocmset is an optional tty driver method */
if (!tty->ops->tiocmset)
return -EINVAL;
set = new_state & ~old_state;
clear = old_state & ~new_state;
if (!set && !clear)
return 0;
gig_dbg(DEBUG_IF, "tiocmset set %x clear %x", set, clear);
return tty->ops->tiocmset(tty, set, clear);
}
static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
{
return -EINVAL;
}
static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
{
return -EINVAL;
}
static const struct gigaset_ops ops = {
.write_cmd = gigaset_write_cmd,
.write_room = gigaset_write_room,
.chars_in_buffer = gigaset_chars_in_buffer,
.brkchars = gigaset_brkchars,
.init_bchannel = gigaset_init_bchannel,
.close_bchannel = gigaset_close_bchannel,
.initbcshw = gigaset_initbcshw,
.freebcshw = gigaset_freebcshw,
.reinitbcshw = gigaset_reinitbcshw,
.initcshw = gigaset_initcshw,
.freecshw = gigaset_freecshw,
.set_modem_ctrl = gigaset_set_modem_ctrl,
.baud_rate = gigaset_baud_rate,
.set_line_ctrl = gigaset_set_line_ctrl,
.send_skb = gigaset_m10x_send_skb, /* asyncdata.c */
.handle_input = gigaset_m10x_input, /* asyncdata.c */
};
/* Line Discipline Interface */
/* ========================= */
/* helper functions for cardstate refcounting */
static struct cardstate *cs_get(struct tty_struct *tty)
{
struct cardstate *cs = tty->disc_data;
if (!cs || !cs->hw.ser) {
gig_dbg(DEBUG_ANY, "%s: no cardstate", __func__);
return NULL;
}
atomic_inc(&cs->hw.ser->refcnt);
return cs;
}
static void cs_put(struct cardstate *cs)
{
if (atomic_dec_and_test(&cs->hw.ser->refcnt))
complete(&cs->hw.ser->dead_cmp);
}
/*
* Called by the tty driver when the line discipline is pushed onto the tty.
* Called in process context.
*/
static int
gigaset_tty_open(struct tty_struct *tty)
{
struct cardstate *cs;
int rc;
gig_dbg(DEBUG_INIT, "Starting HLL for Gigaset M101");
pr_info(DRIVER_DESC "\n");
if (!driver) {
pr_err("%s: no driver structure\n", __func__);
return -ENODEV;
}
/* allocate memory for our device state and initialize it */
cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
if (!cs) {
rc = -ENODEV;
goto error;
}
cs->dev = &cs->hw.ser->dev.dev;
cs->hw.ser->tty = tty;
atomic_set(&cs->hw.ser->refcnt, 1);
init_completion(&cs->hw.ser->dead_cmp);
tty->disc_data = cs;
/* Set the amount of data we're willing to receive per call
* from the hardware driver to half of the input buffer size
* to leave some reserve.
* Note: We don't do flow control towards the hardware driver.
* If more data is received than will fit into the input buffer,
* it will be dropped and an error will be logged. This should
* never happen as the device is slow and the buffer size ample.
*/
tty->receive_room = RBUFSIZE/2;
/* OK.. Initialization of the datastructures and the HW is done.. Now
* startup system and notify the LL that we are ready to run
*/
if (startmode == SM_LOCKED)
cs->mstate = MS_LOCKED;
rc = gigaset_start(cs);
if (rc < 0) {
tasklet_kill(&cs->write_tasklet);
goto error;
}
gig_dbg(DEBUG_INIT, "Startup of HLL done");
return 0;
error:
gig_dbg(DEBUG_INIT, "Startup of HLL failed");
tty->disc_data = NULL;
gigaset_freecs(cs);
return rc;
}
/*
* Called by the tty driver when the line discipline is removed.
* Called from process context.
*/
static void
gigaset_tty_close(struct tty_struct *tty)
{
struct cardstate *cs = tty->disc_data;
gig_dbg(DEBUG_INIT, "Stopping HLL for Gigaset M101");
if (!cs) {
gig_dbg(DEBUG_INIT, "%s: no cardstate", __func__);
return;
}
/* prevent other callers from entering ldisc methods */
tty->disc_data = NULL;
if (!cs->hw.ser)
pr_err("%s: no hw cardstate\n", __func__);
else {
/* wait for running methods to finish */
if (!atomic_dec_and_test(&cs->hw.ser->refcnt))
wait_for_completion(&cs->hw.ser->dead_cmp);
}
/* stop operations */
gigaset_stop(cs);
tasklet_kill(&cs->write_tasklet);
flush_send_queue(cs);
cs->dev = NULL;
gigaset_freecs(cs);
gig_dbg(DEBUG_INIT, "Shutdown of HLL done");
}
/*
* Called by the tty driver when the tty line is hung up.
* Wait for I/O to driver to complete and unregister ISDN device.
* This is already done by the close routine, so just call that.
* Called from process context.
*/
static int gigaset_tty_hangup(struct tty_struct *tty)
{
gigaset_tty_close(tty);
return 0;
}
/*
* Ioctl on the tty.
* Called in process context only.
* May be re-entered by multiple ioctl calling threads.
*/
static int
gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct cardstate *cs = cs_get(tty);
int rc, val;
int __user *p = (int __user *)arg;
if (!cs)
return -ENXIO;
switch (cmd) {
case FIONREAD:
/* unused, always return zero */
val = 0;
rc = put_user(val, p);
break;
case TCFLSH:
/* flush our buffers and the serial port's buffer */
switch (arg) {
case TCIFLUSH:
/* no own input buffer to flush */
break;
case TCIOFLUSH:
case TCOFLUSH:
flush_send_queue(cs);
break;
}
/* fall through */
default:
/* pass through to underlying serial device */
rc = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
}
cs_put(cs);
return rc;
}
/*
* Called by the tty driver when a block of data has been received.
* Will not be re-entered while running but other ldisc functions
* may be called in parallel.
* Can be called from hard interrupt level as well as soft interrupt
* level or mainline.
* Parameters:
* tty tty structure
* buf buffer containing received characters
* cflags buffer containing error flags for received characters (ignored)
* count number of received characters
*/
static void
gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
char *cflags, int count)
{
struct cardstate *cs = cs_get(tty);
unsigned tail, head, n;
struct inbuf_t *inbuf;
if (!cs)
return;
inbuf = cs->inbuf;
if (!inbuf) {
dev_err(cs->dev, "%s: no inbuf\n", __func__);
cs_put(cs);
return;
}
tail = inbuf->tail;
head = inbuf->head;
gig_dbg(DEBUG_INTR, "buffer state: %u -> %u, receive %u bytes",
head, tail, count);
if (head <= tail) {
/* possible buffer wraparound */
n = min_t(unsigned, count, RBUFSIZE - tail);
memcpy(inbuf->data + tail, buf, n);
tail = (tail + n) % RBUFSIZE;
buf += n;
count -= n;
}
if (count > 0) {
/* tail < head and some data left */
n = head - tail - 1;
if (count > n) {
dev_err(cs->dev,
"inbuf overflow, discarding %d bytes\n",
count - n);
count = n;
}
memcpy(inbuf->data + tail, buf, count);
tail += count;
}
gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
inbuf->tail = tail;
/* Everything was received .. Push data into handler */
gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
gigaset_schedule_event(cs);
cs_put(cs);
}
/*
* Called by the tty driver when there's room for more data to send.
*/
static void
gigaset_tty_wakeup(struct tty_struct *tty)
{
struct cardstate *cs = cs_get(tty);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
if (!cs)
return;
tasklet_schedule(&cs->write_tasklet);
cs_put(cs);
}
static struct tty_ldisc_ops gigaset_ldisc = {
.owner = THIS_MODULE,
.magic = TTY_LDISC_MAGIC,
.name = "ser_gigaset",
.open = gigaset_tty_open,
.close = gigaset_tty_close,
.hangup = gigaset_tty_hangup,
.ioctl = gigaset_tty_ioctl,
.receive_buf = gigaset_tty_receive,
.write_wakeup = gigaset_tty_wakeup,
};
/* Initialization / Shutdown */
/* ========================= */
static int __init ser_gigaset_init(void)
{
int rc;
gig_dbg(DEBUG_INIT, "%s", __func__);
rc = platform_driver_register(&device_driver);
if (rc != 0) {
pr_err("error %d registering platform driver\n", rc);
return rc;
}
/* allocate memory for our driver state and initialize it */
driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
GIGASET_MODULENAME, GIGASET_DEVNAME,
&ops, THIS_MODULE);
if (!driver) {
rc = -ENOMEM;
goto error;
}
rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc);
if (rc != 0) {
pr_err("error %d registering line discipline\n", rc);
goto error;
}
return 0;
error:
if (driver) {
gigaset_freedriver(driver);
driver = NULL;
}
platform_driver_unregister(&device_driver);
return rc;
}
static void __exit ser_gigaset_exit(void)
{
int rc;
gig_dbg(DEBUG_INIT, "%s", __func__);
if (driver) {
gigaset_freedriver(driver);
driver = NULL;
}
rc = tty_unregister_ldisc(N_GIGASET_M101);
if (rc != 0)
pr_err("error %d unregistering line discipline\n", rc);
platform_driver_unregister(&device_driver);
}
module_init(ser_gigaset_init);
module_exit(ser_gigaset_exit);

View file

@ -1,949 +0,0 @@
/*
* USB driver for Gigaset 307x directly or using M105 Data.
*
* Copyright (c) 2001 by Stefan Eilers
* and Hansjoerg Lipp <hjlipp@web.de>.
*
* This driver was derived from the USB skeleton driver by
* Greg Kroah-Hartman <greg@kroah.com>
*
* =====================================================================
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
*/
#include "gigaset.h"
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
/* Version Information */
#define DRIVER_AUTHOR "Hansjoerg Lipp <[email protected]>, Stefan Eilers"
#define DRIVER_DESC "USB Driver for Gigaset 307x using M105"
/* Module parameters */
static int startmode = SM_ISDN;
static int cidmode = 1;
module_param(startmode, int, S_IRUGO);
module_param(cidmode, int, S_IRUGO);
MODULE_PARM_DESC(startmode, "start in isdn4linux mode");
MODULE_PARM_DESC(cidmode, "Call-ID mode");
#define GIGASET_MINORS 1
#define GIGASET_MINOR 8
#define GIGASET_MODULENAME "usb_gigaset"
#define GIGASET_DEVNAME "ttyGU"
/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */
#define IF_WRITEBUF 264
/* Values for the Gigaset M105 Data */
#define USB_M105_VENDOR_ID 0x0681
#define USB_M105_PRODUCT_ID 0x0009
/* table of devices that work with this driver */
static const struct usb_device_id gigaset_table[] = {
{ USB_DEVICE(USB_M105_VENDOR_ID, USB_M105_PRODUCT_ID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, gigaset_table);
/*
* Control requests (empty fields: 00)
*
* RT|RQ|VALUE|INDEX|LEN |DATA
* In:
* C1 08 01
* Get flags (1 byte). Bits: 0=dtr,1=rts,3-7:?
* C1 0F ll ll
* Get device information/status (llll: 0x200 and 0x40 seen).
* Real size: I only saw MIN(llll,0x64).
* Contents: seems to be always the same...
* offset 0x00: Length of this structure (0x64) (len: 1,2,3 bytes)
* offset 0x3c: String (16 bit chars): "MCCI USB Serial V2.0"
* rest: ?
* Out:
* 41 11
* Initialize/reset device ?
* 41 00 xx 00
* ? (xx=00 or 01; 01 on start, 00 on close)
* 41 07 vv mm
* Set/clear flags vv=value, mm=mask (see RQ 08)
* 41 12 xx
* Used before the following configuration requests are issued
* (with xx=0x0f). I've seen other values<0xf, though.
* 41 01 xx xx
* Set baud rate. xxxx=ceil(0x384000/rate)=trunc(0x383fff/rate)+1.
* 41 03 ps bb
* Set byte size and parity. p: 0x20=even,0x10=odd,0x00=no parity
* [ 0x30: m, 0x40: s ]
* [s: 0: 1 stop bit; 1: 1.5; 2: 2]
* bb: bits/byte (seen 7 and 8)
* 41 13 -- -- -- -- 10 00 ww 00 00 00 xx 00 00 00 yy 00 00 00 zz 00 00 00
* ??
* Initialization: 01, 40, 00, 00
* Open device: 00 40, 00, 00
* yy and zz seem to be equal, either 0x00 or 0x0a
* (ww,xx) pairs seen: (00,00), (00,40), (01,40), (09,80), (19,80)
* 41 19 -- -- -- -- 06 00 00 00 00 xx 11 13
* Used after every "configuration sequence" (RQ 12, RQs 01/03/13).
* xx is usually 0x00 but was 0x7e before starting data transfer
* in unimodem mode. So, this might be an array of characters that
* need special treatment ("commit all bufferd data"?), 11=^Q, 13=^S.
*
* Unimodem mode: use "modprobe ppp_async flag_time=0" as the device _needs_ two
* flags per packet.
*/
/* functions called if a device of this driver is connected/disconnected */
static int gigaset_probe(struct usb_interface *interface,
const struct usb_device_id *id);
static void gigaset_disconnect(struct usb_interface *interface);
/* functions called before/after suspend */
static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
static int gigaset_resume(struct usb_interface *intf);
static int gigaset_pre_reset(struct usb_interface *intf);
static struct gigaset_driver *driver;
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver gigaset_usb_driver = {
.name = GIGASET_MODULENAME,
.probe = gigaset_probe,
.disconnect = gigaset_disconnect,
.id_table = gigaset_table,
.suspend = gigaset_suspend,
.resume = gigaset_resume,
.reset_resume = gigaset_resume,
.pre_reset = gigaset_pre_reset,
.post_reset = gigaset_resume,
.disable_hub_initiated_lpm = 1,
};
struct usb_cardstate {
struct usb_device *udev; /* usb device pointer */
struct usb_interface *interface; /* interface for this device */
int busy; /* bulk output in progress */
/* Output buffer */
unsigned char *bulk_out_buffer;
int bulk_out_size;
int bulk_out_epnum;
struct urb *bulk_out_urb;
/* Input buffer */
unsigned char *rcvbuf;
int rcvbuf_size;
struct urb *read_urb;
char bchars[6]; /* for request 0x19 */
};
static inline unsigned tiocm_to_gigaset(unsigned state)
{
return ((state & TIOCM_DTR) ? 1 : 0) | ((state & TIOCM_RTS) ? 2 : 0);
}
static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
unsigned new_state)
{
struct usb_device *udev = cs->hw.usb->udev;
unsigned mask, val;
int r;
mask = tiocm_to_gigaset(old_state ^ new_state);
val = tiocm_to_gigaset(new_state);
gig_dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask);
r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 7, 0x41,
(val & 0xff) | ((mask & 0xff) << 8), 0,
NULL, 0, 2000 /* timeout? */);
if (r < 0)
return r;
return 0;
}
/*
* Set M105 configuration value
* using undocumented device commands reverse engineered from USB traces
* of the Siemens Windows driver
*/
static int set_value(struct cardstate *cs, u8 req, u16 val)
{
struct usb_device *udev = cs->hw.usb->udev;
int r, r2;
gig_dbg(DEBUG_USBREQ, "request %02x (%04x)",
(unsigned)req, (unsigned)val);
r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x12, 0x41,
0xf /*?*/, 0, NULL, 0, 2000 /*?*/);
/* no idea what this does */
if (r < 0) {
dev_err(&udev->dev, "error %d on request 0x12\n", -r);
return r;
}
r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), req, 0x41,
val, 0, NULL, 0, 2000 /*?*/);
if (r < 0)
dev_err(&udev->dev, "error %d on request 0x%02x\n",
-r, (unsigned)req);
r2 = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41,
0, 0, cs->hw.usb->bchars, 6, 2000 /*?*/);
if (r2 < 0)
dev_err(&udev->dev, "error %d on request 0x19\n", -r2);
return r < 0 ? r : (r2 < 0 ? r2 : 0);
}
/*
* set the baud rate on the internal serial adapter
* using the undocumented parameter setting command
*/
static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
{
u16 val;
u32 rate;
cflag &= CBAUD;
switch (cflag) {
case B300: rate = 300; break;
case B600: rate = 600; break;
case B1200: rate = 1200; break;
case B2400: rate = 2400; break;
case B4800: rate = 4800; break;
case B9600: rate = 9600; break;
case B19200: rate = 19200; break;
case B38400: rate = 38400; break;
case B57600: rate = 57600; break;
case B115200: rate = 115200; break;
default:
rate = 9600;
dev_err(cs->dev, "unsupported baudrate request 0x%x,"
" using default of B9600\n", cflag);
}
val = 0x383fff / rate + 1;
return set_value(cs, 1, val);
}
/*
* set the line format on the internal serial adapter
* using the undocumented parameter setting command
*/
static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
{
u16 val = 0;
/* set the parity */
if (cflag & PARENB)
val |= (cflag & PARODD) ? 0x10 : 0x20;
/* set the number of data bits */
switch (cflag & CSIZE) {
case CS5:
val |= 5 << 8; break;
case CS6:
val |= 6 << 8; break;
case CS7:
val |= 7 << 8; break;
case CS8:
val |= 8 << 8; break;
default:
dev_err(cs->dev, "CSIZE was not CS5-CS8, using default of 8\n");
val |= 8 << 8;
break;
}
/* set the number of stop bits */
if (cflag & CSTOPB) {
if ((cflag & CSIZE) == CS5)
val |= 1; /* 1.5 stop bits */
else
val |= 2; /* 2 stop bits */
}
return set_value(cs, 3, val);
}
/*============================================================================*/
static int gigaset_init_bchannel(struct bc_state *bcs)
{
/* nothing to do for M10x */
gigaset_bchannel_up(bcs);
return 0;
}
static int gigaset_close_bchannel(struct bc_state *bcs)
{
/* nothing to do for M10x */
gigaset_bchannel_down(bcs);
return 0;
}
static int write_modem(struct cardstate *cs);
static int send_cb(struct cardstate *cs);
/* Write tasklet handler: Continue sending current skb, or send command, or
* start sending an skb from the send queue.
*/
static void gigaset_modem_fill(unsigned long data)
{
struct cardstate *cs = (struct cardstate *) data;
struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
gig_dbg(DEBUG_OUTPUT, "modem_fill");
if (cs->hw.usb->busy) {
gig_dbg(DEBUG_OUTPUT, "modem_fill: busy");
return;
}
again:
if (!bcs->tx_skb) { /* no skb is being sent */
if (cs->cmdbuf) { /* commands to send? */
gig_dbg(DEBUG_OUTPUT, "modem_fill: cb");
if (send_cb(cs) < 0) {
gig_dbg(DEBUG_OUTPUT,
"modem_fill: send_cb failed");
goto again; /* no callback will be called! */
}
return;
}
/* skbs to send? */
bcs->tx_skb = skb_dequeue(&bcs->squeue);
if (!bcs->tx_skb)
return;
gig_dbg(DEBUG_INTR, "Dequeued skb (Adr: %lx)!",
(unsigned long) bcs->tx_skb);
}
gig_dbg(DEBUG_OUTPUT, "modem_fill: tx_skb");
if (write_modem(cs) < 0) {
gig_dbg(DEBUG_OUTPUT, "modem_fill: write_modem failed");
goto again; /* no callback will be called! */
}
}
/*
* Interrupt Input URB completion routine
*/
static void gigaset_read_int_callback(struct urb *urb)
{
struct cardstate *cs = urb->context;
struct inbuf_t *inbuf = cs->inbuf;
int status = urb->status;
int r;
unsigned numbytes;
unsigned char *src;
unsigned long flags;
if (!status) {
numbytes = urb->actual_length;
if (numbytes) {
src = cs->hw.usb->rcvbuf;
if (unlikely(*src))
dev_warn(cs->dev,
"%s: There was no leading 0, but 0x%02x!\n",
__func__, (unsigned) *src);
++src; /* skip leading 0x00 */
--numbytes;
if (gigaset_fill_inbuf(inbuf, src, numbytes)) {
gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
gigaset_schedule_event(inbuf->cs);
}
} else
gig_dbg(DEBUG_INTR, "Received zero block length");
} else {
/* The urb might have been killed. */
gig_dbg(DEBUG_ANY, "%s - nonzero status received: %d",
__func__, status);
if (status == -ENOENT || status == -ESHUTDOWN)
/* killed or endpoint shutdown: don't resubmit */
return;
}
/* resubmit URB */
spin_lock_irqsave(&cs->lock, flags);
if (!cs->connected) {
spin_unlock_irqrestore(&cs->lock, flags);
pr_err("%s: disconnected\n", __func__);
return;
}
r = usb_submit_urb(urb, GFP_ATOMIC);
spin_unlock_irqrestore(&cs->lock, flags);
if (r)
dev_err(cs->dev, "error %d resubmitting URB\n", -r);
}
/* This callback routine is called when data was transmitted to the device. */
static void gigaset_write_bulk_callback(struct urb *urb)
{
struct cardstate *cs = urb->context;
int status = urb->status;
unsigned long flags;
switch (status) {
case 0: /* normal completion */
break;
case -ENOENT: /* killed */
gig_dbg(DEBUG_ANY, "%s: killed", __func__);
cs->hw.usb->busy = 0;
return;
default:
dev_err(cs->dev, "bulk transfer failed (status %d)\n",
-status);
/* That's all we can do. Communication problems
are handled by timeouts or network protocols. */
}
spin_lock_irqsave(&cs->lock, flags);
if (!cs->connected) {
pr_err("%s: disconnected\n", __func__);
} else {
cs->hw.usb->busy = 0;
tasklet_schedule(&cs->write_tasklet);
}
spin_unlock_irqrestore(&cs->lock, flags);
}
static int send_cb(struct cardstate *cs)
{
struct cmdbuf_t *cb = cs->cmdbuf;
unsigned long flags;
int count;
int status = -ENOENT;
struct usb_cardstate *ucs = cs->hw.usb;
do {
if (!cb->len) {
spin_lock_irqsave(&cs->cmdlock, flags);
cs->cmdbytes -= cs->curlen;
gig_dbg(DEBUG_OUTPUT, "send_cb: sent %u bytes, %u left",
cs->curlen, cs->cmdbytes);
cs->cmdbuf = cb->next;
if (cs->cmdbuf) {
cs->cmdbuf->prev = NULL;
cs->curlen = cs->cmdbuf->len;
} else {
cs->lastcmdbuf = NULL;
cs->curlen = 0;
}
spin_unlock_irqrestore(&cs->cmdlock, flags);
if (cb->wake_tasklet)
tasklet_schedule(cb->wake_tasklet);
kfree(cb);
cb = cs->cmdbuf;
}
if (cb) {
count = min(cb->len, ucs->bulk_out_size);
gig_dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count);
usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
usb_sndbulkpipe(ucs->udev,
ucs->bulk_out_epnum),
cb->buf + cb->offset, count,
gigaset_write_bulk_callback, cs);
cb->offset += count;
cb->len -= count;
ucs->busy = 1;
spin_lock_irqsave(&cs->lock, flags);
status = cs->connected ?
usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) :
-ENODEV;
spin_unlock_irqrestore(&cs->lock, flags);
if (status) {
ucs->busy = 0;
dev_err(cs->dev,
"could not submit urb (error %d)\n",
-status);
cb->len = 0; /* skip urb => remove cb+wakeup
in next loop cycle */
}
}
} while (cb && status); /* next command on error */
return status;
}
/* Send command to device. */
static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
{
unsigned long flags;
int len;
gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
"CMD Transmit", cb->len, cb->buf);
spin_lock_irqsave(&cs->cmdlock, flags);
cb->prev = cs->lastcmdbuf;
if (cs->lastcmdbuf)
cs->lastcmdbuf->next = cb;
else {
cs->cmdbuf = cb;
cs->curlen = cb->len;
}
cs->cmdbytes += cb->len;
cs->lastcmdbuf = cb;
spin_unlock_irqrestore(&cs->cmdlock, flags);
spin_lock_irqsave(&cs->lock, flags);
len = cb->len;
if (cs->connected)
tasklet_schedule(&cs->write_tasklet);
spin_unlock_irqrestore(&cs->lock, flags);
return len;
}
static int gigaset_write_room(struct cardstate *cs)
{
unsigned bytes;
bytes = cs->cmdbytes;
return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0;
}
static int gigaset_chars_in_buffer(struct cardstate *cs)
{
return cs->cmdbytes;
}
/*
* set the break characters on the internal serial adapter
* using undocumented device commands reverse engineered from USB traces
* of the Siemens Windows driver
*/
static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
{
struct usb_device *udev = cs->hw.usb->udev;
gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf);
memcpy(cs->hw.usb->bchars, buf, 6);
return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41,
0, 0, &buf, 6, 2000);
}
static void gigaset_freebcshw(struct bc_state *bcs)
{
/* unused */
}
/* Initialize the b-channel structure */
static int gigaset_initbcshw(struct bc_state *bcs)
{
/* unused */
bcs->hw.usb = NULL;
return 0;
}
static void gigaset_reinitbcshw(struct bc_state *bcs)
{
/* nothing to do for M10x */
}
static void gigaset_freecshw(struct cardstate *cs)
{
tasklet_kill(&cs->write_tasklet);
kfree(cs->hw.usb);
}
static int gigaset_initcshw(struct cardstate *cs)
{
struct usb_cardstate *ucs;
cs->hw.usb = ucs =
kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL);
if (!ucs) {
pr_err("out of memory\n");
return -ENOMEM;
}
ucs->bchars[0] = 0;
ucs->bchars[1] = 0;
ucs->bchars[2] = 0;
ucs->bchars[3] = 0;
ucs->bchars[4] = 0x11;
ucs->bchars[5] = 0x13;
ucs->bulk_out_buffer = NULL;
ucs->bulk_out_urb = NULL;
ucs->read_urb = NULL;
tasklet_init(&cs->write_tasklet,
gigaset_modem_fill, (unsigned long) cs);
return 0;
}
/* Send data from current skb to the device. */
static int write_modem(struct cardstate *cs)
{
int ret = 0;
int count;
struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
struct usb_cardstate *ucs = cs->hw.usb;
unsigned long flags;
gig_dbg(DEBUG_OUTPUT, "len: %d...", bcs->tx_skb->len);
if (!bcs->tx_skb->len) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
return -EINVAL;
}
/* Copy data to bulk out buffer and transmit data */
count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count);
skb_pull(bcs->tx_skb, count);
ucs->busy = 1;
gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
spin_lock_irqsave(&cs->lock, flags);
if (cs->connected) {
usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
usb_sndbulkpipe(ucs->udev,
ucs->bulk_out_epnum),
ucs->bulk_out_buffer, count,
gigaset_write_bulk_callback, cs);
ret = usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC);
} else {
ret = -ENODEV;
}
spin_unlock_irqrestore(&cs->lock, flags);
if (ret) {
dev_err(cs->dev, "could not submit urb (error %d)\n", -ret);
ucs->busy = 0;
}
if (!bcs->tx_skb->len) {
/* skb sent completely */
gigaset_skb_sent(bcs, bcs->tx_skb);
gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!",
(unsigned long) bcs->tx_skb);
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
}
return ret;
}
static int gigaset_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
int retval;
struct usb_device *udev = interface_to_usbdev(interface);
struct usb_host_interface *hostif = interface->cur_altsetting;
struct cardstate *cs = NULL;
struct usb_cardstate *ucs = NULL;
struct usb_endpoint_descriptor *endpoint;
int buffer_size;
gig_dbg(DEBUG_ANY, "%s: Check if device matches ...", __func__);
/* See if the device offered us matches what we can accept */
if ((le16_to_cpu(udev->descriptor.idVendor) != USB_M105_VENDOR_ID) ||
(le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID)) {
gig_dbg(DEBUG_ANY, "device ID (0x%x, 0x%x) not for me - skip",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
return -ENODEV;
}
if (hostif->desc.bInterfaceNumber != 0) {
gig_dbg(DEBUG_ANY, "interface %d not for me - skip",
hostif->desc.bInterfaceNumber);
return -ENODEV;
}
if (hostif->desc.bAlternateSetting != 0) {
dev_notice(&udev->dev, "unsupported altsetting %d - skip",
hostif->desc.bAlternateSetting);
return -ENODEV;
}
if (hostif->desc.bInterfaceClass != 255) {
dev_notice(&udev->dev, "unsupported interface class %d - skip",
hostif->desc.bInterfaceClass);
return -ENODEV;
}
dev_info(&udev->dev, "%s: Device matched ... !\n", __func__);
/* allocate memory for our device state and initialize it */
cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
if (!cs)
return -ENODEV;
ucs = cs->hw.usb;
/* save off device structure ptrs for later use */
usb_get_dev(udev);
ucs->udev = udev;
ucs->interface = interface;
cs->dev = &interface->dev;
/* save address of controller structure */
usb_set_intfdata(interface, cs);
endpoint = &hostif->endpoint[0].desc;
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
ucs->bulk_out_size = buffer_size;
ucs->bulk_out_epnum = usb_endpoint_num(endpoint);
ucs->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!ucs->bulk_out_buffer) {
dev_err(cs->dev, "Couldn't allocate bulk_out_buffer\n");
retval = -ENOMEM;
goto error;
}
ucs->bulk_out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ucs->bulk_out_urb) {
dev_err(cs->dev, "Couldn't allocate bulk_out_urb\n");
retval = -ENOMEM;
goto error;
}
endpoint = &hostif->endpoint[1].desc;
ucs->busy = 0;
ucs->read_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ucs->read_urb) {
dev_err(cs->dev, "No free urbs available\n");
retval = -ENOMEM;
goto error;
}
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
ucs->rcvbuf_size = buffer_size;
ucs->rcvbuf = kmalloc(buffer_size, GFP_KERNEL);
if (!ucs->rcvbuf) {
dev_err(cs->dev, "Couldn't allocate rcvbuf\n");
retval = -ENOMEM;
goto error;
}
/* Fill the interrupt urb and send it to the core */
usb_fill_int_urb(ucs->read_urb, udev,
usb_rcvintpipe(udev, usb_endpoint_num(endpoint)),
ucs->rcvbuf, buffer_size,
gigaset_read_int_callback,
cs, endpoint->bInterval);
retval = usb_submit_urb(ucs->read_urb, GFP_KERNEL);
if (retval) {
dev_err(cs->dev, "Could not submit URB (error %d)\n", -retval);
goto error;
}
/* tell common part that the device is ready */
if (startmode == SM_LOCKED)
cs->mstate = MS_LOCKED;
retval = gigaset_start(cs);
if (retval < 0) {
tasklet_kill(&cs->write_tasklet);
goto error;
}
return 0;
error:
usb_kill_urb(ucs->read_urb);
kfree(ucs->bulk_out_buffer);
usb_free_urb(ucs->bulk_out_urb);
kfree(ucs->rcvbuf);
usb_free_urb(ucs->read_urb);
usb_set_intfdata(interface, NULL);
ucs->read_urb = ucs->bulk_out_urb = NULL;
ucs->rcvbuf = ucs->bulk_out_buffer = NULL;
usb_put_dev(ucs->udev);
ucs->udev = NULL;
ucs->interface = NULL;
gigaset_freecs(cs);
return retval;
}
static void gigaset_disconnect(struct usb_interface *interface)
{
struct cardstate *cs;
struct usb_cardstate *ucs;
cs = usb_get_intfdata(interface);
ucs = cs->hw.usb;
dev_info(cs->dev, "disconnecting Gigaset USB adapter\n");
usb_kill_urb(ucs->read_urb);
gigaset_stop(cs);
usb_set_intfdata(interface, NULL);
tasklet_kill(&cs->write_tasklet);
usb_kill_urb(ucs->bulk_out_urb);
kfree(ucs->bulk_out_buffer);
usb_free_urb(ucs->bulk_out_urb);
kfree(ucs->rcvbuf);
usb_free_urb(ucs->read_urb);
ucs->read_urb = ucs->bulk_out_urb = NULL;
ucs->rcvbuf = ucs->bulk_out_buffer = NULL;
usb_put_dev(ucs->udev);
ucs->interface = NULL;
ucs->udev = NULL;
cs->dev = NULL;
gigaset_freecs(cs);
}
/* gigaset_suspend
* This function is called before the USB connection is suspended or reset.
*/
static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
{
struct cardstate *cs = usb_get_intfdata(intf);
/* stop activity */
cs->connected = 0; /* prevent rescheduling */
usb_kill_urb(cs->hw.usb->read_urb);
tasklet_kill(&cs->write_tasklet);
usb_kill_urb(cs->hw.usb->bulk_out_urb);
gig_dbg(DEBUG_SUSPEND, "suspend complete");
return 0;
}
/* gigaset_resume
* This function is called after the USB connection has been resumed or reset.
*/
static int gigaset_resume(struct usb_interface *intf)
{
struct cardstate *cs = usb_get_intfdata(intf);
int rc;
/* resubmit interrupt URB */
cs->connected = 1;
rc = usb_submit_urb(cs->hw.usb->read_urb, GFP_KERNEL);
if (rc) {
dev_err(cs->dev, "Could not submit read URB (error %d)\n", -rc);
return rc;
}
gig_dbg(DEBUG_SUSPEND, "resume complete");
return 0;
}
/* gigaset_pre_reset
* This function is called before the USB connection is reset.
*/
static int gigaset_pre_reset(struct usb_interface *intf)
{
/* same as suspend */
return gigaset_suspend(intf, PMSG_ON);
}
static const struct gigaset_ops ops = {
.write_cmd = gigaset_write_cmd,
.write_room = gigaset_write_room,
.chars_in_buffer = gigaset_chars_in_buffer,
.brkchars = gigaset_brkchars,
.init_bchannel = gigaset_init_bchannel,
.close_bchannel = gigaset_close_bchannel,
.initbcshw = gigaset_initbcshw,
.freebcshw = gigaset_freebcshw,
.reinitbcshw = gigaset_reinitbcshw,
.initcshw = gigaset_initcshw,
.freecshw = gigaset_freecshw,
.set_modem_ctrl = gigaset_set_modem_ctrl,
.baud_rate = gigaset_baud_rate,
.set_line_ctrl = gigaset_set_line_ctrl,
.send_skb = gigaset_m10x_send_skb,
.handle_input = gigaset_m10x_input,
};
/*
* This function is called while kernel-module is loaded
*/
static int __init usb_gigaset_init(void)
{
int result;
/* allocate memory for our driver state and initialize it */
driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
GIGASET_MODULENAME, GIGASET_DEVNAME,
&ops, THIS_MODULE);
if (driver == NULL) {
result = -ENOMEM;
goto error;
}
/* register this driver with the USB subsystem */
result = usb_register(&gigaset_usb_driver);
if (result < 0) {
pr_err("error %d registering USB driver\n", -result);
goto error;
}
pr_info(DRIVER_DESC "\n");
return 0;
error:
if (driver)
gigaset_freedriver(driver);
driver = NULL;
return result;
}
/*
* This function is called while unloading the kernel-module
*/
static void __exit usb_gigaset_exit(void)
{
int i;
gigaset_blockdriver(driver); /* => probe will fail
* => no gigaset_start any more
*/
/* stop all connected devices */
for (i = 0; i < driver->minors; i++)
gigaset_shutdown(driver->cs + i);
/* from now on, no isdn callback should be possible */
/* deregister this driver with the USB subsystem */
usb_deregister(&gigaset_usb_driver);
/* this will call the disconnect-callback */
/* from now on, no disconnect/probe callback should be running */
gigaset_freedriver(driver);
driver = NULL;
}
module_init(usb_gigaset_init);
module_exit(usb_gigaset_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");

View file

@ -1,8 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# ISDN hardware drivers
#
comment "CAPI hardware drivers"
source "drivers/isdn/hardware/avm/Kconfig"

View file

@ -3,5 +3,4 @@
# Object files in subdirectories
obj-$(CONFIG_CAPI_AVM) += avm/
obj-$(CONFIG_MISDN) += mISDN/

View file

@ -1,65 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# ISDN AVM drivers
#
menuconfig CAPI_AVM
bool "Active AVM cards"
help
Enable support for AVM active ISDN cards.
if CAPI_AVM
config ISDN_DRV_AVMB1_B1ISA
tristate "AVM B1 ISA support"
depends on ISA
help
Enable support for the ISA version of the AVM B1 card.
config ISDN_DRV_AVMB1_B1PCI
tristate "AVM B1 PCI support"
depends on PCI
help
Enable support for the PCI version of the AVM B1 card.
config ISDN_DRV_AVMB1_B1PCIV4
bool "AVM B1 PCI V4 support"
depends on ISDN_DRV_AVMB1_B1PCI
help
Enable support for the V4 version of AVM B1 PCI card.
config ISDN_DRV_AVMB1_T1ISA
tristate "AVM T1/T1-B ISA support"
depends on ISA
help
Enable support for the AVM T1 T1B card.
Note: This is a PRI card and handle 30 B-channels.
config ISDN_DRV_AVMB1_B1PCMCIA
tristate "AVM B1/M1/M2 PCMCIA support"
depends on PCMCIA
help
Enable support for the PCMCIA version of the AVM B1 card.
config ISDN_DRV_AVMB1_AVM_CS
tristate "AVM B1/M1/M2 PCMCIA cs module"
depends on ISDN_DRV_AVMB1_B1PCMCIA
help
Enable the PCMCIA client driver for the AVM B1/M1/M2
PCMCIA cards.
config ISDN_DRV_AVMB1_T1PCI
tristate "AVM T1/T1-B PCI support"
depends on PCI
help
Enable support for the AVM T1 T1B card.
Note: This is a PRI card and handle 30 B-channels.
config ISDN_DRV_AVMB1_C4
tristate "AVM C4/C2 support"
depends on PCI
help
Enable support for the AVM C4/C2 PCI cards.
These cards handle 4/2 BRI ISDN lines (8/4 channels).
endif # CAPI_AVM

View file

@ -1,12 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for the AVM ISDN device drivers
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN_DRV_AVMB1_B1ISA) += b1isa.o b1.o
obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCI) += b1pci.o b1.o b1dma.o
obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCMCIA) += b1pcmcia.o b1.o
obj-$(CONFIG_ISDN_DRV_AVMB1_AVM_CS) += avm_cs.o
obj-$(CONFIG_ISDN_DRV_AVMB1_T1ISA) += t1isa.o b1.o
obj-$(CONFIG_ISDN_DRV_AVMB1_T1PCI) += t1pci.o b1.o b1dma.o
obj-$(CONFIG_ISDN_DRV_AVMB1_C4) += c4.o b1.o

View file

@ -1,166 +0,0 @@
/* $Id: avm_cs.c,v 1.4.6.3 2001/09/23 22:24:33 kai Exp $
*
* A PCMCIA client driver for AVM B1/M1/M2
*
* Copyright 1999 by Carsten Paeth <calle@calle.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/string.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/major.h>
#include <asm/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
#include <pcmcia/cisreg.h>
#include <linux/skbuff.h>
#include <linux/capi.h>
#include <linux/b1lli.h>
#include <linux/b1pcmcia.h>
/*====================================================================*/
MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/*====================================================================*/
static int avmcs_config(struct pcmcia_device *link);
static void avmcs_release(struct pcmcia_device *link);
static void avmcs_detach(struct pcmcia_device *p_dev);
static int avmcs_probe(struct pcmcia_device *p_dev)
{
/* General socket configuration */
p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
p_dev->config_index = 1;
p_dev->config_regs = PRESENT_OPTION;
return avmcs_config(p_dev);
} /* avmcs_attach */
static void avmcs_detach(struct pcmcia_device *link)
{
avmcs_release(link);
} /* avmcs_detach */
static int avmcs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
{
p_dev->resource[0]->end = 16;
p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
return pcmcia_request_io(p_dev);
}
static int avmcs_config(struct pcmcia_device *link)
{
int i = -1;
char devname[128];
int cardtype;
int (*addcard)(unsigned int port, unsigned irq);
devname[0] = 0;
if (link->prod_id[1])
strlcpy(devname, link->prod_id[1], sizeof(devname));
/*
* find IO port
*/
if (pcmcia_loop_config(link, avmcs_configcheck, NULL))
return -ENODEV;
do {
if (!link->irq) {
/* undo */
pcmcia_disable_device(link);
break;
}
/*
* configure the PCMCIA socket
*/
i = pcmcia_enable_device(link);
if (i != 0) {
pcmcia_disable_device(link);
break;
}
} while (0);
if (devname[0]) {
char *s = strrchr(devname, ' ');
if (!s)
s = devname;
else s++;
if (strcmp("M1", s) == 0) {
cardtype = AVM_CARDTYPE_M1;
} else if (strcmp("M2", s) == 0) {
cardtype = AVM_CARDTYPE_M2;
} else {
cardtype = AVM_CARDTYPE_B1;
}
} else
cardtype = AVM_CARDTYPE_B1;
/* If any step failed, release any partially configured state */
if (i != 0) {
avmcs_release(link);
return -ENODEV;
}
switch (cardtype) {
case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
default:
case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
}
if ((i = (*addcard)(link->resource[0]->start, link->irq)) < 0) {
dev_err(&link->dev,
"avm_cs: failed to add AVM-Controller at i/o %#x, irq %d\n",
(unsigned int) link->resource[0]->start, link->irq);
avmcs_release(link);
return -ENODEV;
}
return 0;
} /* avmcs_config */
static void avmcs_release(struct pcmcia_device *link)
{
b1pcmcia_delcard(link->resource[0]->start, link->irq);
pcmcia_disable_device(link);
} /* avmcs_release */
static const struct pcmcia_device_id avmcs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
static struct pcmcia_driver avmcs_driver = {
.owner = THIS_MODULE,
.name = "avm_cs",
.probe = avmcs_probe,
.remove = avmcs_detach,
.id_table = avmcs_ids,
};
module_pcmcia_driver(avmcs_driver);

View file

@ -1,581 +0,0 @@
/* $Id: avmcard.h,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
*
* Copyright 1999 by Carsten Paeth <calle@calle.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef _AVMCARD_H_
#define _AVMCARD_H_
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#define AVMB1_PORTLEN 0x1f
#define AVM_MAXVERSION 8
#define AVM_NCCI_PER_CHANNEL 4
/*
* Versions
*/
#define VER_DRIVER 0
#define VER_CARDTYPE 1
#define VER_HWID 2
#define VER_SERIAL 3
#define VER_OPTION 4
#define VER_PROTO 5
#define VER_PROFILE 6
#define VER_CAPI 7
enum avmcardtype {
avm_b1isa,
avm_b1pci,
avm_b1pcmcia,
avm_m1,
avm_m2,
avm_t1isa,
avm_t1pci,
avm_c4,
avm_c2
};
typedef struct avmcard_dmabuf {
long size;
u8 *dmabuf;
dma_addr_t dmaaddr;
} avmcard_dmabuf;
typedef struct avmcard_dmainfo {
u32 recvlen;
avmcard_dmabuf recvbuf;
avmcard_dmabuf sendbuf;
struct sk_buff_head send_queue;
struct pci_dev *pcidev;
} avmcard_dmainfo;
typedef struct avmctrl_info {
char cardname[32];
int versionlen;
char versionbuf[1024];
char *version[AVM_MAXVERSION];
char infobuf[128]; /* for function procinfo */
struct avmcard *card;
struct capi_ctr capi_ctrl;
struct list_head ncci_head;
} avmctrl_info;
typedef struct avmcard {
char name[32];
spinlock_t lock;
unsigned int port;
unsigned irq;
unsigned long membase;
enum avmcardtype cardtype;
unsigned char revision;
unsigned char class;
int cardnr; /* for t1isa */
char msgbuf[128]; /* capimsg msg part */
char databuf[2048]; /* capimsg data part */
void __iomem *mbase;
volatile u32 csr;
avmcard_dmainfo *dma;
struct avmctrl_info *ctrlinfo;
u_int nr_controllers;
u_int nlogcontr;
struct list_head list;
} avmcard;
extern int b1_irq_table[16];
/*
* LLI Messages to the ISDN-ControllerISDN Controller
*/
#define SEND_POLL 0x72 /*
* after load <- RECEIVE_POLL
*/
#define SEND_INIT 0x11 /*
* first message <- RECEIVE_INIT
* int32 NumApplications int32
* NumNCCIs int32 BoardNumber
*/
#define SEND_REGISTER 0x12 /*
* register an application int32
* ApplIDId int32 NumMessages
* int32 NumB3Connections int32
* NumB3Blocks int32 B3Size
*
* AnzB3Connection != 0 &&
* AnzB3Blocks >= 1 && B3Size >= 1
*/
#define SEND_RELEASE 0x14 /*
* deregister an application int32
* ApplID
*/
#define SEND_MESSAGE 0x15 /*
* send capi-message int32 length
* capi-data ...
*/
#define SEND_DATA_B3_REQ 0x13 /*
* send capi-data-message int32
* MsgLength capi-data ... int32
* B3Length data ....
*/
#define SEND_CONFIG 0x21 /*
*/
#define SEND_POLLACK 0x73 /* T1 Watchdog */
/*
* LLI Messages from the ISDN-ControllerISDN Controller
*/
#define RECEIVE_POLL 0x32 /*
* <- after SEND_POLL
*/
#define RECEIVE_INIT 0x27 /*
* <- after SEND_INIT int32 length
* byte total length b1struct board
* driver revision b1struct card
* type b1struct reserved b1struct
* serial number b1struct driver
* capability b1struct d-channel
* protocol b1struct CAPI-2.0
* profile b1struct capi version
*/
#define RECEIVE_MESSAGE 0x21 /*
* <- after SEND_MESSAGE int32
* AppllID int32 Length capi-data
* ....
*/
#define RECEIVE_DATA_B3_IND 0x22 /*
* received data int32 AppllID
* int32 Length capi-data ...
* int32 B3Length data ...
*/
#define RECEIVE_START 0x23 /*
* Handshake
*/
#define RECEIVE_STOP 0x24 /*
* Handshake
*/
#define RECEIVE_NEW_NCCI 0x25 /*
* int32 AppllID int32 NCCI int32
* WindowSize
*/
#define RECEIVE_FREE_NCCI 0x26 /*
* int32 AppllID int32 NCCI
*/
#define RECEIVE_RELEASE 0x26 /*
* int32 AppllID int32 0xffffffff
*/
#define RECEIVE_TASK_READY 0x31 /*
* int32 tasknr
* int32 Length Taskname ...
*/
#define RECEIVE_DEBUGMSG 0x71 /*
* int32 Length message
*
*/
#define RECEIVE_POLLDWORD 0x75 /* t1pci in dword mode */
#define WRITE_REGISTER 0x00
#define READ_REGISTER 0x01
/*
* port offsets
*/
#define B1_READ 0x00
#define B1_WRITE 0x01
#define B1_INSTAT 0x02
#define B1_OUTSTAT 0x03
#define B1_ANALYSE 0x04
#define B1_REVISION 0x05
#define B1_RESET 0x10
#define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l)
#define B1_STAT1(cardtype) (0x80E00000l)
/* ---------------------------------------------------------------- */
static inline unsigned char b1outp(unsigned int base,
unsigned short offset,
unsigned char value)
{
outb(value, base + offset);
return inb(base + B1_ANALYSE);
}
static inline int b1_rx_full(unsigned int base)
{
return inb(base + B1_INSTAT) & 0x1;
}
static inline unsigned char b1_get_byte(unsigned int base)
{
unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
while (!b1_rx_full(base) && time_before(jiffies, stop));
if (b1_rx_full(base))
return inb(base + B1_READ);
printk(KERN_CRIT "b1lli(0x%x): rx not full after 1 second\n", base);
return 0;
}
static inline unsigned int b1_get_word(unsigned int base)
{
unsigned int val = 0;
val |= b1_get_byte(base);
val |= (b1_get_byte(base) << 8);
val |= (b1_get_byte(base) << 16);
val |= (b1_get_byte(base) << 24);
return val;
}
static inline int b1_tx_empty(unsigned int base)
{
return inb(base + B1_OUTSTAT) & 0x1;
}
static inline void b1_put_byte(unsigned int base, unsigned char val)
{
while (!b1_tx_empty(base));
b1outp(base, B1_WRITE, val);
}
static inline int b1_save_put_byte(unsigned int base, unsigned char val)
{
unsigned long stop = jiffies + 2 * HZ;
while (!b1_tx_empty(base) && time_before(jiffies, stop));
if (!b1_tx_empty(base)) return -1;
b1outp(base, B1_WRITE, val);
return 0;
}
static inline void b1_put_word(unsigned int base, unsigned int val)
{
b1_put_byte(base, val & 0xff);
b1_put_byte(base, (val >> 8) & 0xff);
b1_put_byte(base, (val >> 16) & 0xff);
b1_put_byte(base, (val >> 24) & 0xff);
}
static inline unsigned int b1_get_slice(unsigned int base,
unsigned char *dp)
{
unsigned int len, i;
len = i = b1_get_word(base);
while (i-- > 0) *dp++ = b1_get_byte(base);
return len;
}
static inline void b1_put_slice(unsigned int base,
unsigned char *dp, unsigned int len)
{
unsigned i = len;
b1_put_word(base, i);
while (i-- > 0)
b1_put_byte(base, *dp++);
}
static void b1_wr_reg(unsigned int base,
unsigned int reg,
unsigned int value)
{
b1_put_byte(base, WRITE_REGISTER);
b1_put_word(base, reg);
b1_put_word(base, value);
}
static inline unsigned int b1_rd_reg(unsigned int base,
unsigned int reg)
{
b1_put_byte(base, READ_REGISTER);
b1_put_word(base, reg);
return b1_get_word(base);
}
static inline void b1_reset(unsigned int base)
{
b1outp(base, B1_RESET, 0);
mdelay(55 * 2); /* 2 TIC's */
b1outp(base, B1_RESET, 1);
mdelay(55 * 2); /* 2 TIC's */
b1outp(base, B1_RESET, 0);
mdelay(55 * 2); /* 2 TIC's */
}
static inline unsigned char b1_disable_irq(unsigned int base)
{
return b1outp(base, B1_INSTAT, 0x00);
}
/* ---------------------------------------------------------------- */
static inline void b1_set_test_bit(unsigned int base,
enum avmcardtype cardtype,
int onoff)
{
b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20);
}
static inline int b1_get_test_bit(unsigned int base,
enum avmcardtype cardtype)
{
return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0;
}
/* ---------------------------------------------------------------- */
#define T1_FASTLINK 0x00
#define T1_SLOWLINK 0x08
#define T1_READ B1_READ
#define T1_WRITE B1_WRITE
#define T1_INSTAT B1_INSTAT
#define T1_OUTSTAT B1_OUTSTAT
#define T1_IRQENABLE 0x05
#define T1_FIFOSTAT 0x06
#define T1_RESETLINK 0x10
#define T1_ANALYSE 0x11
#define T1_IRQMASTER 0x12
#define T1_IDENT 0x17
#define T1_RESETBOARD 0x1f
#define T1F_IREADY 0x01
#define T1F_IHALF 0x02
#define T1F_IFULL 0x04
#define T1F_IEMPTY 0x08
#define T1F_IFLAGS 0xF0
#define T1F_OREADY 0x10
#define T1F_OHALF 0x20
#define T1F_OEMPTY 0x40
#define T1F_OFULL 0x80
#define T1F_OFLAGS 0xF0
/* there are HEMA cards with 1k and 4k FIFO out */
#define FIFO_OUTBSIZE 256
#define FIFO_INPBSIZE 512
#define HEMA_VERSION_ID 0
#define HEMA_PAL_ID 0
static inline void t1outp(unsigned int base,
unsigned short offset,
unsigned char value)
{
outb(value, base + offset);
}
static inline unsigned char t1inp(unsigned int base,
unsigned short offset)
{
return inb(base + offset);
}
static inline int t1_isfastlink(unsigned int base)
{
return (inb(base + T1_IDENT) & ~0x82) == 1;
}
static inline unsigned char t1_fifostatus(unsigned int base)
{
return inb(base + T1_FIFOSTAT);
}
static inline unsigned int t1_get_slice(unsigned int base,
unsigned char *dp)
{
unsigned int len, i;
#ifdef FASTLINK_DEBUG
unsigned wcnt = 0, bcnt = 0;
#endif
len = i = b1_get_word(base);
if (t1_isfastlink(base)) {
int status;
while (i > 0) {
status = t1_fifostatus(base) & (T1F_IREADY | T1F_IHALF);
if (i >= FIFO_INPBSIZE) status |= T1F_IFULL;
switch (status) {
case T1F_IREADY | T1F_IHALF | T1F_IFULL:
insb(base + B1_READ, dp, FIFO_INPBSIZE);
dp += FIFO_INPBSIZE;
i -= FIFO_INPBSIZE;
#ifdef FASTLINK_DEBUG
wcnt += FIFO_INPBSIZE;
#endif
break;
case T1F_IREADY | T1F_IHALF:
insb(base + B1_READ, dp, i);
#ifdef FASTLINK_DEBUG
wcnt += i;
#endif
dp += i;
i = 0;
break;
default:
*dp++ = b1_get_byte(base);
i--;
#ifdef FASTLINK_DEBUG
bcnt++;
#endif
break;
}
}
#ifdef FASTLINK_DEBUG
if (wcnt)
printk(KERN_DEBUG "b1lli(0x%x): get_slice l=%d w=%d b=%d\n",
base, len, wcnt, bcnt);
#endif
} else {
while (i-- > 0)
*dp++ = b1_get_byte(base);
}
return len;
}
static inline void t1_put_slice(unsigned int base,
unsigned char *dp, unsigned int len)
{
unsigned i = len;
b1_put_word(base, i);
if (t1_isfastlink(base)) {
int status;
while (i > 0) {
status = t1_fifostatus(base) & (T1F_OREADY | T1F_OHALF);
if (i >= FIFO_OUTBSIZE) status |= T1F_OEMPTY;
switch (status) {
case T1F_OREADY | T1F_OHALF | T1F_OEMPTY:
outsb(base + B1_WRITE, dp, FIFO_OUTBSIZE);
dp += FIFO_OUTBSIZE;
i -= FIFO_OUTBSIZE;
break;
case T1F_OREADY | T1F_OHALF:
outsb(base + B1_WRITE, dp, i);
dp += i;
i = 0;
break;
default:
b1_put_byte(base, *dp++);
i--;
break;
}
}
} else {
while (i-- > 0)
b1_put_byte(base, *dp++);
}
}
static inline void t1_disable_irq(unsigned int base)
{
t1outp(base, T1_IRQMASTER, 0x00);
}
static inline void t1_reset(unsigned int base)
{
/* reset T1 Controller */
b1_reset(base);
/* disable irq on HEMA */
t1outp(base, B1_INSTAT, 0x00);
t1outp(base, B1_OUTSTAT, 0x00);
t1outp(base, T1_IRQMASTER, 0x00);
/* reset HEMA board configuration */
t1outp(base, T1_RESETBOARD, 0xf);
}
static inline void b1_setinterrupt(unsigned int base, unsigned irq,
enum avmcardtype cardtype)
{
switch (cardtype) {
case avm_t1isa:
t1outp(base, B1_INSTAT, 0x00);
t1outp(base, B1_INSTAT, 0x02);
t1outp(base, T1_IRQMASTER, 0x08);
break;
case avm_b1isa:
b1outp(base, B1_INSTAT, 0x00);
b1outp(base, B1_RESET, b1_irq_table[irq]);
b1outp(base, B1_INSTAT, 0x02);
break;
default:
case avm_m1:
case avm_m2:
case avm_b1pci:
b1outp(base, B1_INSTAT, 0x00);
b1outp(base, B1_RESET, 0xf0);
b1outp(base, B1_INSTAT, 0x02);
break;
case avm_c4:
case avm_t1pci:
b1outp(base, B1_RESET, 0xf0);
break;
}
}
/* b1.c */
avmcard *b1_alloc_card(int nr_controllers);
void b1_free_card(avmcard *card);
int b1_detect(unsigned int base, enum avmcardtype cardtype);
void b1_getrevision(avmcard *card);
int b1_load_t4file(avmcard *card, capiloaddatapart *t4file);
int b1_load_config(avmcard *card, capiloaddatapart *config);
int b1_loaded(avmcard *card);
int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
void b1_reset_ctr(struct capi_ctr *ctrl);
void b1_register_appl(struct capi_ctr *ctrl, u16 appl,
capi_register_params *rp);
void b1_release_appl(struct capi_ctr *ctrl, u16 appl);
u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
void b1_parse_version(avmctrl_info *card);
irqreturn_t b1_interrupt(int interrupt, void *devptr);
int b1_proc_show(struct seq_file *m, void *v);
avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *,
long rsize, long ssize);
void avmcard_dma_free(avmcard_dmainfo *);
/* b1dma.c */
int b1pciv4_detect(avmcard *card);
int t1pci_detect(avmcard *card);
void b1dma_reset(avmcard *card);
irqreturn_t b1dma_interrupt(int interrupt, void *devptr);
int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
void b1dma_reset_ctr(struct capi_ctr *ctrl);
void b1dma_remove_ctr(struct capi_ctr *ctrl);
void b1dma_register_appl(struct capi_ctr *ctrl,
u16 appl,
capi_register_params *rp);
void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl);
u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
int b1dma_proc_show(struct seq_file *m, void *v);
#endif /* _AVMCARD_H_ */

View file

@ -1,804 +0,0 @@
/* $Id: b1.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
*
* Common module for AVM B1 cards.
*
* Copyright 1999 by Carsten Paeth <calle@calle.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/netdevice.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
static char *revision = "$Revision: 1.1.2.2 $";
/* ------------------------------------------------------------- */
MODULE_DESCRIPTION("CAPI4Linux: Common support for active AVM cards");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
int b1_irq_table[16] =
{0,
0,
0,
192, /* irq 3 */
32, /* irq 4 */
160, /* irq 5 */
96, /* irq 6 */
224, /* irq 7 */
0,
64, /* irq 9 */
80, /* irq 10 */
208, /* irq 11 */
48, /* irq 12 */
0,
0,
112, /* irq 15 */
};
/* ------------------------------------------------------------- */
avmcard *b1_alloc_card(int nr_controllers)
{
avmcard *card;
avmctrl_info *cinfo;
int i;
card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card)
return NULL;
cinfo = kcalloc(nr_controllers, sizeof(*cinfo), GFP_KERNEL);
if (!cinfo) {
kfree(card);
return NULL;
}
card->ctrlinfo = cinfo;
for (i = 0; i < nr_controllers; i++) {
INIT_LIST_HEAD(&cinfo[i].ncci_head);
cinfo[i].card = card;
}
spin_lock_init(&card->lock);
card->nr_controllers = nr_controllers;
return card;
}
/* ------------------------------------------------------------- */
void b1_free_card(avmcard *card)
{
kfree(card->ctrlinfo);
kfree(card);
}
/* ------------------------------------------------------------- */
int b1_detect(unsigned int base, enum avmcardtype cardtype)
{
int onoff, i;
/*
* Statusregister 0000 00xx
*/
if ((inb(base + B1_INSTAT) & 0xfc)
|| (inb(base + B1_OUTSTAT) & 0xfc))
return 1;
/*
* Statusregister 0000 001x
*/
b1outp(base, B1_INSTAT, 0x2); /* enable irq */
/* b1outp(base, B1_OUTSTAT, 0x2); */
if ((inb(base + B1_INSTAT) & 0xfe) != 0x2
/* || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2 */)
return 2;
/*
* Statusregister 0000 000x
*/
b1outp(base, B1_INSTAT, 0x0); /* disable irq */
b1outp(base, B1_OUTSTAT, 0x0);
if ((inb(base + B1_INSTAT) & 0xfe)
|| (inb(base + B1_OUTSTAT) & 0xfe))
return 3;
for (onoff = !0, i = 0; i < 10; i++) {
b1_set_test_bit(base, cardtype, onoff);
if (b1_get_test_bit(base, cardtype) != onoff)
return 4;
onoff = !onoff;
}
if (cardtype == avm_m1)
return 0;
if ((b1_rd_reg(base, B1_STAT1(cardtype)) & 0x0f) != 0x01)
return 5;
return 0;
}
void b1_getrevision(avmcard *card)
{
card->class = inb(card->port + B1_ANALYSE);
card->revision = inb(card->port + B1_REVISION);
}
#define FWBUF_SIZE 256
int b1_load_t4file(avmcard *card, capiloaddatapart *t4file)
{
unsigned char buf[FWBUF_SIZE];
unsigned char *dp;
int i, left;
unsigned int base = card->port;
dp = t4file->data;
left = t4file->len;
while (left > FWBUF_SIZE) {
if (t4file->user) {
if (copy_from_user(buf, dp, FWBUF_SIZE))
return -EFAULT;
} else {
memcpy(buf, dp, FWBUF_SIZE);
}
for (i = 0; i < FWBUF_SIZE; i++)
if (b1_save_put_byte(base, buf[i]) < 0) {
printk(KERN_ERR "%s: corrupted firmware file ?\n",
card->name);
return -EIO;
}
left -= FWBUF_SIZE;
dp += FWBUF_SIZE;
}
if (left) {
if (t4file->user) {
if (copy_from_user(buf, dp, left))
return -EFAULT;
} else {
memcpy(buf, dp, left);
}
for (i = 0; i < left; i++)
if (b1_save_put_byte(base, buf[i]) < 0) {
printk(KERN_ERR "%s: corrupted firmware file ?\n",
card->name);
return -EIO;
}
}
return 0;
}
int b1_load_config(avmcard *card, capiloaddatapart *config)
{
unsigned char buf[FWBUF_SIZE];
unsigned char *dp;
unsigned int base = card->port;
int i, j, left;
dp = config->data;
left = config->len;
if (left) {
b1_put_byte(base, SEND_CONFIG);
b1_put_word(base, 1);
b1_put_byte(base, SEND_CONFIG);
b1_put_word(base, left);
}
while (left > FWBUF_SIZE) {
if (config->user) {
if (copy_from_user(buf, dp, FWBUF_SIZE))
return -EFAULT;
} else {
memcpy(buf, dp, FWBUF_SIZE);
}
for (i = 0; i < FWBUF_SIZE; ) {
b1_put_byte(base, SEND_CONFIG);
for (j = 0; j < 4; j++) {
b1_put_byte(base, buf[i++]);
}
}
left -= FWBUF_SIZE;
dp += FWBUF_SIZE;
}
if (left) {
if (config->user) {
if (copy_from_user(buf, dp, left))
return -EFAULT;
} else {
memcpy(buf, dp, left);
}
for (i = 0; i < left; ) {
b1_put_byte(base, SEND_CONFIG);
for (j = 0; j < 4; j++) {
if (i < left)
b1_put_byte(base, buf[i++]);
else
b1_put_byte(base, 0);
}
}
}
return 0;
}
int b1_loaded(avmcard *card)
{
unsigned int base = card->port;
unsigned long stop;
unsigned char ans;
unsigned long tout = 2;
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_tx_empty(base))
break;
}
if (!b1_tx_empty(base)) {
printk(KERN_ERR "%s: b1_loaded: tx err, corrupted t4 file ?\n",
card->name);
return 0;
}
b1_put_byte(base, SEND_POLL);
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_rx_full(base)) {
if ((ans = b1_get_byte(base)) == RECEIVE_POLL) {
return 1;
}
printk(KERN_ERR "%s: b1_loaded: got 0x%x, firmware not running\n",
card->name, ans);
return 0;
}
}
printk(KERN_ERR "%s: b1_loaded: firmware not running\n", card->name);
return 0;
}
/* ------------------------------------------------------------- */
int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
int retval;
b1_reset(port);
if ((retval = b1_load_t4file(card, &data->firmware))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load t4file!!\n",
card->name);
return retval;
}
b1_disable_irq(port);
if (data->configuration.len > 0 && data->configuration.data) {
if ((retval = b1_load_config(card, &data->configuration))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load config!!\n",
card->name);
return retval;
}
}
if (!b1_loaded(card)) {
printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
return -EIO;
}
spin_lock_irqsave(&card->lock, flags);
b1_setinterrupt(port, card->irq, card->cardtype);
b1_put_byte(port, SEND_INIT);
b1_put_word(port, CAPI_MAXAPPL);
b1_put_word(port, AVM_NCCI_PER_CHANNEL * 2);
b1_put_word(port, ctrl->cnr - 1);
spin_unlock_irqrestore(&card->lock, flags);
return 0;
}
void b1_reset_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
b1_reset(port);
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
spin_lock_irqsave(&card->lock, flags);
capilib_release(&cinfo->ncci_head);
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_down(ctrl);
}
void b1_register_appl(struct capi_ctr *ctrl,
u16 appl,
capi_register_params *rp)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
int nconn, want = rp->level3cnt;
if (want > 0) nconn = want;
else nconn = ctrl->profile.nbchannel * -want;
if (nconn == 0) nconn = ctrl->profile.nbchannel;
spin_lock_irqsave(&card->lock, flags);
b1_put_byte(port, SEND_REGISTER);
b1_put_word(port, appl);
b1_put_word(port, 1024 * (nconn + 1));
b1_put_word(port, nconn);
b1_put_word(port, rp->datablkcnt);
b1_put_word(port, rp->datablklen);
spin_unlock_irqrestore(&card->lock, flags);
}
void b1_release_appl(struct capi_ctr *ctrl, u16 appl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
capilib_release_appl(&cinfo->ncci_head, appl);
b1_put_byte(port, SEND_RELEASE);
b1_put_word(port, appl);
spin_unlock_irqrestore(&card->lock, flags);
}
u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
u16 len = CAPIMSG_LEN(skb->data);
u8 cmd = CAPIMSG_COMMAND(skb->data);
u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
u16 dlen, retval;
spin_lock_irqsave(&card->lock, flags);
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
if (retval != CAPI_NOERROR) {
spin_unlock_irqrestore(&card->lock, flags);
return retval;
}
dlen = CAPIMSG_DATALEN(skb->data);
b1_put_byte(port, SEND_DATA_B3_REQ);
b1_put_slice(port, skb->data, len);
b1_put_slice(port, skb->data + len, dlen);
} else {
b1_put_byte(port, SEND_MESSAGE);
b1_put_slice(port, skb->data, len);
}
spin_unlock_irqrestore(&card->lock, flags);
dev_kfree_skb_any(skb);
return CAPI_NOERROR;
}
/* ------------------------------------------------------------- */
void b1_parse_version(avmctrl_info *cinfo)
{
struct capi_ctr *ctrl = &cinfo->capi_ctrl;
avmcard *card = cinfo->card;
capi_profile *profp;
u8 *dversion;
u8 flag;
int i, j;
for (j = 0; j < AVM_MAXVERSION; j++)
cinfo->version[j] = "";
for (i = 0, j = 0;
j < AVM_MAXVERSION && i < cinfo->versionlen;
j++, i += cinfo->versionbuf[i] + 1)
cinfo->version[j] = &cinfo->versionbuf[i + 1];
strlcpy(ctrl->serial, cinfo->version[VER_SERIAL], sizeof(ctrl->serial));
memcpy(&ctrl->profile, cinfo->version[VER_PROFILE], sizeof(capi_profile));
strlcpy(ctrl->manu, "AVM GmbH", sizeof(ctrl->manu));
dversion = cinfo->version[VER_DRIVER];
ctrl->version.majorversion = 2;
ctrl->version.minorversion = 0;
ctrl->version.majormanuversion = (((dversion[0] - '0') & 0xf) << 4);
ctrl->version.majormanuversion |= ((dversion[2] - '0') & 0xf);
ctrl->version.minormanuversion = (dversion[3] - '0') << 4;
ctrl->version.minormanuversion |=
(dversion[5] - '0') * 10 + ((dversion[6] - '0') & 0xf);
profp = &ctrl->profile;
flag = ((u8 *)(profp->manu))[1];
switch (flag) {
case 0: if (cinfo->version[VER_CARDTYPE])
strcpy(cinfo->cardname, cinfo->version[VER_CARDTYPE]);
else strcpy(cinfo->cardname, "B1");
break;
case 3: strcpy(cinfo->cardname, "PCMCIA B"); break;
case 4: strcpy(cinfo->cardname, "PCMCIA M1"); break;
case 5: strcpy(cinfo->cardname, "PCMCIA M2"); break;
case 6: strcpy(cinfo->cardname, "B1 V3.0"); break;
case 7: strcpy(cinfo->cardname, "B1 PCI"); break;
default: sprintf(cinfo->cardname, "AVM?%u", (unsigned int)flag); break;
}
printk(KERN_NOTICE "%s: card %d \"%s\" ready.\n",
card->name, ctrl->cnr, cinfo->cardname);
flag = ((u8 *)(profp->manu))[3];
if (flag)
printk(KERN_NOTICE "%s: card %d Protocol:%s%s%s%s%s%s%s\n",
card->name,
ctrl->cnr,
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
(flag & 0x04) ? " VN3" : "",
(flag & 0x08) ? " NI1" : "",
(flag & 0x10) ? " AUSTEL" : "",
(flag & 0x20) ? " ESS" : "",
(flag & 0x40) ? " 1TR6" : ""
);
flag = ((u8 *)(profp->manu))[5];
if (flag)
printk(KERN_NOTICE "%s: card %d Linetype:%s%s%s%s\n",
card->name,
ctrl->cnr,
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
(flag & 0x08) ? " leased line without D-channel" : "",
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
/* ------------------------------------------------------------- */
irqreturn_t b1_interrupt(int interrupt, void *devptr)
{
avmcard *card = devptr;
avmctrl_info *cinfo = &card->ctrlinfo[0];
struct capi_ctr *ctrl = &cinfo->capi_ctrl;
unsigned char b1cmd;
struct sk_buff *skb;
unsigned ApplId;
unsigned MsgLen;
unsigned DataB3Len;
unsigned NCCI;
unsigned WindowSize;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
if (!b1_rx_full(card->port)) {
spin_unlock_irqrestore(&card->lock, flags);
return IRQ_NONE;
}
b1cmd = b1_get_byte(card->port);
switch (b1cmd) {
case RECEIVE_DATA_B3_IND:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = b1_get_slice(card->port, card->msgbuf);
DataB3Len = b1_get_slice(card->port, card->databuf);
spin_unlock_irqrestore(&card->lock, flags);
if (MsgLen < 30) { /* not CAPI 64Bit */
memset(card->msgbuf + MsgLen, 0, 30-MsgLen);
MsgLen = 30;
CAPIMSG_SETLEN(card->msgbuf, 30);
}
if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
skb_put_data(skb, card->msgbuf, MsgLen);
skb_put_data(skb, card->databuf, DataB3Len);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_MESSAGE:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = b1_get_slice(card->port, card->msgbuf);
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
spin_unlock_irqrestore(&card->lock, flags);
} else {
skb_put_data(skb, card->msgbuf, MsgLen);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_NEW_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
WindowSize = b1_get_word(card->port);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_FREE_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
if (NCCI != 0xffffffff)
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_START:
/* b1_put_byte(card->port, SEND_POLLACK); */
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_resume_output(ctrl);
break;
case RECEIVE_STOP:
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_suspend_output(ctrl);
break;
case RECEIVE_INIT:
cinfo->versionlen = b1_get_slice(card->port, cinfo->versionbuf);
spin_unlock_irqrestore(&card->lock, flags);
b1_parse_version(cinfo);
printk(KERN_INFO "%s: %s-card (%s) now active\n",
card->name,
cinfo->version[VER_CARDTYPE],
cinfo->version[VER_DRIVER]);
capi_ctr_ready(ctrl);
break;
case RECEIVE_TASK_READY:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = b1_get_slice(card->port, card->msgbuf);
spin_unlock_irqrestore(&card->lock, flags);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = b1_get_slice(card->port, card->msgbuf);
spin_unlock_irqrestore(&card->lock, flags);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
case 0xff:
spin_unlock_irqrestore(&card->lock, flags);
printk(KERN_ERR "%s: card removed ?\n", card->name);
return IRQ_NONE;
default:
spin_unlock_irqrestore(&card->lock, flags);
printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
card->name, b1cmd);
return IRQ_HANDLED;
}
return IRQ_HANDLED;
}
/* ------------------------------------------------------------- */
int b1_proc_show(struct seq_file *m, void *v)
{
struct capi_ctr *ctrl = m->private;
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u8 flag;
char *s;
seq_printf(m, "%-16s %s\n", "name", card->name);
seq_printf(m, "%-16s 0x%x\n", "io", card->port);
seq_printf(m, "%-16s %d\n", "irq", card->irq);
switch (card->cardtype) {
case avm_b1isa: s = "B1 ISA"; break;
case avm_b1pci: s = "B1 PCI"; break;
case avm_b1pcmcia: s = "B1 PCMCIA"; break;
case avm_m1: s = "M1"; break;
case avm_m2: s = "M2"; break;
case avm_t1isa: s = "T1 ISA (HEMA)"; break;
case avm_t1pci: s = "T1 PCI"; break;
case avm_c4: s = "C4"; break;
case avm_c2: s = "C2"; break;
default: s = "???"; break;
}
seq_printf(m, "%-16s %s\n", "type", s);
if (card->cardtype == avm_t1isa)
seq_printf(m, "%-16s %d\n", "cardnr", card->cardnr);
if ((s = cinfo->version[VER_DRIVER]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[3];
if (flag)
seq_printf(m, "%-16s%s%s%s%s%s%s%s\n",
"protocol",
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
(flag & 0x04) ? " VN3" : "",
(flag & 0x08) ? " NI1" : "",
(flag & 0x10) ? " AUSTEL" : "",
(flag & 0x20) ? " ESS" : "",
(flag & 0x40) ? " 1TR6" : ""
);
}
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[5];
if (flag)
seq_printf(m, "%-16s%s%s%s%s\n",
"linetype",
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
(flag & 0x08) ? " leased line without D-channel" : "",
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
return 0;
}
EXPORT_SYMBOL(b1_proc_show);
/* ------------------------------------------------------------- */
#ifdef CONFIG_PCI
avmcard_dmainfo *
avmcard_dma_alloc(char *name, struct pci_dev *pdev, long rsize, long ssize)
{
avmcard_dmainfo *p;
void *buf;
p = kzalloc(sizeof(avmcard_dmainfo), GFP_KERNEL);
if (!p) {
printk(KERN_WARNING "%s: no memory.\n", name);
goto err;
}
p->recvbuf.size = rsize;
buf = pci_alloc_consistent(pdev, rsize, &p->recvbuf.dmaaddr);
if (!buf) {
printk(KERN_WARNING "%s: allocation of receive dma buffer failed.\n", name);
goto err_kfree;
}
p->recvbuf.dmabuf = buf;
p->sendbuf.size = ssize;
buf = pci_alloc_consistent(pdev, ssize, &p->sendbuf.dmaaddr);
if (!buf) {
printk(KERN_WARNING "%s: allocation of send dma buffer failed.\n", name);
goto err_free_consistent;
}
p->sendbuf.dmabuf = buf;
skb_queue_head_init(&p->send_queue);
return p;
err_free_consistent:
pci_free_consistent(p->pcidev, p->recvbuf.size,
p->recvbuf.dmabuf, p->recvbuf.dmaaddr);
err_kfree:
kfree(p);
err:
return NULL;
}
void avmcard_dma_free(avmcard_dmainfo *p)
{
pci_free_consistent(p->pcidev, p->recvbuf.size,
p->recvbuf.dmabuf, p->recvbuf.dmaaddr);
pci_free_consistent(p->pcidev, p->sendbuf.size,
p->sendbuf.dmabuf, p->sendbuf.dmaaddr);
skb_queue_purge(&p->send_queue);
kfree(p);
}
EXPORT_SYMBOL(avmcard_dma_alloc);
EXPORT_SYMBOL(avmcard_dma_free);
#endif
EXPORT_SYMBOL(b1_irq_table);
EXPORT_SYMBOL(b1_alloc_card);
EXPORT_SYMBOL(b1_free_card);
EXPORT_SYMBOL(b1_detect);
EXPORT_SYMBOL(b1_getrevision);
EXPORT_SYMBOL(b1_load_t4file);
EXPORT_SYMBOL(b1_load_config);
EXPORT_SYMBOL(b1_loaded);
EXPORT_SYMBOL(b1_load_firmware);
EXPORT_SYMBOL(b1_reset_ctr);
EXPORT_SYMBOL(b1_register_appl);
EXPORT_SYMBOL(b1_release_appl);
EXPORT_SYMBOL(b1_send_message);
EXPORT_SYMBOL(b1_parse_version);
EXPORT_SYMBOL(b1_interrupt);
static int __init b1_init(void)
{
char *p;
char rev[32];
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
printk(KERN_INFO "b1: revision %s\n", rev);
return 0;
}
static void __exit b1_exit(void)
{
}
module_init(b1_init);
module_exit(b1_exit);

View file

@ -1,981 +0,0 @@
/* $Id: b1dma.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
*
* Common module for AVM B1 cards that support dma with AMCC
*
* Copyright 2000 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/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/gfp.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/netdevice.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
static char *revision = "$Revision: 1.1.2.3 $";
#undef AVM_B1DMA_DEBUG
/* ------------------------------------------------------------- */
MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
static bool suppress_pollack = 0;
module_param(suppress_pollack, bool, 0);
/* ------------------------------------------------------------- */
static void b1dma_dispatch_tx(avmcard *card);
/* ------------------------------------------------------------- */
/* S5933 */
#define AMCC_RXPTR 0x24
#define AMCC_RXLEN 0x28
#define AMCC_TXPTR 0x2c
#define AMCC_TXLEN 0x30
#define AMCC_INTCSR 0x38
# define EN_READ_TC_INT 0x00008000L
# define EN_WRITE_TC_INT 0x00004000L
# define EN_TX_TC_INT EN_READ_TC_INT
# define EN_RX_TC_INT EN_WRITE_TC_INT
# define AVM_FLAG 0x30000000L
# define ANY_S5933_INT 0x00800000L
# define READ_TC_INT 0x00080000L
# define WRITE_TC_INT 0x00040000L
# define TX_TC_INT READ_TC_INT
# define RX_TC_INT WRITE_TC_INT
# define MASTER_ABORT_INT 0x00100000L
# define TARGET_ABORT_INT 0x00200000L
# define BUS_MASTER_INT 0x00200000L
# define ALL_INT 0x000C0000L
#define AMCC_MCSR 0x3c
# define A2P_HI_PRIORITY 0x00000100L
# define EN_A2P_TRANSFERS 0x00000400L
# define P2A_HI_PRIORITY 0x00001000L
# define EN_P2A_TRANSFERS 0x00004000L
# define RESET_A2P_FLAGS 0x04000000L
# define RESET_P2A_FLAGS 0x02000000L
/* ------------------------------------------------------------- */
static inline void b1dma_writel(avmcard *card, u32 value, int off)
{
writel(value, card->mbase + off);
}
static inline u32 b1dma_readl(avmcard *card, int off)
{
return readl(card->mbase + off);
}
/* ------------------------------------------------------------- */
static inline int b1dma_tx_empty(unsigned int port)
{
return inb(port + 0x03) & 0x1;
}
static inline int b1dma_rx_full(unsigned int port)
{
return inb(port + 0x02) & 0x1;
}
static int b1dma_tolink(avmcard *card, void *buf, unsigned int len)
{
unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
unsigned char *s = (unsigned char *)buf;
while (len--) {
while (!b1dma_tx_empty(card->port)
&& time_before(jiffies, stop));
if (!b1dma_tx_empty(card->port))
return -1;
t1outp(card->port, 0x01, *s++);
}
return 0;
}
static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len)
{
unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
unsigned char *s = (unsigned char *)buf;
while (len--) {
while (!b1dma_rx_full(card->port)
&& time_before(jiffies, stop));
if (!b1dma_rx_full(card->port))
return -1;
*s++ = t1inp(card->port, 0x00);
}
return 0;
}
static int WriteReg(avmcard *card, u32 reg, u8 val)
{
u8 cmd = 0x00;
if (b1dma_tolink(card, &cmd, 1) == 0
&& b1dma_tolink(card, &reg, 4) == 0) {
u32 tmp = val;
return b1dma_tolink(card, &tmp, 4);
}
return -1;
}
static u8 ReadReg(avmcard *card, u32 reg)
{
u8 cmd = 0x01;
if (b1dma_tolink(card, &cmd, 1) == 0
&& b1dma_tolink(card, &reg, 4) == 0) {
u32 tmp;
if (b1dma_fromlink(card, &tmp, 4) == 0)
return (u8)tmp;
}
return 0xff;
}
/* ------------------------------------------------------------- */
static inline void _put_byte(void **pp, u8 val)
{
u8 *s = *pp;
*s++ = val;
*pp = s;
}
static inline void _put_word(void **pp, u32 val)
{
u8 *s = *pp;
*s++ = val & 0xff;
*s++ = (val >> 8) & 0xff;
*s++ = (val >> 16) & 0xff;
*s++ = (val >> 24) & 0xff;
*pp = s;
}
static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
{
unsigned i = len;
_put_word(pp, i);
while (i-- > 0)
_put_byte(pp, *dp++);
}
static inline u8 _get_byte(void **pp)
{
u8 *s = *pp;
u8 val;
val = *s++;
*pp = s;
return val;
}
static inline u32 _get_word(void **pp)
{
u8 *s = *pp;
u32 val;
val = *s++;
val |= (*s++ << 8);
val |= (*s++ << 16);
val |= (*s++ << 24);
*pp = s;
return val;
}
static inline u32 _get_slice(void **pp, unsigned char *dp)
{
unsigned int len, i;
len = i = _get_word(pp);
while (i-- > 0) *dp++ = _get_byte(pp);
return len;
}
/* ------------------------------------------------------------- */
void b1dma_reset(avmcard *card)
{
card->csr = 0x0;
b1dma_writel(card, card->csr, AMCC_INTCSR);
b1dma_writel(card, 0, AMCC_MCSR);
b1dma_writel(card, 0, AMCC_RXLEN);
b1dma_writel(card, 0, AMCC_TXLEN);
t1outp(card->port, 0x10, 0x00);
t1outp(card->port, 0x07, 0x00);
b1dma_writel(card, 0, AMCC_MCSR);
mdelay(10);
b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */
mdelay(10);
b1dma_writel(card, 0, AMCC_MCSR);
if (card->cardtype == avm_t1pci)
mdelay(42);
else
mdelay(10);
}
/* ------------------------------------------------------------- */
static int b1dma_detect(avmcard *card)
{
b1dma_writel(card, 0, AMCC_MCSR);
mdelay(10);
b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */
mdelay(10);
b1dma_writel(card, 0, AMCC_MCSR);
mdelay(42);
b1dma_writel(card, 0, AMCC_RXLEN);
b1dma_writel(card, 0, AMCC_TXLEN);
card->csr = 0x0;
b1dma_writel(card, card->csr, AMCC_INTCSR);
if (b1dma_readl(card, AMCC_MCSR) != 0x000000E6)
return 1;
b1dma_writel(card, 0xffffffff, AMCC_RXPTR);
b1dma_writel(card, 0xffffffff, AMCC_TXPTR);
if (b1dma_readl(card, AMCC_RXPTR) != 0xfffffffc
|| b1dma_readl(card, AMCC_TXPTR) != 0xfffffffc)
return 2;
b1dma_writel(card, 0x0, AMCC_RXPTR);
b1dma_writel(card, 0x0, AMCC_TXPTR);
if (b1dma_readl(card, AMCC_RXPTR) != 0x0
|| b1dma_readl(card, AMCC_TXPTR) != 0x0)
return 3;
t1outp(card->port, 0x10, 0x00);
t1outp(card->port, 0x07, 0x00);
t1outp(card->port, 0x02, 0x02);
t1outp(card->port, 0x03, 0x02);
if ((t1inp(card->port, 0x02) & 0xFE) != 0x02
|| t1inp(card->port, 0x3) != 0x03)
return 4;
t1outp(card->port, 0x02, 0x00);
t1outp(card->port, 0x03, 0x00);
if ((t1inp(card->port, 0x02) & 0xFE) != 0x00
|| t1inp(card->port, 0x3) != 0x01)
return 5;
return 0;
}
int t1pci_detect(avmcard *card)
{
int ret;
if ((ret = b1dma_detect(card)) != 0)
return ret;
/* Transputer test */
if (WriteReg(card, 0x80001000, 0x11) != 0
|| WriteReg(card, 0x80101000, 0x22) != 0
|| WriteReg(card, 0x80201000, 0x33) != 0
|| WriteReg(card, 0x80301000, 0x44) != 0)
return 6;
if (ReadReg(card, 0x80001000) != 0x11
|| ReadReg(card, 0x80101000) != 0x22
|| ReadReg(card, 0x80201000) != 0x33
|| ReadReg(card, 0x80301000) != 0x44)
return 7;
if (WriteReg(card, 0x80001000, 0x55) != 0
|| WriteReg(card, 0x80101000, 0x66) != 0
|| WriteReg(card, 0x80201000, 0x77) != 0
|| WriteReg(card, 0x80301000, 0x88) != 0)
return 8;
if (ReadReg(card, 0x80001000) != 0x55
|| ReadReg(card, 0x80101000) != 0x66
|| ReadReg(card, 0x80201000) != 0x77
|| ReadReg(card, 0x80301000) != 0x88)
return 9;
return 0;
}
int b1pciv4_detect(avmcard *card)
{
int ret, i;
if ((ret = b1dma_detect(card)) != 0)
return ret;
for (i = 0; i < 5; i++) {
if (WriteReg(card, 0x80A00000, 0x21) != 0)
return 6;
if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01)
return 7;
}
for (i = 0; i < 5; i++) {
if (WriteReg(card, 0x80A00000, 0x20) != 0)
return 8;
if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00)
return 9;
}
return 0;
}
static void b1dma_queue_tx(avmcard *card, struct sk_buff *skb)
{
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
skb_queue_tail(&card->dma->send_queue, skb);
if (!(card->csr & EN_TX_TC_INT)) {
b1dma_dispatch_tx(card);
b1dma_writel(card, card->csr, AMCC_INTCSR);
}
spin_unlock_irqrestore(&card->lock, flags);
}
/* ------------------------------------------------------------- */
static void b1dma_dispatch_tx(avmcard *card)
{
avmcard_dmainfo *dma = card->dma;
struct sk_buff *skb;
u8 cmd, subcmd;
u16 len;
u32 txlen;
void *p;
skb = skb_dequeue(&dma->send_queue);
len = CAPIMSG_LEN(skb->data);
if (len) {
cmd = CAPIMSG_COMMAND(skb->data);
subcmd = CAPIMSG_SUBCOMMAND(skb->data);
p = dma->sendbuf.dmabuf;
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
u16 dlen = CAPIMSG_DATALEN(skb->data);
_put_byte(&p, SEND_DATA_B3_REQ);
_put_slice(&p, skb->data, len);
_put_slice(&p, skb->data + len, dlen);
} else {
_put_byte(&p, SEND_MESSAGE);
_put_slice(&p, skb->data, len);
}
txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;
#ifdef AVM_B1DMA_DEBUG
printk(KERN_DEBUG "tx: put msg len=%d\n", txlen);
#endif
} else {
txlen = skb->len - 2;
#ifdef AVM_B1DMA_POLLDEBUG
if (skb->data[2] == SEND_POLLACK)
printk(KERN_INFO "%s: send ack\n", card->name);
#endif
#ifdef AVM_B1DMA_DEBUG
printk(KERN_DEBUG "tx: put 0x%x len=%d\n",
skb->data[2], txlen);
#endif
skb_copy_from_linear_data_offset(skb, 2, dma->sendbuf.dmabuf,
skb->len - 2);
}
txlen = (txlen + 3) & ~3;
b1dma_writel(card, dma->sendbuf.dmaaddr, AMCC_TXPTR);
b1dma_writel(card, txlen, AMCC_TXLEN);
card->csr |= EN_TX_TC_INT;
dev_kfree_skb_any(skb);
}
/* ------------------------------------------------------------- */
static void queue_pollack(avmcard *card)
{
struct sk_buff *skb;
void *p;
skb = alloc_skb(3, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost poll ack\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_POLLACK);
skb_put(skb, (u8 *)p - (u8 *)skb->data);
b1dma_queue_tx(card, skb);
}
/* ------------------------------------------------------------- */
static void b1dma_handle_rx(avmcard *card)
{
avmctrl_info *cinfo = &card->ctrlinfo[0];
avmcard_dmainfo *dma = card->dma;
struct capi_ctr *ctrl = &cinfo->capi_ctrl;
struct sk_buff *skb;
void *p = dma->recvbuf.dmabuf + 4;
u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
u8 b1cmd = _get_byte(&p);
#ifdef AVM_B1DMA_DEBUG
printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
#endif
switch (b1cmd) {
case RECEIVE_DATA_B3_IND:
ApplId = (unsigned) _get_word(&p);
MsgLen = _get_slice(&p, card->msgbuf);
DataB3Len = _get_slice(&p, card->databuf);
if (MsgLen < 30) { /* not CAPI 64Bit */
memset(card->msgbuf + MsgLen, 0, 30 - MsgLen);
MsgLen = 30;
CAPIMSG_SETLEN(card->msgbuf, 30);
}
if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
skb_put_data(skb, card->msgbuf, MsgLen);
skb_put_data(skb, card->databuf, DataB3Len);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_MESSAGE:
ApplId = (unsigned) _get_word(&p);
MsgLen = _get_slice(&p, card->msgbuf);
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
skb_put_data(skb, card->msgbuf, MsgLen);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) {
spin_lock(&card->lock);
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
spin_unlock(&card->lock);
}
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_NEW_NCCI:
ApplId = _get_word(&p);
NCCI = _get_word(&p);
WindowSize = _get_word(&p);
spin_lock(&card->lock);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
spin_unlock(&card->lock);
break;
case RECEIVE_FREE_NCCI:
ApplId = _get_word(&p);
NCCI = _get_word(&p);
if (NCCI != 0xffffffff) {
spin_lock(&card->lock);
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
spin_unlock(&card->lock);
}
break;
case RECEIVE_START:
#ifdef AVM_B1DMA_POLLDEBUG
printk(KERN_INFO "%s: receive poll\n", card->name);
#endif
if (!suppress_pollack)
queue_pollack(card);
capi_ctr_resume_output(ctrl);
break;
case RECEIVE_STOP:
capi_ctr_suspend_output(ctrl);
break;
case RECEIVE_INIT:
cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
b1_parse_version(cinfo);
printk(KERN_INFO "%s: %s-card (%s) now active\n",
card->name,
cinfo->version[VER_CARDTYPE],
cinfo->version[VER_DRIVER]);
capi_ctr_ready(ctrl);
break;
case RECEIVE_TASK_READY:
ApplId = (unsigned) _get_word(&p);
MsgLen = _get_slice(&p, card->msgbuf);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = _get_slice(&p, card->msgbuf);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
default:
printk(KERN_ERR "%s: b1dma_interrupt: 0x%x ???\n",
card->name, b1cmd);
return;
}
}
/* ------------------------------------------------------------- */
static void b1dma_handle_interrupt(avmcard *card)
{
u32 status;
u32 newcsr;
spin_lock(&card->lock);
status = b1dma_readl(card, AMCC_INTCSR);
if ((status & ANY_S5933_INT) == 0) {
spin_unlock(&card->lock);
return;
}
newcsr = card->csr | (status & ALL_INT);
if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
b1dma_writel(card, newcsr, AMCC_INTCSR);
if ((status & RX_TC_INT) != 0) {
struct avmcard_dmainfo *dma = card->dma;
u32 rxlen;
if (card->dma->recvlen == 0) {
rxlen = b1dma_readl(card, AMCC_RXLEN);
if (rxlen == 0) {
dma->recvlen = *((u32 *)dma->recvbuf.dmabuf);
rxlen = (dma->recvlen + 3) & ~3;
b1dma_writel(card, dma->recvbuf.dmaaddr + 4, AMCC_RXPTR);
b1dma_writel(card, rxlen, AMCC_RXLEN);
#ifdef AVM_B1DMA_DEBUG
} else {
printk(KERN_ERR "%s: rx not complete (%d).\n",
card->name, rxlen);
#endif
}
} else {
spin_unlock(&card->lock);
b1dma_handle_rx(card);
dma->recvlen = 0;
spin_lock(&card->lock);
b1dma_writel(card, dma->recvbuf.dmaaddr, AMCC_RXPTR);
b1dma_writel(card, 4, AMCC_RXLEN);
}
}
if ((status & TX_TC_INT) != 0) {
if (skb_queue_empty(&card->dma->send_queue))
card->csr &= ~EN_TX_TC_INT;
else
b1dma_dispatch_tx(card);
}
b1dma_writel(card, card->csr, AMCC_INTCSR);
spin_unlock(&card->lock);
}
irqreturn_t b1dma_interrupt(int interrupt, void *devptr)
{
avmcard *card = devptr;
b1dma_handle_interrupt(card);
return IRQ_HANDLED;
}
/* ------------------------------------------------------------- */
static int b1dma_loaded(avmcard *card)
{
unsigned long stop;
unsigned char ans;
unsigned long tout = 2;
unsigned int base = card->port;
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_tx_empty(base))
break;
}
if (!b1_tx_empty(base)) {
printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n",
card->name);
return 0;
}
b1_put_byte(base, SEND_POLLACK);
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_rx_full(base)) {
if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) {
return 1;
}
printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans);
return 0;
}
}
printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name);
return 0;
}
/* ------------------------------------------------------------- */
static void b1dma_send_init(avmcard *card)
{
struct sk_buff *skb;
void *p;
skb = alloc_skb(15, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost register appl.\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_INIT);
_put_word(&p, CAPI_MAXAPPL);
_put_word(&p, AVM_NCCI_PER_CHANNEL * 30);
_put_word(&p, card->cardnr - 1);
skb_put(skb, (u8 *)p - (u8 *)skb->data);
b1dma_queue_tx(card, skb);
}
int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
int retval;
b1dma_reset(card);
if ((retval = b1_load_t4file(card, &data->firmware))) {
b1dma_reset(card);
printk(KERN_ERR "%s: failed to load t4file!!\n",
card->name);
return retval;
}
if (data->configuration.len > 0 && data->configuration.data) {
if ((retval = b1_load_config(card, &data->configuration))) {
b1dma_reset(card);
printk(KERN_ERR "%s: failed to load config!!\n",
card->name);
return retval;
}
}
if (!b1dma_loaded(card)) {
b1dma_reset(card);
printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
return -EIO;
}
card->csr = AVM_FLAG;
b1dma_writel(card, card->csr, AMCC_INTCSR);
b1dma_writel(card, EN_A2P_TRANSFERS | EN_P2A_TRANSFERS | A2P_HI_PRIORITY |
P2A_HI_PRIORITY | RESET_A2P_FLAGS | RESET_P2A_FLAGS,
AMCC_MCSR);
t1outp(card->port, 0x07, 0x30);
t1outp(card->port, 0x10, 0xF0);
card->dma->recvlen = 0;
b1dma_writel(card, card->dma->recvbuf.dmaaddr, AMCC_RXPTR);
b1dma_writel(card, 4, AMCC_RXLEN);
card->csr |= EN_RX_TC_INT;
b1dma_writel(card, card->csr, AMCC_INTCSR);
b1dma_send_init(card);
return 0;
}
void b1dma_reset_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
b1dma_reset(card);
memset(cinfo->version, 0, sizeof(cinfo->version));
capilib_release(&cinfo->ncci_head);
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_down(ctrl);
}
/* ------------------------------------------------------------- */
void b1dma_register_appl(struct capi_ctr *ctrl,
u16 appl,
capi_register_params *rp)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
struct sk_buff *skb;
int want = rp->level3cnt;
int nconn;
void *p;
if (want > 0) nconn = want;
else nconn = ctrl->profile.nbchannel * -want;
if (nconn == 0) nconn = ctrl->profile.nbchannel;
skb = alloc_skb(23, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost register appl.\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_REGISTER);
_put_word(&p, appl);
_put_word(&p, 1024 * (nconn + 1));
_put_word(&p, nconn);
_put_word(&p, rp->datablkcnt);
_put_word(&p, rp->datablklen);
skb_put(skb, (u8 *)p - (u8 *)skb->data);
b1dma_queue_tx(card, skb);
}
/* ------------------------------------------------------------- */
void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
struct sk_buff *skb;
void *p;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
capilib_release_appl(&cinfo->ncci_head, appl);
spin_unlock_irqrestore(&card->lock, flags);
skb = alloc_skb(7, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost release appl.\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_RELEASE);
_put_word(&p, appl);
skb_put(skb, (u8 *)p - (u8 *)skb->data);
b1dma_queue_tx(card, skb);
}
/* ------------------------------------------------------------- */
u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u16 retval = CAPI_NOERROR;
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
spin_unlock_irqrestore(&card->lock, flags);
}
if (retval == CAPI_NOERROR)
b1dma_queue_tx(card, skb);
return retval;
}
/* ------------------------------------------------------------- */
int b1dma_proc_show(struct seq_file *m, void *v)
{
struct capi_ctr *ctrl = m->private;
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u8 flag;
char *s;
u32 txoff, txlen, rxoff, rxlen, csr;
unsigned long flags;
seq_printf(m, "%-16s %s\n", "name", card->name);
seq_printf(m, "%-16s 0x%x\n", "io", card->port);
seq_printf(m, "%-16s %d\n", "irq", card->irq);
seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase);
switch (card->cardtype) {
case avm_b1isa: s = "B1 ISA"; break;
case avm_b1pci: s = "B1 PCI"; break;
case avm_b1pcmcia: s = "B1 PCMCIA"; break;
case avm_m1: s = "M1"; break;
case avm_m2: s = "M2"; break;
case avm_t1isa: s = "T1 ISA (HEMA)"; break;
case avm_t1pci: s = "T1 PCI"; break;
case avm_c4: s = "C4"; break;
case avm_c2: s = "C2"; break;
default: s = "???"; break;
}
seq_printf(m, "%-16s %s\n", "type", s);
if ((s = cinfo->version[VER_DRIVER]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[3];
if (flag)
seq_printf(m, "%-16s%s%s%s%s%s%s%s\n",
"protocol",
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
(flag & 0x04) ? " VN3" : "",
(flag & 0x08) ? " NI1" : "",
(flag & 0x10) ? " AUSTEL" : "",
(flag & 0x20) ? " ESS" : "",
(flag & 0x40) ? " 1TR6" : ""
);
}
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[5];
if (flag)
seq_printf(m, "%-16s%s%s%s%s\n",
"linetype",
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
(flag & 0x08) ? " leased line without D-channel" : "",
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
spin_lock_irqsave(&card->lock, flags);
txoff = (dma_addr_t)b1dma_readl(card, AMCC_TXPTR)-card->dma->sendbuf.dmaaddr;
txlen = b1dma_readl(card, AMCC_TXLEN);
rxoff = (dma_addr_t)b1dma_readl(card, AMCC_RXPTR)-card->dma->recvbuf.dmaaddr;
rxlen = b1dma_readl(card, AMCC_RXLEN);
csr = b1dma_readl(card, AMCC_INTCSR);
spin_unlock_irqrestore(&card->lock, flags);
seq_printf(m, "%-16s 0x%lx\n", "csr (cached)", (unsigned long)card->csr);
seq_printf(m, "%-16s 0x%lx\n", "csr", (unsigned long)csr);
seq_printf(m, "%-16s %lu\n", "txoff", (unsigned long)txoff);
seq_printf(m, "%-16s %lu\n", "txlen", (unsigned long)txlen);
seq_printf(m, "%-16s %lu\n", "rxoff", (unsigned long)rxoff);
seq_printf(m, "%-16s %lu\n", "rxlen", (unsigned long)rxlen);
return 0;
}
EXPORT_SYMBOL(b1dma_proc_show);
/* ------------------------------------------------------------- */
EXPORT_SYMBOL(b1dma_reset);
EXPORT_SYMBOL(t1pci_detect);
EXPORT_SYMBOL(b1pciv4_detect);
EXPORT_SYMBOL(b1dma_interrupt);
EXPORT_SYMBOL(b1dma_load_firmware);
EXPORT_SYMBOL(b1dma_reset_ctr);
EXPORT_SYMBOL(b1dma_register_appl);
EXPORT_SYMBOL(b1dma_release_appl);
EXPORT_SYMBOL(b1dma_send_message);
static int __init b1dma_init(void)
{
char *p;
char rev[32];
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, sizeof(rev));
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
printk(KERN_INFO "b1dma: revision %s\n", rev);
return 0;
}
static void __exit b1dma_exit(void)
{
}
module_init(b1dma_init);
module_exit(b1dma_exit);

View file

@ -1,243 +0,0 @@
/* $Id: b1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
*
* Module for AVM B1 ISA-card.
*
* Copyright 1999 by Carsten Paeth <calle@calle.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
/* ------------------------------------------------------------- */
static char *revision = "$Revision: 1.1.2.3 $";
/* ------------------------------------------------------------- */
MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 ISA card");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
static void b1isa_remove(struct pci_dev *pdev)
{
avmctrl_info *cinfo = pci_get_drvdata(pdev);
avmcard *card;
if (!cinfo)
return;
card = cinfo->card;
b1_reset(card->port);
b1_reset(card->port);
detach_capi_ctr(&cinfo->capi_ctrl);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
b1_free_card(card);
}
/* ------------------------------------------------------------- */
static char *b1isa_procinfo(struct capi_ctr *ctrl);
static int b1isa_probe(struct pci_dev *pdev)
{
avmctrl_info *cinfo;
avmcard *card;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "b1isa: no memory.\n");
retval = -ENOMEM;
goto err;
}
cinfo = card->ctrlinfo;
card->port = pci_resource_start(pdev, 0);
card->irq = pdev->irq;
card->cardtype = avm_b1isa;
sprintf(card->name, "b1isa-%x", card->port);
if (card->port != 0x150 && card->port != 0x250
&& card->port != 0x300 && card->port != 0x340) {
printk(KERN_WARNING "b1isa: invalid port 0x%x.\n", card->port);
retval = -EINVAL;
goto err_free;
}
if (b1_irq_table[card->irq & 0xf] == 0) {
printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq);
retval = -EINVAL;
goto err_free;
}
if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING "b1isa: ports 0x%03x-0x%03x in use.\n",
card->port, card->port + AVMB1_PORTLEN);
retval = -EBUSY;
goto err_free;
}
retval = request_irq(card->irq, b1_interrupt, 0, card->name, card);
if (retval) {
printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq);
goto err_release_region;
}
b1_reset(card->port);
if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n",
card->port, retval);
retval = -ENODEV;
goto err_free_irq;
}
b1_reset(card->port);
b1_getrevision(card);
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "b1isa";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1_register_appl;
cinfo->capi_ctrl.release_appl = b1_release_appl;
cinfo->capi_ctrl.send_message = b1_send_message;
cinfo->capi_ctrl.load_firmware = b1_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
cinfo->capi_ctrl.procinfo = b1isa_procinfo;
cinfo->capi_ctrl.proc_show = b1_proc_show;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_ERR "b1isa: attach controller failed.\n");
goto err_free_irq;
}
printk(KERN_INFO "b1isa: AVM B1 ISA at i/o %#x, irq %d, revision %d\n",
card->port, card->irq, card->revision);
pci_set_drvdata(pdev, cinfo);
return 0;
err_free_irq:
free_irq(card->irq, card);
err_release_region:
release_region(card->port, AVMB1_PORTLEN);
err_free:
b1_free_card(card);
err:
return retval;
}
static char *b1isa_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
#define MAX_CARDS 4
static struct pci_dev isa_dev[MAX_CARDS];
static int io[MAX_CARDS];
static int irq[MAX_CARDS];
module_param_hw_array(io, int, ioport, NULL, 0);
module_param_hw_array(irq, int, irq, NULL, 0);
MODULE_PARM_DESC(io, "I/O base address(es)");
MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
static int b1isa_add_card(struct capi_driver *driver, capicardparams *data)
{
int i;
for (i = 0; i < MAX_CARDS; i++) {
if (isa_dev[i].resource[0].start)
continue;
isa_dev[i].resource[0].start = data->port;
isa_dev[i].irq = data->irq;
if (b1isa_probe(&isa_dev[i]) == 0)
return 0;
}
return -ENODEV;
}
static struct capi_driver capi_driver_b1isa = {
.name = "b1isa",
.revision = "1.0",
.add_card = b1isa_add_card,
};
static int __init b1isa_init(void)
{
char *p;
char rev[32];
int i;
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
for (i = 0; i < MAX_CARDS; i++) {
if (!io[i])
break;
isa_dev[i].resource[0].start = io[i];
isa_dev[i].irq = irq[i];
if (b1isa_probe(&isa_dev[i]) != 0)
return -ENODEV;
}
strlcpy(capi_driver_b1isa.revision, rev, 32);
register_capi_driver(&capi_driver_b1isa);
printk(KERN_INFO "b1isa: revision %s\n", rev);
return 0;
}
static void __exit b1isa_exit(void)
{
int i;
for (i = 0; i < MAX_CARDS; i++) {
if (isa_dev[i].resource[0].start)
b1isa_remove(&isa_dev[i]);
}
unregister_capi_driver(&capi_driver_b1isa);
}
module_init(b1isa_init);
module_exit(b1isa_exit);

View file

@ -1,416 +0,0 @@
/* $Id: b1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
*
* Module for AVM B1 PCI-card.
*
* Copyright 1999 by Carsten Paeth <calle@calle.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/capi.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
/* ------------------------------------------------------------- */
static char *revision = "$Revision: 1.1.2.2 $";
/* ------------------------------------------------------------- */
static struct pci_device_id b1pci_pci_tbl[] = {
{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, PCI_ANY_ID, PCI_ANY_ID },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, b1pci_pci_tbl);
MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 PCI card");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
static char *b1pci_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev)
{
avmcard *card;
avmctrl_info *cinfo;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "b1pci: no memory.\n");
retval = -ENOMEM;
goto err;
}
cinfo = card->ctrlinfo;
sprintf(card->name, "b1pci-%x", p->port);
card->port = p->port;
card->irq = p->irq;
card->cardtype = avm_b1pci;
if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n",
card->port, card->port + AVMB1_PORTLEN);
retval = -EBUSY;
goto err_free;
}
b1_reset(card->port);
retval = b1_detect(card->port, card->cardtype);
if (retval) {
printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
card->port, retval);
retval = -ENODEV;
goto err_release_region;
}
b1_reset(card->port);
b1_getrevision(card);
retval = request_irq(card->irq, b1_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq);
retval = -EBUSY;
goto err_release_region;
}
cinfo->capi_ctrl.driver_name = "b1pci";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1_register_appl;
cinfo->capi_ctrl.release_appl = b1_release_appl;
cinfo->capi_ctrl.send_message = b1_send_message;
cinfo->capi_ctrl.load_firmware = b1_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
cinfo->capi_ctrl.procinfo = b1pci_procinfo;
cinfo->capi_ctrl.proc_show = b1_proc_show;
strcpy(cinfo->capi_ctrl.name, card->name);
cinfo->capi_ctrl.owner = THIS_MODULE;
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_ERR "b1pci: attach controller failed.\n");
goto err_free_irq;
}
if (card->revision >= 4) {
printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n",
card->port, card->irq, card->revision);
} else {
printk(KERN_INFO "b1pci: AVM B1 PCI at i/o %#x, irq %d, revision %d\n",
card->port, card->irq, card->revision);
}
pci_set_drvdata(pdev, card);
return 0;
err_free_irq:
free_irq(card->irq, card);
err_release_region:
release_region(card->port, AVMB1_PORTLEN);
err_free:
b1_free_card(card);
err:
return retval;
}
static void b1pci_remove(struct pci_dev *pdev)
{
avmcard *card = pci_get_drvdata(pdev);
avmctrl_info *cinfo = card->ctrlinfo;
unsigned int port = card->port;
b1_reset(port);
b1_reset(port);
detach_capi_ctr(&cinfo->capi_ctrl);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
b1_free_card(card);
}
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
/* ------------------------------------------------------------- */
static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->membase : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev)
{
avmcard *card;
avmctrl_info *cinfo;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "b1pci: no memory.\n");
retval = -ENOMEM;
goto err;
}
card->dma = avmcard_dma_alloc("b1pci", pdev, 2048 + 128, 2048 + 128);
if (!card->dma) {
printk(KERN_WARNING "b1pci: dma alloc.\n");
retval = -ENOMEM;
goto err_free;
}
cinfo = card->ctrlinfo;
sprintf(card->name, "b1pciv4-%x", p->port);
card->port = p->port;
card->irq = p->irq;
card->membase = p->membase;
card->cardtype = avm_b1pci;
if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n",
card->port, card->port + AVMB1_PORTLEN);
retval = -EBUSY;
goto err_free_dma;
}
card->mbase = ioremap(card->membase, 64);
if (!card->mbase) {
printk(KERN_NOTICE "b1pci: can't remap memory at 0x%lx\n",
card->membase);
retval = -ENOMEM;
goto err_release_region;
}
b1dma_reset(card);
retval = b1pciv4_detect(card);
if (retval) {
printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
card->port, retval);
retval = -ENODEV;
goto err_unmap;
}
b1dma_reset(card);
b1_getrevision(card);
retval = request_irq(card->irq, b1dma_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "b1pci: unable to get IRQ %d.\n",
card->irq);
retval = -EBUSY;
goto err_unmap;
}
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "b1pciv4";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1dma_register_appl;
cinfo->capi_ctrl.release_appl = b1dma_release_appl;
cinfo->capi_ctrl.send_message = b1dma_send_message;
cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr;
cinfo->capi_ctrl.procinfo = b1pciv4_procinfo;
cinfo->capi_ctrl.proc_show = b1dma_proc_show;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_ERR "b1pci: attach controller failed.\n");
goto err_free_irq;
}
card->cardnr = cinfo->capi_ctrl.cnr;
printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n",
card->port, card->irq, card->membase, card->revision);
pci_set_drvdata(pdev, card);
return 0;
err_free_irq:
free_irq(card->irq, card);
err_unmap:
iounmap(card->mbase);
err_release_region:
release_region(card->port, AVMB1_PORTLEN);
err_free_dma:
avmcard_dma_free(card->dma);
err_free:
b1_free_card(card);
err:
return retval;
}
static void b1pciv4_remove(struct pci_dev *pdev)
{
avmcard *card = pci_get_drvdata(pdev);
avmctrl_info *cinfo = card->ctrlinfo;
b1dma_reset(card);
detach_capi_ctr(&cinfo->capi_ctrl);
free_irq(card->irq, card);
iounmap(card->mbase);
release_region(card->port, AVMB1_PORTLEN);
avmcard_dma_free(card->dma);
b1_free_card(card);
}
#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
static int b1pci_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct capicardparams param;
int retval;
if (pci_enable_device(pdev) < 0) {
printk(KERN_ERR "b1pci: failed to enable AVM-B1\n");
return -ENODEV;
}
param.irq = pdev->irq;
if (pci_resource_start(pdev, 2)) { /* B1 PCI V4 */
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
pci_set_master(pdev);
#endif
param.membase = pci_resource_start(pdev, 0);
param.port = pci_resource_start(pdev, 2);
printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
param.port, param.irq, param.membase);
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
retval = b1pciv4_probe(&param, pdev);
#else
retval = b1pci_probe(&param, pdev);
#endif
if (retval != 0) {
printk(KERN_ERR "b1pci: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n",
param.port, param.irq, param.membase);
}
} else {
param.membase = 0;
param.port = pci_resource_start(pdev, 1);
printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
param.port, param.irq);
retval = b1pci_probe(&param, pdev);
if (retval != 0) {
printk(KERN_ERR "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n",
param.port, param.irq);
}
}
return retval;
}
static void b1pci_pci_remove(struct pci_dev *pdev)
{
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
avmcard *card = pci_get_drvdata(pdev);
if (card->dma)
b1pciv4_remove(pdev);
else
b1pci_remove(pdev);
#else
b1pci_remove(pdev);
#endif
}
static struct pci_driver b1pci_pci_driver = {
.name = "b1pci",
.id_table = b1pci_pci_tbl,
.probe = b1pci_pci_probe,
.remove = b1pci_pci_remove,
};
static struct capi_driver capi_driver_b1pci = {
.name = "b1pci",
.revision = "1.0",
};
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
static struct capi_driver capi_driver_b1pciv4 = {
.name = "b1pciv4",
.revision = "1.0",
};
#endif
static int __init b1pci_init(void)
{
char *p;
char rev[32];
int err;
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
err = pci_register_driver(&b1pci_pci_driver);
if (!err) {
strlcpy(capi_driver_b1pci.revision, rev, 32);
register_capi_driver(&capi_driver_b1pci);
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
strlcpy(capi_driver_b1pciv4.revision, rev, 32);
register_capi_driver(&capi_driver_b1pciv4);
#endif
printk(KERN_INFO "b1pci: revision %s\n", rev);
}
return err;
}
static void __exit b1pci_exit(void)
{
unregister_capi_driver(&capi_driver_b1pci);
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
unregister_capi_driver(&capi_driver_b1pciv4);
#endif
pci_unregister_driver(&b1pci_pci_driver);
}
module_init(b1pci_init);
module_exit(b1pci_exit);

View file

@ -1,224 +0,0 @@
/* $Id: b1pcmcia.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
*
* Module for AVM B1/M1/M2 PCMCIA-card.
*
* Copyright 1999 by Carsten Paeth <calle@calle.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/capi.h>
#include <linux/b1pcmcia.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
/* ------------------------------------------------------------- */
static char *revision = "$Revision: 1.1.2.2 $";
/* ------------------------------------------------------------- */
MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM PCMCIA cards");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
b1_reset(port);
b1_reset(port);
detach_capi_ctr(ctrl);
free_irq(card->irq, card);
b1_free_card(card);
}
/* ------------------------------------------------------------- */
static LIST_HEAD(cards);
static char *b1pcmcia_procinfo(struct capi_ctr *ctrl);
static int b1pcmcia_add_card(unsigned int port, unsigned irq,
enum avmcardtype cardtype)
{
avmctrl_info *cinfo;
avmcard *card;
char *cardname;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "b1pcmcia: no memory.\n");
retval = -ENOMEM;
goto err;
}
cinfo = card->ctrlinfo;
switch (cardtype) {
case avm_m1: sprintf(card->name, "m1-%x", port); break;
case avm_m2: sprintf(card->name, "m2-%x", port); break;
default: sprintf(card->name, "b1pcmcia-%x", port); break;
}
card->port = port;
card->irq = irq;
card->cardtype = cardtype;
retval = request_irq(card->irq, b1_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n",
card->irq);
retval = -EBUSY;
goto err_free;
}
b1_reset(card->port);
if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
printk(KERN_NOTICE "b1pcmcia: NO card at 0x%x (%d)\n",
card->port, retval);
retval = -ENODEV;
goto err_free_irq;
}
b1_reset(card->port);
b1_getrevision(card);
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "b1pcmcia";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1_register_appl;
cinfo->capi_ctrl.release_appl = b1_release_appl;
cinfo->capi_ctrl.send_message = b1_send_message;
cinfo->capi_ctrl.load_firmware = b1_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo;
cinfo->capi_ctrl.proc_show = b1_proc_show;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_ERR "b1pcmcia: attach controller failed.\n");
goto err_free_irq;
}
switch (cardtype) {
case avm_m1: cardname = "M1"; break;
case avm_m2: cardname = "M2"; break;
default: cardname = "B1 PCMCIA"; break;
}
printk(KERN_INFO "b1pcmcia: AVM %s at i/o %#x, irq %d, revision %d\n",
cardname, card->port, card->irq, card->revision);
list_add(&card->list, &cards);
return cinfo->capi_ctrl.cnr;
err_free_irq:
free_irq(card->irq, card);
err_free:
b1_free_card(card);
err:
return retval;
}
/* ------------------------------------------------------------- */
static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
int b1pcmcia_addcard_b1(unsigned int port, unsigned irq)
{
return b1pcmcia_add_card(port, irq, avm_b1pcmcia);
}
int b1pcmcia_addcard_m1(unsigned int port, unsigned irq)
{
return b1pcmcia_add_card(port, irq, avm_m1);
}
int b1pcmcia_addcard_m2(unsigned int port, unsigned irq)
{
return b1pcmcia_add_card(port, irq, avm_m2);
}
int b1pcmcia_delcard(unsigned int port, unsigned irq)
{
struct list_head *l;
avmcard *card;
list_for_each(l, &cards) {
card = list_entry(l, avmcard, list);
if (card->port == port && card->irq == irq) {
b1pcmcia_remove_ctr(&card->ctrlinfo[0].capi_ctrl);
return 0;
}
}
return -ESRCH;
}
EXPORT_SYMBOL(b1pcmcia_addcard_b1);
EXPORT_SYMBOL(b1pcmcia_addcard_m1);
EXPORT_SYMBOL(b1pcmcia_addcard_m2);
EXPORT_SYMBOL(b1pcmcia_delcard);
static struct capi_driver capi_driver_b1pcmcia = {
.name = "b1pcmcia",
.revision = "1.0",
};
static int __init b1pcmcia_init(void)
{
char *p;
char rev[32];
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
strlcpy(capi_driver_b1pcmcia.revision, rev, 32);
register_capi_driver(&capi_driver_b1pcmcia);
printk(KERN_INFO "b1pci: revision %s\n", rev);
return 0;
}
static void __exit b1pcmcia_exit(void)
{
unregister_capi_driver(&capi_driver_b1pcmcia);
}
module_init(b1pcmcia_init);
module_exit(b1pcmcia_exit);

File diff suppressed because it is too large Load diff

View file

@ -1,594 +0,0 @@
/* $Id: t1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
*
* Module for AVM T1 HEMA-card.
*
* Copyright 1999 by Carsten Paeth <calle@calle.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <linux/netdevice.h>
#include <linux/kernelcapi.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/gfp.h>
#include <asm/io.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
/* ------------------------------------------------------------- */
static char *revision = "$Revision: 1.1.2.3 $";
/* ------------------------------------------------------------- */
MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 HEMA ISA card");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
static int hema_irq_table[16] =
{0,
0,
0,
0x80, /* irq 3 */
0,
0x90, /* irq 5 */
0,
0xA0, /* irq 7 */
0,
0xB0, /* irq 9 */
0xC0, /* irq 10 */
0xD0, /* irq 11 */
0xE0, /* irq 12 */
0,
0,
0xF0, /* irq 15 */
};
static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr)
{
unsigned char cregs[8];
unsigned char reverse_cardnr;
unsigned char dummy;
int i;
reverse_cardnr = ((cardnr & 0x01) << 3) | ((cardnr & 0x02) << 1)
| ((cardnr & 0x04) >> 1) | ((cardnr & 0x08) >> 3);
cregs[0] = (HEMA_VERSION_ID << 4) | (reverse_cardnr & 0xf);
cregs[1] = 0x00; /* fast & slow link connected to CON1 */
cregs[2] = 0x05; /* fast link 20MBit, slow link 20 MBit */
cregs[3] = 0;
cregs[4] = 0x11; /* zero wait state */
cregs[5] = hema_irq_table[irq & 0xf];
cregs[6] = 0;
cregs[7] = 0;
/*
* no one else should use the ISA bus in this moment,
* but no function there to prevent this :-(
* save_flags(flags); cli();
*/
/* board reset */
t1outp(base, T1_RESETBOARD, 0xf);
mdelay(100);
dummy = t1inp(base, T1_FASTLINK + T1_OUTSTAT); /* first read */
/* write config */
dummy = (base >> 4) & 0xff;
for (i = 1; i <= 0xf; i++) t1outp(base, i, dummy);
t1outp(base, HEMA_PAL_ID & 0xf, dummy);
t1outp(base, HEMA_PAL_ID >> 4, cregs[0]);
for (i = 1; i < 7; i++) t1outp(base, 0, cregs[i]);
t1outp(base, ((base >> 4)) & 0x3, cregs[7]);
/* restore_flags(flags); */
mdelay(100);
t1outp(base, T1_FASTLINK + T1_RESETLINK, 0);
t1outp(base, T1_SLOWLINK + T1_RESETLINK, 0);
mdelay(10);
t1outp(base, T1_FASTLINK + T1_RESETLINK, 1);
t1outp(base, T1_SLOWLINK + T1_RESETLINK, 1);
mdelay(100);
t1outp(base, T1_FASTLINK + T1_RESETLINK, 0);
t1outp(base, T1_SLOWLINK + T1_RESETLINK, 0);
mdelay(10);
t1outp(base, T1_FASTLINK + T1_ANALYSE, 0);
mdelay(5);
t1outp(base, T1_SLOWLINK + T1_ANALYSE, 0);
if (t1inp(base, T1_FASTLINK + T1_OUTSTAT) != 0x1) /* tx empty */
return 1;
if (t1inp(base, T1_FASTLINK + T1_INSTAT) != 0x0) /* rx empty */
return 2;
if (t1inp(base, T1_FASTLINK + T1_IRQENABLE) != 0x0)
return 3;
if ((t1inp(base, T1_FASTLINK + T1_FIFOSTAT) & 0xf0) != 0x70)
return 4;
if ((t1inp(base, T1_FASTLINK + T1_IRQMASTER) & 0x0e) != 0)
return 5;
if ((t1inp(base, T1_FASTLINK + T1_IDENT) & 0x7d) != 1)
return 6;
if (t1inp(base, T1_SLOWLINK + T1_OUTSTAT) != 0x1) /* tx empty */
return 7;
if ((t1inp(base, T1_SLOWLINK + T1_IRQMASTER) & 0x0e) != 0)
return 8;
if ((t1inp(base, T1_SLOWLINK + T1_IDENT) & 0x7d) != 0)
return 9;
return 0;
}
static irqreturn_t t1isa_interrupt(int interrupt, void *devptr)
{
avmcard *card = devptr;
avmctrl_info *cinfo = &card->ctrlinfo[0];
struct capi_ctr *ctrl = &cinfo->capi_ctrl;
unsigned char b1cmd;
struct sk_buff *skb;
unsigned ApplId;
unsigned MsgLen;
unsigned DataB3Len;
unsigned NCCI;
unsigned WindowSize;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
while (b1_rx_full(card->port)) {
b1cmd = b1_get_byte(card->port);
switch (b1cmd) {
case RECEIVE_DATA_B3_IND:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = t1_get_slice(card->port, card->msgbuf);
DataB3Len = t1_get_slice(card->port, card->databuf);
spin_unlock_irqrestore(&card->lock, flags);
if (MsgLen < 30) { /* not CAPI 64Bit */
memset(card->msgbuf + MsgLen, 0, 30 - MsgLen);
MsgLen = 30;
CAPIMSG_SETLEN(card->msgbuf, 30);
}
if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
skb_put_data(skb, card->msgbuf, MsgLen);
skb_put_data(skb, card->databuf, DataB3Len);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_MESSAGE:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = t1_get_slice(card->port, card->msgbuf);
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
spin_unlock_irqrestore(&card->lock, flags);
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
skb_put_data(skb, card->msgbuf, MsgLen);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_NEW_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
WindowSize = b1_get_word(card->port);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_FREE_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
if (NCCI != 0xffffffff)
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_START:
b1_put_byte(card->port, SEND_POLLACK);
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_resume_output(ctrl);
break;
case RECEIVE_STOP:
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_suspend_output(ctrl);
break;
case RECEIVE_INIT:
cinfo->versionlen = t1_get_slice(card->port, cinfo->versionbuf);
spin_unlock_irqrestore(&card->lock, flags);
b1_parse_version(cinfo);
printk(KERN_INFO "%s: %s-card (%s) now active\n",
card->name,
cinfo->version[VER_CARDTYPE],
cinfo->version[VER_DRIVER]);
capi_ctr_ready(ctrl);
break;
case RECEIVE_TASK_READY:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = t1_get_slice(card->port, card->msgbuf);
spin_unlock_irqrestore(&card->lock, flags);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = t1_get_slice(card->port, card->msgbuf);
spin_unlock_irqrestore(&card->lock, flags);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
case 0xff:
spin_unlock_irqrestore(&card->lock, flags);
printk(KERN_ERR "%s: card reseted ?\n", card->name);
return IRQ_HANDLED;
default:
spin_unlock_irqrestore(&card->lock, flags);
printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
card->name, b1cmd);
return IRQ_NONE;
}
}
return IRQ_HANDLED;
}
/* ------------------------------------------------------------- */
static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
int retval;
t1_disable_irq(port);
b1_reset(port);
if ((retval = b1_load_t4file(card, &data->firmware))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load t4file!!\n",
card->name);
return retval;
}
if (data->configuration.len > 0 && data->configuration.data) {
if ((retval = b1_load_config(card, &data->configuration))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load config!!\n",
card->name);
return retval;
}
}
if (!b1_loaded(card)) {
printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
return -EIO;
}
spin_lock_irqsave(&card->lock, flags);
b1_setinterrupt(port, card->irq, card->cardtype);
b1_put_byte(port, SEND_INIT);
b1_put_word(port, CAPI_MAXAPPL);
b1_put_word(port, AVM_NCCI_PER_CHANNEL * 30);
b1_put_word(port, ctrl->cnr - 1);
spin_unlock_irqrestore(&card->lock, flags);
return 0;
}
static void t1isa_reset_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
t1_disable_irq(port);
b1_reset(port);
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
spin_lock_irqsave(&card->lock, flags);
capilib_release(&cinfo->ncci_head);
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_down(ctrl);
}
static void t1isa_remove(struct pci_dev *pdev)
{
avmctrl_info *cinfo = pci_get_drvdata(pdev);
avmcard *card;
if (!cinfo)
return;
card = cinfo->card;
t1_disable_irq(card->port);
b1_reset(card->port);
b1_reset(card->port);
t1_reset(card->port);
detach_capi_ctr(&cinfo->capi_ctrl);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
b1_free_card(card);
}
/* ------------------------------------------------------------- */
static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
static char *t1isa_procinfo(struct capi_ctr *ctrl);
static int t1isa_probe(struct pci_dev *pdev, int cardnr)
{
avmctrl_info *cinfo;
avmcard *card;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "t1isa: no memory.\n");
retval = -ENOMEM;
goto err;
}
cinfo = card->ctrlinfo;
card->port = pci_resource_start(pdev, 0);
card->irq = pdev->irq;
card->cardtype = avm_t1isa;
card->cardnr = cardnr;
sprintf(card->name, "t1isa-%x", card->port);
if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) {
printk(KERN_WARNING "t1isa: invalid port 0x%x.\n", card->port);
retval = -EINVAL;
goto err_free;
}
if (hema_irq_table[card->irq & 0xf] == 0) {
printk(KERN_WARNING "t1isa: irq %d not valid.\n", card->irq);
retval = -EINVAL;
goto err_free;
}
if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_INFO "t1isa: ports 0x%03x-0x%03x in use.\n",
card->port, card->port + AVMB1_PORTLEN);
retval = -EBUSY;
goto err_free;
}
retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card);
if (retval) {
printk(KERN_INFO "t1isa: unable to get IRQ %d.\n", card->irq);
retval = -EBUSY;
goto err_release_region;
}
if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) {
printk(KERN_INFO "t1isa: NO card at 0x%x (%d)\n",
card->port, retval);
retval = -ENODEV;
goto err_free_irq;
}
t1_disable_irq(card->port);
b1_reset(card->port);
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "t1isa";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1_register_appl;
cinfo->capi_ctrl.release_appl = b1_release_appl;
cinfo->capi_ctrl.send_message = t1isa_send_message;
cinfo->capi_ctrl.load_firmware = t1isa_load_firmware;
cinfo->capi_ctrl.reset_ctr = t1isa_reset_ctr;
cinfo->capi_ctrl.procinfo = t1isa_procinfo;
cinfo->capi_ctrl.proc_show = b1_proc_show;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_INFO "t1isa: attach controller failed.\n");
goto err_free_irq;
}
printk(KERN_INFO "t1isa: AVM T1 ISA at i/o %#x, irq %d, card %d\n",
card->port, card->irq, card->cardnr);
pci_set_drvdata(pdev, cinfo);
return 0;
err_free_irq:
free_irq(card->irq, card);
err_release_region:
release_region(card->port, AVMB1_PORTLEN);
err_free:
b1_free_card(card);
err:
return retval;
}
static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
u16 len = CAPIMSG_LEN(skb->data);
u8 cmd = CAPIMSG_COMMAND(skb->data);
u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
u16 dlen, retval;
spin_lock_irqsave(&card->lock, flags);
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
if (retval != CAPI_NOERROR) {
spin_unlock_irqrestore(&card->lock, flags);
return retval;
}
dlen = CAPIMSG_DATALEN(skb->data);
b1_put_byte(port, SEND_DATA_B3_REQ);
t1_put_slice(port, skb->data, len);
t1_put_slice(port, skb->data + len, dlen);
} else {
b1_put_byte(port, SEND_MESSAGE);
t1_put_slice(port, skb->data, len);
}
spin_unlock_irqrestore(&card->lock, flags);
dev_kfree_skb_any(skb);
return CAPI_NOERROR;
}
/* ------------------------------------------------------------- */
static char *t1isa_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d %d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->cardnr : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
#define MAX_CARDS 4
static struct pci_dev isa_dev[MAX_CARDS];
static int io[MAX_CARDS];
static int irq[MAX_CARDS];
static int cardnr[MAX_CARDS];
module_param_hw_array(io, int, ioport, NULL, 0);
module_param_hw_array(irq, int, irq, NULL, 0);
module_param_array(cardnr, int, NULL, 0);
MODULE_PARM_DESC(io, "I/O base address(es)");
MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
MODULE_PARM_DESC(cardnr, "Card number(s) (as jumpered)");
static int t1isa_add_card(struct capi_driver *driver, capicardparams *data)
{
int i;
for (i = 0; i < MAX_CARDS; i++) {
if (isa_dev[i].resource[0].start)
continue;
isa_dev[i].resource[0].start = data->port;
isa_dev[i].irq = data->irq;
if (t1isa_probe(&isa_dev[i], data->cardnr) == 0)
return 0;
}
return -ENODEV;
}
static struct capi_driver capi_driver_t1isa = {
.name = "t1isa",
.revision = "1.0",
.add_card = t1isa_add_card,
};
static int __init t1isa_init(void)
{
char rev[32];
char *p;
int i;
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
for (i = 0; i < MAX_CARDS; i++) {
if (!io[i])
break;
isa_dev[i].resource[0].start = io[i];
isa_dev[i].irq = irq[i];
if (t1isa_probe(&isa_dev[i], cardnr[i]) != 0)
return -ENODEV;
}
strlcpy(capi_driver_t1isa.revision, rev, 32);
register_capi_driver(&capi_driver_t1isa);
printk(KERN_INFO "t1isa: revision %s\n", rev);
return 0;
}
static void __exit t1isa_exit(void)
{
int i;
unregister_capi_driver(&capi_driver_t1isa);
for (i = 0; i < MAX_CARDS; i++) {
if (!io[i])
break;
t1isa_remove(&isa_dev[i]);
}
}
module_init(t1isa_init);
module_exit(t1isa_exit);

View file

@ -1,259 +0,0 @@
/* $Id: t1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
*
* Module for AVM T1 PCI-card.
*
* Copyright 1999 by Carsten Paeth <calle@calle.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/capi.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
#undef CONFIG_T1PCI_DEBUG
#undef CONFIG_T1PCI_POLLDEBUG
/* ------------------------------------------------------------- */
static char *revision = "$Revision: 1.1.2.2 $";
/* ------------------------------------------------------------- */
static struct pci_device_id t1pci_pci_tbl[] = {
{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, PCI_ANY_ID, PCI_ANY_ID },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, t1pci_pci_tbl);
MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 PCI card");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
static char *t1pci_procinfo(struct capi_ctr *ctrl);
static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev)
{
avmcard *card;
avmctrl_info *cinfo;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "t1pci: no memory.\n");
retval = -ENOMEM;
goto err;
}
card->dma = avmcard_dma_alloc("t1pci", pdev, 2048 + 128, 2048 + 128);
if (!card->dma) {
printk(KERN_WARNING "t1pci: no memory.\n");
retval = -ENOMEM;
goto err_free;
}
cinfo = card->ctrlinfo;
sprintf(card->name, "t1pci-%x", p->port);
card->port = p->port;
card->irq = p->irq;
card->membase = p->membase;
card->cardtype = avm_t1pci;
if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING "t1pci: ports 0x%03x-0x%03x in use.\n",
card->port, card->port + AVMB1_PORTLEN);
retval = -EBUSY;
goto err_free_dma;
}
card->mbase = ioremap(card->membase, 64);
if (!card->mbase) {
printk(KERN_NOTICE "t1pci: can't remap memory at 0x%lx\n",
card->membase);
retval = -EIO;
goto err_release_region;
}
b1dma_reset(card);
retval = t1pci_detect(card);
if (retval != 0) {
if (retval < 6)
printk(KERN_NOTICE "t1pci: NO card at 0x%x (%d)\n",
card->port, retval);
else
printk(KERN_NOTICE "t1pci: card at 0x%x, but cable not connected or T1 has no power (%d)\n",
card->port, retval);
retval = -EIO;
goto err_unmap;
}
b1dma_reset(card);
retval = request_irq(card->irq, b1dma_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "t1pci: unable to get IRQ %d.\n", card->irq);
retval = -EBUSY;
goto err_unmap;
}
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "t1pci";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1dma_register_appl;
cinfo->capi_ctrl.release_appl = b1dma_release_appl;
cinfo->capi_ctrl.send_message = b1dma_send_message;
cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr;
cinfo->capi_ctrl.procinfo = t1pci_procinfo;
cinfo->capi_ctrl.proc_show = b1dma_proc_show;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_ERR "t1pci: attach controller failed.\n");
retval = -EBUSY;
goto err_free_irq;
}
card->cardnr = cinfo->capi_ctrl.cnr;
printk(KERN_INFO "t1pci: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n",
card->port, card->irq, card->membase);
pci_set_drvdata(pdev, card);
return 0;
err_free_irq:
free_irq(card->irq, card);
err_unmap:
iounmap(card->mbase);
err_release_region:
release_region(card->port, AVMB1_PORTLEN);
err_free_dma:
avmcard_dma_free(card->dma);
err_free:
b1_free_card(card);
err:
return retval;
}
/* ------------------------------------------------------------- */
static void t1pci_remove(struct pci_dev *pdev)
{
avmcard *card = pci_get_drvdata(pdev);
avmctrl_info *cinfo = card->ctrlinfo;
b1dma_reset(card);
detach_capi_ctr(&cinfo->capi_ctrl);
free_irq(card->irq, card);
iounmap(card->mbase);
release_region(card->port, AVMB1_PORTLEN);
avmcard_dma_free(card->dma);
b1_free_card(card);
}
/* ------------------------------------------------------------- */
static char *t1pci_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->membase : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static int t1pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
struct capicardparams param;
int retval;
if (pci_enable_device(dev) < 0) {
printk(KERN_ERR "t1pci: failed to enable AVM-T1-PCI\n");
return -ENODEV;
}
pci_set_master(dev);
param.port = pci_resource_start(dev, 1);
param.irq = dev->irq;
param.membase = pci_resource_start(dev, 0);
printk(KERN_INFO "t1pci: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
param.port, param.irq, param.membase);
retval = t1pci_add_card(&param, dev);
if (retval != 0) {
printk(KERN_ERR "t1pci: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
param.port, param.irq, param.membase);
pci_disable_device(dev);
return -ENODEV;
}
return 0;
}
static struct pci_driver t1pci_pci_driver = {
.name = "t1pci",
.id_table = t1pci_pci_tbl,
.probe = t1pci_probe,
.remove = t1pci_remove,
};
static struct capi_driver capi_driver_t1pci = {
.name = "t1pci",
.revision = "1.0",
};
static int __init t1pci_init(void)
{
char *p;
char rev[32];
int err;
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
err = pci_register_driver(&t1pci_pci_driver);
if (!err) {
strlcpy(capi_driver_t1pci.revision, rev, 32);
register_capi_driver(&capi_driver_t1pci);
printk(KERN_INFO "t1pci: revision %s\n", rev);
}
return err;
}
static void __exit t1pci_exit(void)
{
unregister_capi_driver(&capi_driver_t1pci);
pci_unregister_driver(&t1pci_pci_driver);
}
module_init(t1pci_init);
module_exit(t1pci_exit);

View file

@ -79,11 +79,14 @@ config MISDN_NETJET
depends on PCI
depends on TTY
select MISDN_IPAC
select ISDN_HDLC
select ISDN_I4L
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

View file

@ -15,3 +15,5 @@ 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

View file

@ -12,8 +12,8 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/crc-ccitt.h>
#include <linux/isdn/hdlc.h>
#include <linux/bitrev.h>
#include "isdnhdlc.h"
/*-------------------------------------------------------------------*/

View file

@ -0,0 +1,69 @@
/* 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__ */

View file

@ -29,7 +29,7 @@
#include "ipac.h"
#include "iohelper.h"
#include "netjet.h"
#include <linux/isdn/hdlc.h>
#include "isdnhdlc.h"
#define NETJET_REV "2.0"

View file

@ -1,423 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "Passive cards"
config ISDN_DRV_HISAX
tristate "HiSax SiemensChipSet driver support"
select CRC_CCITT
---help---
This is a driver supporting the Siemens chipset on various
ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, Teles
S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many
compatibles).
HiSax is just the name of this driver, not the name of any hardware.
If you have a card with such a chipset, you should say Y here and
also to the configuration option of the driver for your particular
card, below.
if ISDN_DRV_HISAX
comment "D-channel protocol features"
config HISAX_EURO
bool "HiSax Support for EURO/DSS1"
help
Say Y or N according to the D-channel protocol which your local
telephone service company provides.
The call control protocol E-DSS1 is used in most European countries.
If unsure, say Y.
config DE_AOC
bool "Support for german chargeinfo"
depends on HISAX_EURO
help
If you want that the HiSax hardware driver sends messages to the
upper level of the isdn code on each AOCD (Advice Of Charge, During
the call -- transmission of the fee information during a call) and
on each AOCE (Advice Of Charge, at the End of the call --
transmission of fee information at the end of the call), say Y here.
This works only in Germany.
config HISAX_NO_SENDCOMPLETE
bool "Disable sending complete"
depends on HISAX_EURO
help
If you have trouble with some ugly exchanges or you live in
Australia select this option.
config HISAX_NO_LLC
bool "Disable sending low layer compatibility"
depends on HISAX_EURO
help
If you have trouble with some ugly exchanges try to select this
option.
config HISAX_NO_KEYPAD
bool "Disable keypad protocol option"
depends on HISAX_EURO
help
If you like to send special dial strings including * or # without
using the keypad protocol, select this option.
config HISAX_1TR6
bool "HiSax Support for german 1TR6"
help
Say Y or N according to the D-channel protocol which your local
telephone service company provides.
1TR6 is an old call control protocol which was used in Germany
before E-DSS1 was established. Nowadays, all new lines in Germany
use E-DSS1.
config HISAX_NI1
bool "HiSax Support for US NI1"
help
Enable this if you like to use ISDN in US on a NI1 basic rate
interface.
config HISAX_MAX_CARDS
int "Maximum number of cards supported by HiSax"
default "8"
help
This option allows you to specify the maximum number of cards which
the HiSax driver will be able to handle.
comment "HiSax supported cards"
config HISAX_16_0
bool "Teles 16.0/8.0"
depends on ISA
help
This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8
and many compatibles.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port/shmem settings.
config HISAX_16_3
bool "Teles 16.3 or PNP or PCMCIA"
help
This enables HiSax support for the Teles ISDN-cards S0-16.3 the
Teles/Creatix PnP and the Teles PCMCIA.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_TELESPCI
bool "Teles PCI"
depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN)))
help
This enables HiSax support for the Teles PCI.
See <file:Documentation/isdn/README.HiSax> on how to configure it.
config HISAX_S0BOX
bool "Teles S0Box"
help
This enables HiSax support for the Teles/Creatix parallel port
S0BOX. See <file:Documentation/isdn/README.HiSax> on how to
configure it.
config HISAX_AVM_A1
bool "AVM A1 (Fritz)"
depends on ISA
help
This enables HiSax support for the AVM A1 (aka "Fritz").
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_FRITZPCI
bool "AVM PnP/PCI (Fritz!PnP/PCI)"
depends on BROKEN || !PPC64
help
This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI".
See <file:Documentation/isdn/README.HiSax> on how to configure it.
config HISAX_AVM_A1_PCMCIA
bool "AVM A1 PCMCIA (Fritz)"
help
This enables HiSax support for the AVM A1 "Fritz!PCMCIA").
See <file:Documentation/isdn/README.HiSax> on how to configure it.
config HISAX_ELSA
bool "Elsa cards"
help
This enables HiSax support for the Elsa Mircolink ISA cards, for the
Elsa Quickstep series cards and Elsa PCMCIA.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_IX1MICROR2
bool "ITK ix1-micro Revision 2"
depends on ISA
help
This enables HiSax support for the ITK ix1-micro Revision 2 card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_DIEHLDIVA
bool "Eicon.Diehl Diva cards"
help
This enables HiSax support for the Eicon.Diehl Diva none PRO
versions passive ISDN cards.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_ASUSCOM
bool "ASUSCOM ISA cards"
depends on ISA
help
This enables HiSax support for the AsusCom and their OEM versions
passive ISDN ISA cards.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_TELEINT
bool "TELEINT cards"
depends on ISA
help
This enables HiSax support for the TELEINT SA1 semiactiv ISDN card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_HFCS
bool "HFC-S based cards"
depends on ISA
help
This enables HiSax support for the HFC-S 2BDS0 based cards, like
teles 16.3c.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_SEDLBAUER
bool "Sedlbauer cards"
help
This enables HiSax support for the Sedlbauer passive ISDN cards.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_SPORTSTER
bool "USR Sportster internal TA"
depends on ISA
help
This enables HiSax support for the USR Sportster internal TA card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_MIC
bool "MIC card"
depends on ISA
help
This enables HiSax support for the ITH MIC card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_NETJET
bool "NETjet card"
depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE))
depends on VIRT_TO_BUS
help
This enables HiSax support for the NetJet from Traverse
Technologies.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_NETJET_U
bool "NETspider U card"
depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE))
depends on VIRT_TO_BUS
help
This enables HiSax support for the Netspider U interface ISDN card
from Traverse Technologies.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_NICCY
bool "Niccy PnP/PCI card"
help
This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_ISURF
bool "Siemens I-Surf card"
depends on ISA
help
This enables HiSax support for the Siemens I-Talk/I-Surf card with
ISAR chip.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_HSTSAPHIR
bool "HST Saphir card"
depends on ISA
help
This enables HiSax support for the HST Saphir card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_BKM_A4T
bool "Telekom A4T card"
depends on PCI
help
This enables HiSax support for the Telekom A4T card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_SCT_QUADRO
bool "Scitel Quadro card"
depends on PCI
help
This enables HiSax support for the Scitel Quadro card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_GAZEL
bool "Gazel cards"
help
This enables HiSax support for the Gazel cards.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_HFC_PCI
bool "HFC PCI-Bus cards"
depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN)))
help
This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
For more information see under
<file:Documentation/isdn/README.hfc-pci>.
config HISAX_W6692
bool "Winbond W6692 based cards"
depends on PCI
help
This enables HiSax support for Winbond W6692 based PCI ISDN cards.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_HFC_SX
bool "HFC-S+, HFC-SP, HFC-PCMCIA cards"
help
This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA
cards. This code is not finished yet.
config HISAX_ENTERNOW_PCI
bool "Formula-n enter:now PCI card"
depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN)))
help
This enables HiSax support for the Formula-n enter:now PCI
ISDN card.
config HISAX_DEBUG
bool "HiSax debugging"
help
This enables debugging code in the new-style HiSax drivers, i.e.
the ST5481 USB driver currently.
If in doubt, say yes.
comment "HiSax PCMCIA card service modules"
config HISAX_SEDLBAUER_CS
tristate "Sedlbauer PCMCIA cards"
depends on PCMCIA && HISAX_SEDLBAUER
help
This enables the PCMCIA client driver for the Sedlbauer Speed Star
and Speed Star II cards.
config HISAX_ELSA_CS
tristate "ELSA PCMCIA MicroLink cards"
depends on PCMCIA && HISAX_ELSA
help
This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink
card.
config HISAX_AVM_A1_CS
tristate "AVM A1 PCMCIA cards"
depends on PCMCIA && ISDN_DRV_HISAX
help
This enables the PCMCIA client driver for the AVM A1 / Fritz!Card
PCMCIA cards.
config HISAX_TELES_CS
tristate "TELES PCMCIA cards"
depends on PCMCIA && HISAX_16_3
help
This enables the PCMCIA client driver for the Teles PCMCIA cards.
comment "HiSax sub driver modules"
config HISAX_ST5481
tristate "ST5481 USB ISDN modem"
depends on USB
select ISDN_HDLC
select CRC_CCITT
select BITREVERSE
help
This enables the driver for ST5481 based USB ISDN adapters,
e.g. the BeWan Gazel 128 USB
config HISAX_HFCUSB
tristate "HFC USB based ISDN modems"
depends on USB
help
This enables the driver for HFC USB based ISDN modems.
config HISAX_HFC4S8S
tristate "HFC-4S/8S based ISDN cards"
help
This enables the driver for HFC-4S/8S based ISDN cards.
config HISAX_FRITZ_PCIPNP
tristate "AVM Fritz!Card PCI/PCIv2/PnP support"
depends on PCI
help
This enables the driver for the AVM Fritz!Card PCI,
Fritz!Card PCI v2 and Fritz!Card PnP.
(the latter also needs you to select "ISA Plug and Play support"
from the menu "Plug and Play configuration")
endif
endmenu

View file

@ -1,60 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for the hisax ISDN device driver
# The target object and module list name.
# Define maximum number of cards
ccflags-y := -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o
obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o
obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o
obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o
obj-$(CONFIG_HISAX_TELES_CS) += teles_cs.o
obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o
obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o
obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o
obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o
# Multipart objects.
hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \
st5481_b.o
hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
lmgr.o q931.o callc.o fsm.o
hisax-$(CONFIG_HISAX_EURO) += l3dss1.o
hisax-$(CONFIG_HISAX_NI1) += l3ni1.o
hisax-$(CONFIG_HISAX_1TR6) += l3_1tr6.o
hisax-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
hisax-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipacx.o
hisax-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
hisax-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o \
isar.o
hisax-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o
hisax-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o
hisax-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o
hisax-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o
hisax-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o
hisax-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o
hisax-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o
hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_W6692) += w6692.o
hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o

View file

@ -1,794 +0,0 @@
/* gerdes_amd7930.c,v 0.99 2001/10/02
*
* gerdes_amd7930.c Amd 79C30A and 79C32A specific routines
* (based on HiSax driver by Karsten Keil)
*
* Author Christoph Ersfeld <info@formula-n.de>
* Formula-n Europe AG (www.formula-n.com)
* previously Gerdes AG
*
*
* This file is (c) under GNU PUBLIC LICENSE
*
*
* Notes:
* Version 0.99 is the first release of this driver and there are
* certainly a few bugs.
*
* Please don't report any malfunction to me without sending
* (compressed) debug-logs.
* It would be nearly impossible to retrace it.
*
* Log D-channel-processing as follows:
*
* 1. Load hisax with card-specific parameters, this example ist for
* Formula-n enter:now ISDN PCI and compatible
* (f.e. Gerdes Power ISDN PCI)
*
* modprobe hisax type=41 protocol=2 id=gerdes
*
* if you chose an other value for id, you need to modify the
* code below, too.
*
* 2. set debug-level
*
* hisaxctrl gerdes 1 0x3ff
* hisaxctrl gerdes 11 0x4f
* cat /dev/isdnctrl >> ~/log &
*
* Please take also a look into /var/log/messages if there is
* anything importand concerning HISAX.
*
*
* Credits:
* Programming the driver for Formula-n enter:now ISDN PCI and
* necessary this driver for the used Amd 7930 D-channel-controller
* was spnsored by Formula-n Europe AG.
* Thanks to Karsten Keil and Petr Novak, who gave me support in
* Hisax-specific questions.
* I want so say special thanks to Carl-Friedrich Braun, who had to
* answer a lot of questions about generally ISDN and about handling
* of the Amd-Chip.
*
*/
#include "hisax.h"
#include "isdnl1.h"
#include "isac.h"
#include "amd7930_fn.h"
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/gfp.h>
static void Amd7930_new_ph(struct IsdnCardState *cs);
static WORD initAMD[] = {
0x0100,
0x00A5, 3, 0x01, 0x40, 0x58, // LPR, LMR1, LMR2
0x0086, 1, 0x0B, // DMR1 (D-Buffer TH-Interrupts on)
0x0087, 1, 0xFF, // DMR2
0x0092, 1, 0x03, // EFCR (extended mode d-channel-fifo on)
0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F, // FRAR4, SRAR4, DMR3, DMR4 (address recognition )
0x0084, 2, 0x80, 0x00, // DRLR
0x00C0, 1, 0x47, // PPCR1
0x00C8, 1, 0x01, // PPCR2
0x0102,
0x0107,
0x01A1, 1,
0x0121, 1,
0x0189, 2,
0x0045, 4, 0x61, 0x72, 0x00, 0x00, // MCR1, MCR2, MCR3, MCR4
0x0063, 2, 0x08, 0x08, // GX
0x0064, 2, 0x08, 0x08, // GR
0x0065, 2, 0x99, 0x00, // GER
0x0066, 2, 0x7C, 0x8B, // STG
0x0067, 2, 0x00, 0x00, // FTGR1, FTGR2
0x0068, 2, 0x20, 0x20, // ATGR1, ATGR2
0x0069, 1, 0x4F, // MMR1
0x006A, 1, 0x00, // MMR2
0x006C, 1, 0x40, // MMR3
0x0021, 1, 0x02, // INIT
0x00A3, 1, 0x40, // LMR1
0xFFFF
};
static void /* macro wWordAMD */
WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
{
wByteAMD(cs, 0x00, reg);
wByteAMD(cs, 0x01, LOBYTE(val));
wByteAMD(cs, 0x01, HIBYTE(val));
}
static WORD /* macro rWordAMD */
ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
{
WORD res;
/* direct access register */
if (reg < 8) {
res = rByteAMD(cs, reg);
res += 256 * rByteAMD(cs, reg);
}
/* indirect access register */
else {
wByteAMD(cs, 0x00, reg);
res = rByteAMD(cs, 0x01);
res += 256 * rByteAMD(cs, 0x01);
}
return (res);
}
static void
Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command);
cs->dc.amd7930.lmr1 = command;
wByteAMD(cs, 0xA3, command);
}
static BYTE i430States[] = {
// to reset F3 F4 F5 F6 F7 F8 AR from
0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // init
0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // reset
0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04, // F3
0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F4
0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F5
0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00, // F6
0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00, // F7
0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // F8
0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A}; // AR
/* Row init - reset F3 F4 F5 F6 F7 F8 AR */
static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
static void
Amd7930_get_state(struct IsdnCardState *cs) {
BYTE lsr = rByteAMD(cs, 0xA1);
cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
Amd7930_new_ph(cs);
}
static void
Amd7930_new_ph(struct IsdnCardState *cs)
{
u_char index = stateHelper[cs->dc.amd7930.old_state] * 8 + stateHelper[cs->dc.amd7930.ph_state] - 1;
u_char message = i430States[index];
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d",
cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index);
cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state;
/* abort transmit if nessesary */
if ((message & 0xf0) && (cs->tx_skb)) {
wByteAMD(cs, 0x21, 0xC2);
wByteAMD(cs, 0x21, 0x02);
}
switch (message & 0x0f) {
case (1):
l1_msg(cs, HW_RESET | INDICATION, NULL);
Amd7930_get_state(cs);
break;
case (2): /* init, Card starts in F3 */
l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
break;
case (3):
l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
break;
case (4):
l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST");
break;
case (5):
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
break;
case (6):
l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
break;
case (7): /* init, Card starts in F7 */
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
break;
case (8):
l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
/* fall through */
case (9):
Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set");
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
l1_msg(cs, HW_INFO2 | INDICATION, NULL);
l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
break;
case (10):
Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared");
cs->dc.amd7930.old_state = 3;
break;
case (11):
l1_msg(cs, HW_INFO2 | INDICATION, NULL);
break;
default:
break;
}
}
static void
Amd7930_bh(struct work_struct *work)
{
struct IsdnCardState *cs =
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
stptr = cs->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
stptr = stptr->next;
}
}
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "AMD7930: bh, D_L1STATECHANGE");
Amd7930_new_ph(cs);
}
if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "AMD7930: bh, D_RCVBUFREADY");
DChannel_proc_rcv(cs);
}
if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "AMD7930: bh, D_XMTBUFREADY");
DChannel_proc_xmt(cs);
}
}
static void
Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
{
BYTE stat, der;
BYTE *ptr;
struct sk_buff *skb;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "Amd7930: empty_Dfifo");
ptr = cs->rcvbuf + cs->rcvidx;
/* AMD interrupts off */
AmdIrqOff(cs);
/* read D-Channel-Fifo*/
stat = rByteAMD(cs, 0x07); // DSR2
/* while Data in Fifo ... */
while ((stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1)) {
*ptr = rByteAMD(cs, 0x04); // DCRB
ptr++;
stat = rByteAMD(cs, 0x07); // DSR2
cs->rcvidx = ptr - cs->rcvbuf;
/* Paket ready? */
if (stat & 1) {
der = rWordAMD(cs, 0x03);
/* no errors, packet ok */
if (!der && !flag) {
rWordAMD(cs, 0x89); // clear DRCR
if ((cs->rcvidx) > 0) {
if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC)))
printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n");
else {
/* Debugging */
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx);
QuickHex(t, cs->rcvbuf, cs->rcvidx);
debugl1(cs, "%s", cs->dlog);
}
/* moves received data in sk-buffer */
skb_put_data(skb, cs->rcvbuf,
cs->rcvidx);
skb_queue_tail(&cs->rq, skb);
}
}
}
/* throw damaged packets away, reset receive-buffer, indicate RX */
ptr = cs->rcvbuf;
cs->rcvidx = 0;
schedule_event(cs, D_RCVBUFREADY);
}
}
/* Packet to long, overflow */
if (cs->rcvidx >= MAX_DFRAME_LEN_L1) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
cs->rcvidx = 0;
return;
}
/* AMD interrupts on */
AmdIrqOn(cs);
}
static void
Amd7930_fill_Dfifo(struct IsdnCardState *cs)
{
WORD dtcrr, dtcrw, len, count;
BYTE txstat, dmr3;
BYTE *ptr, *deb_ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "Amd7930: fill_Dfifo");
if ((!cs->tx_skb) || (cs->tx_skb->len <= 0))
return;
dtcrw = 0;
if (!cs->dc.amd7930.tx_xmtlen)
/* new Frame */
len = dtcrw = cs->tx_skb->len;
/* continue frame */
else len = cs->dc.amd7930.tx_xmtlen;
/* AMD interrupts off */
AmdIrqOff(cs);
deb_ptr = ptr = cs->tx_skb->data;
/* while free place in tx-fifo available and data in sk-buffer */
txstat = 0x10;
while ((txstat & 0x10) && (cs->tx_cnt < len)) {
wByteAMD(cs, 0x04, *ptr);
ptr++;
cs->tx_cnt++;
txstat = rByteAMD(cs, 0x07);
}
count = ptr - cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
dtcrr = rWordAMD(cs, 0x85); // DTCR
dmr3 = rByteAMD(cs, 0x8E);
if (cs->debug & L1_DEB_ISAC) {
debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw));
}
/* writeing of dtcrw starts transmit */
if (!cs->dc.amd7930.tx_xmtlen) {
wWordAMD(cs, 0x85, dtcrw);
cs->dc.amd7930.tx_xmtlen = dtcrw;
}
if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running");
del_timer(&cs->dbusytimer);
}
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
add_timer(&cs->dbusytimer);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
QuickHex(t, deb_ptr, count);
debugl1(cs, "%s", cs->dlog);
}
/* AMD interrupts on */
AmdIrqOn(cs);
}
void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
{
BYTE dsr1, dsr2, lsr;
WORD der;
while (irflags)
{
dsr1 = rByteAMD(cs, 0x02);
der = rWordAMD(cs, 0x03);
dsr2 = rByteAMD(cs, 0x07);
lsr = rByteAMD(cs, 0xA1);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der);
/* D error -> read DER and DSR2 bit 2 */
if (der || (dsr2 & 4)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der);
/* RX, TX abort if collision detected */
if (der & 2) {
wByteAMD(cs, 0x21, 0xC2);
wByteAMD(cs, 0x21, 0x02);
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
/* restart frame */
if (cs->tx_skb) {
skb_push(cs->tx_skb, cs->tx_cnt);
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
Amd7930_fill_Dfifo(cs);
} else {
printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n");
debugl1(cs, "Amd7930: interrupt: D-Collision, no skb");
}
}
/* remove damaged data from fifo */
Amd7930_empty_Dfifo(cs, 1);
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
/* restart TX-Frame */
if (cs->tx_skb) {
skb_push(cs->tx_skb, cs->tx_cnt);
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
Amd7930_fill_Dfifo(cs);
}
}
/* D TX FIFO empty -> fill */
if (irflags & 1) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data");
/* AMD interrupts off */
AmdIrqOff(cs);
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) {
if (cs->tx_skb->len)
Amd7930_fill_Dfifo(cs);
}
/* AMD interrupts on */
AmdIrqOn(cs);
}
/* D RX FIFO full or tiny packet in Fifo -> empty */
if ((irflags & 2) || (dsr1 & 2)) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: interrupt: empty D-FIFO");
Amd7930_empty_Dfifo(cs, 0);
}
/* D-Frame transmit complete */
if (dsr1 & 64) {
if (cs->debug & L1_DEB_ISAC) {
debugl1(cs, "Amd7930: interrupt: transmit packet ready");
}
/* AMD interrupts off */
AmdIrqOff(cs);
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb");
dev_kfree_skb_irq(cs->tx_skb);
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
cs->tx_skb = NULL;
}
if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued");
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
Amd7930_fill_Dfifo(cs);
}
else
schedule_event(cs, D_XMTBUFREADY);
/* AMD interrupts on */
AmdIrqOn(cs);
}
/* LIU status interrupt -> read LSR, check statechanges */
if (lsr & 0x38) {
/* AMD interrupts off */
AmdIrqOff(cs);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) + 2));
cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
schedule_event(cs, D_L1STATECHANGE);
/* AMD interrupts on */
AmdIrqOn(cs);
}
/* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */
irflags = rByteAMD(cs, 0x00);
}
}
static void
Amd7930_l1hw(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
struct sk_buff *skb = arg;
u_long flags;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
switch (pr) {
case (PH_DATA | REQUEST):
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
skb_queue_tail(&cs->sq, skb);
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);
#endif
} else {
cs->tx_skb = skb;
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);
#endif
Amd7930_fill_Dfifo(cs);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
skb_queue_tail(&cs->sq, skb);
spin_unlock_irqrestore(&cs->lock, flags);
break;
}
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
cs->tx_skb = skb;
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
#endif
Amd7930_fill_Dfifo(cs);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | REQUEST):
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb) ? "yes" : "no");
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (HW_RESET | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
if (cs->dc.amd7930.ph_state == 8) {
/* b-channels off, PH-AR cleared
* change to F3 */
Amd7930_ph_command(cs, 0x20, "HW_RESET REQUEST"); //LMR1 bit 5
spin_unlock_irqrestore(&cs->lock, flags);
} else {
Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
cs->dc.amd7930.ph_state = 2;
spin_unlock_irqrestore(&cs->lock, flags);
Amd7930_new_ph(cs);
}
break;
case (HW_ENABLE | REQUEST):
cs->dc.amd7930.ph_state = 9;
Amd7930_new_ph(cs);
break;
case (HW_INFO3 | REQUEST):
// automatic
break;
case (HW_TESTLOOP | REQUEST):
/* not implemented yet */
break;
case (HW_DEACTIVATE | RESPONSE):
skb_queue_purge(&cs->rq);
skb_queue_purge(&cs->sq);
if (cs->tx_skb) {
dev_kfree_skb(cs->tx_skb);
cs->tx_skb = NULL;
}
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
break;
default:
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
break;
}
}
static void
setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: setstack called");
st->l1.l1hw = Amd7930_l1hw;
}
static void
DC_Close_Amd7930(struct IsdnCardState *cs) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: DC_Close called");
}
static void
dbusy_timer_handler(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
u_long flags;
struct PStack *stptr;
WORD dtcr, der;
BYTE dsr1, dsr2;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: dbusy_timer expired!");
if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
spin_lock_irqsave(&cs->lock, flags);
/* D Transmit Byte Count Register:
* Counts down packet's number of Bytes, 0 if packet ready */
dtcr = rWordAMD(cs, 0x85);
dsr1 = rByteAMD(cs, 0x02);
dsr2 = rByteAMD(cs, 0x07);
der = rWordAMD(cs, 0x03);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) { /* D-Channel Busy */
test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
stptr = cs->stlist;
spin_unlock_irqrestore(&cs->lock, flags);
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
stptr = stptr->next;
}
} else {
/* discard frame; reset transceiver */
test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
cs->dc.amd7930.tx_xmtlen = 0;
} else {
printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n");
debugl1(cs, "Amd7930: D-Channel Busy no skb");
}
/* Transmitter reset, abort transmit */
wByteAMD(cs, 0x21, 0x82);
wByteAMD(cs, 0x21, 0x02);
spin_unlock_irqrestore(&cs->lock, flags);
cs->irq_func(cs->irq, cs);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
}
}
}
void Amd7930_init(struct IsdnCardState *cs)
{
WORD *ptr;
BYTE cmd, cnt;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: initamd called");
cs->dc.amd7930.tx_xmtlen = 0;
cs->dc.amd7930.old_state = 0;
cs->dc.amd7930.lmr1 = 0x40;
cs->dc.amd7930.ph_command = Amd7930_ph_command;
cs->setstack_d = setstack_Amd7930;
cs->DC_Close = DC_Close_Amd7930;
/* AMD Initialisation */
for (ptr = initAMD; *ptr != 0xFFFF; ) {
cmd = LOBYTE(*ptr);
/* read */
if (*ptr++ >= 0x100) {
if (cmd < 8)
/* reset register */
rByteAMD(cs, cmd);
else {
wByteAMD(cs, 0x00, cmd);
for (cnt = *ptr++; cnt > 0; cnt--)
rByteAMD(cs, 0x01);
}
}
/* write */
else if (cmd < 8)
wByteAMD(cs, cmd, LOBYTE(*ptr++));
else {
wByteAMD(cs, 0x00, cmd);
for (cnt = *ptr++; cnt > 0; cnt--)
wByteAMD(cs, 0x01, LOBYTE(*ptr++));
}
}
}
void setup_Amd7930(struct IsdnCardState *cs)
{
INIT_WORK(&cs->tqueue, Amd7930_bh);
timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
}

View file

@ -1,37 +0,0 @@
/* drivers/isdn/hisax/amd7930_fn.h
*
* gerdes_amd7930.h Header-file included by
* gerdes_amd7930.c
*
* Author Christoph Ersfeld <info@formula-n.de>
* Formula-n Europe AG (www.formula-n.com)
* previously Gerdes AG
*
*
* This file is (c) under GNU PUBLIC LICENSE
*/
#define BYTE unsigned char
#define WORD unsigned int
#define rByteAMD(cs, reg) cs->readisac(cs, reg)
#define wByteAMD(cs, reg, val) cs->writeisac(cs, reg, val)
#define rWordAMD(cs, reg) ReadWordAmd7930(cs, reg)
#define wWordAMD(cs, reg, val) WriteWordAmd7930(cs, reg, val)
#define HIBYTE(w) ((unsigned char)((w & 0xff00) / 256))
#define LOBYTE(w) ((unsigned char)(w & 0x00ff))
#define AmdIrqOff(cs) cs->dc.amd7930.setIrqMask(cs, 0)
#define AmdIrqOn(cs) cs->dc.amd7930.setIrqMask(cs, 1)
#define AMD_CR 0x00
#define AMD_DR 0x01
#define DBUSY_TIMER_VALUE 80
extern void Amd7930_interrupt(struct IsdnCardState *, unsigned char);
extern void Amd7930_init(struct IsdnCardState *);
extern void setup_Amd7930(struct IsdnCardState *);

View file

@ -1,131 +0,0 @@
/* $Id: arcofi.c,v 1.14.2.3 2004/01/13 14:31:24 keil Exp $
*
* Ansteuerung ARCOFI 2165
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/sched.h>
#include "hisax.h"
#include "isdnl1.h"
#include "isac.h"
#include "arcofi.h"
#define ARCOFI_TIMER_VALUE 20
static void
add_arcofi_timer(struct IsdnCardState *cs) {
if (test_and_set_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
del_timer(&cs->dc.isac.arcofitimer);
}
cs->dc.isac.arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ) / 1000);
add_timer(&cs->dc.isac.arcofitimer);
}
static void
send_arcofi(struct IsdnCardState *cs) {
add_arcofi_timer(cs);
cs->dc.isac.mon_txp = 0;
cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len;
memcpy(cs->dc.isac.mon_tx, cs->dc.isac.arcofi_list->msg, cs->dc.isac.mon_txc);
switch (cs->dc.isac.arcofi_bc) {
case 0: break;
case 1: cs->dc.isac.mon_tx[1] |= 0x40;
break;
default: break;
}
cs->dc.isac.mocr &= 0x0f;
cs->dc.isac.mocr |= 0xa0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
(void) cs->readisac(cs, ISAC_MOSR);
cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
cs->dc.isac.mocr |= 0x10;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
}
int
arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
if (cs->debug & L1_DEB_MONITOR) {
debugl1(cs, "arcofi state %d event %d", cs->dc.isac.arcofi_state, event);
}
if (event == ARCOFI_TIMEOUT) {
cs->dc.isac.arcofi_state = ARCOFI_NOP;
test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags);
wake_up(&cs->dc.isac.arcofi_wait);
return (1);
}
switch (cs->dc.isac.arcofi_state) {
case ARCOFI_NOP:
if (event == ARCOFI_START) {
cs->dc.isac.arcofi_list = data;
cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
send_arcofi(cs);
}
break;
case ARCOFI_TRANSMIT:
if (event == ARCOFI_TX_END) {
if (cs->dc.isac.arcofi_list->receive) {
add_arcofi_timer(cs);
cs->dc.isac.arcofi_state = ARCOFI_RECEIVE;
} else {
if (cs->dc.isac.arcofi_list->next) {
cs->dc.isac.arcofi_list =
cs->dc.isac.arcofi_list->next;
send_arcofi(cs);
} else {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
del_timer(&cs->dc.isac.arcofitimer);
}
cs->dc.isac.arcofi_state = ARCOFI_NOP;
wake_up(&cs->dc.isac.arcofi_wait);
}
}
}
break;
case ARCOFI_RECEIVE:
if (event == ARCOFI_RX_END) {
if (cs->dc.isac.arcofi_list->next) {
cs->dc.isac.arcofi_list =
cs->dc.isac.arcofi_list->next;
cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
send_arcofi(cs);
} else {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
del_timer(&cs->dc.isac.arcofitimer);
}
cs->dc.isac.arcofi_state = ARCOFI_NOP;
wake_up(&cs->dc.isac.arcofi_wait);
}
}
break;
default:
debugl1(cs, "Arcofi unknown state %x", cs->dc.isac.arcofi_state);
return (2);
}
return (0);
}
static void
arcofi_timer(struct timer_list *t) {
struct IsdnCardState *cs = from_timer(cs, t, dc.isac.arcofitimer);
arcofi_fsm(cs, ARCOFI_TIMEOUT, NULL);
}
void
clear_arcofi(struct IsdnCardState *cs) {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
del_timer(&cs->dc.isac.arcofitimer);
}
}
void
init_arcofi(struct IsdnCardState *cs) {
timer_setup(&cs->dc.isac.arcofitimer, arcofi_timer, 0);
init_waitqueue_head(&cs->dc.isac.arcofi_wait);
test_and_set_bit(HW_ARCOFI, &cs->HW_Flags);
}

View file

@ -1,27 +0,0 @@
/* $Id: arcofi.h,v 1.6.6.2 2001/09/23 22:24:46 kai Exp $
*
* Ansteuerung ARCOFI 2165
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define ARCOFI_USE 1
/* states */
#define ARCOFI_NOP 0
#define ARCOFI_TRANSMIT 1
#define ARCOFI_RECEIVE 2
/* events */
#define ARCOFI_START 1
#define ARCOFI_TX_END 2
#define ARCOFI_RX_END 3
#define ARCOFI_TIMEOUT 4
extern int arcofi_fsm(struct IsdnCardState *cs, int event, void *data);
extern void init_arcofi(struct IsdnCardState *cs);
extern void clear_arcofi(struct IsdnCardState *cs);

View file

@ -1,423 +0,0 @@
/* $Id: asuscom.c,v 1.14.2.4 2004/01/13 23:48:39 keil Exp $
*
* low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for information
*
*/
#include <linux/init.h>
#include <linux/isapnp.h>
#include "hisax.h"
#include "isac.h"
#include "ipac.h"
#include "hscx.h"
#include "isdnl1.h"
static const char *Asuscom_revision = "$Revision: 1.14.2.4 $";
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
#define ASUS_ISAC 0
#define ASUS_HSCX 1
#define ASUS_ADR 2
#define ASUS_CTRL_U7 3
#define ASUS_CTRL_POTS 5
#define ASUS_IPAC_ALE 0
#define ASUS_IPAC_DATA 1
#define ASUS_ISACHSCX 1
#define ASUS_IPAC 2
/* CARD_ADR (Write) */
#define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
byteout(ale, off);
ret = bytein(adr);
return (ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
insb(adr, data, size);
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
byteout(ale, off);
byteout(adr, data);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
outsb(adr, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
}
static u_char
ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset | 0x80));
}
static void
WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset | 0x80, value);
}
static void
ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
}
static void
WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.asus.adr,
cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0)));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.asus.adr,
cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \
cs->hw.asus.hscx, reg + (nr ? 0x40 : 0))
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \
cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \
cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \
cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
asuscom_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
if (val) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
if (val) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF);
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0);
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0);
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static irqreturn_t
asuscom_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val, icnt = 5;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
Start_IPAC:
if (cs->debug & L1_DEB_IPAC)
debugl1(cs, "IPAC ISTA %02X", ista);
if (ista & 0x0f) {
val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
if (ista & 0x01)
val |= 0x01;
if (ista & 0x04)
val |= 0x02;
if (ista & 0x08)
val |= 0x04;
if (val)
hscx_int_main(cs, val);
}
if (ista & 0x20) {
val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80);
if (val) {
isac_interrupt(cs, val);
}
}
if (ista & 0x10) {
val = 0x01;
isac_interrupt(cs, val);
}
ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
if ((ista & 0x3f) && icnt) {
icnt--;
goto Start_IPAC;
}
if (!icnt)
printk(KERN_WARNING "ASUS IRQ LOOP\n");
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_asuscom(struct IsdnCardState *cs)
{
int bytecnt = 8;
if (cs->hw.asus.cfg_reg)
release_region(cs->hw.asus.cfg_reg, bytecnt);
}
static void
reset_asuscom(struct IsdnCardState *cs)
{
if (cs->subtyp == ASUS_IPAC)
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20);
else
byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */
mdelay(10);
if (cs->subtyp == ASUS_IPAC)
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0);
else
byteout(cs->hw.asus.adr, 0); /* Reset Off */
mdelay(10);
if (cs->subtyp == ASUS_IPAC) {
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12);
}
}
static int
Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_asuscom(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_asuscom(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
cs->debug |= L1_DEB_IPAC;
inithscxisac(cs, 3);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
#ifdef __ISAPNP__
static struct isapnp_device_id asus_ids[] = {
{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
(unsigned long) "Asus1688 PnP" },
{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
(unsigned long) "Asus1690 PnP" },
{ ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
(unsigned long) "Isurf2 PnP" },
{ ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
(unsigned long) "Iscas TE320" },
{ 0, }
};
static struct isapnp_device_id *ipid = &asus_ids[0];
static struct pnp_card *pnp_c = NULL;
#endif
int setup_asuscom(struct IsdnCard *card)
{
int bytecnt;
struct IsdnCardState *cs = card->cs;
u_char val;
char tmp[64];
strcpy(tmp, Asuscom_revision);
printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_ASUSCOM)
return (0);
#ifdef __ISAPNP__
if (!card->para[1] && isapnp_present()) {
struct pnp_dev *pnp_d;
while (ipid->card_vendor) {
if ((pnp_c = pnp_find_card(ipid->card_vendor,
ipid->card_device, pnp_c))) {
pnp_d = NULL;
if ((pnp_d = pnp_find_dev(pnp_c,
ipid->vendor, ipid->function, pnp_d))) {
int err;
printk(KERN_INFO "HiSax: %s detected\n",
(char *)ipid->driver_data);
pnp_disable_dev(pnp_d);
err = pnp_activate_dev(pnp_d);
if (err < 0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
__func__, err);
return (0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
card->para[0] = pnp_irq(pnp_d, 0);
if (card->para[0] == -1 || !card->para[1]) {
printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n",
card->para[0], card->para[1]);
pnp_disable_dev(pnp_d);
return (0);
}
break;
} else {
printk(KERN_ERR "AsusPnP: PnP error card found, no device\n");
}
}
ipid++;
pnp_c = NULL;
}
if (!ipid->card_vendor) {
printk(KERN_INFO "AsusPnP: no ISAPnP card found\n");
return (0);
}
}
#endif
bytecnt = 8;
cs->hw.asus.cfg_reg = card->para[1];
cs->irq = card->para[0];
if (!request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn")) {
printk(KERN_WARNING
"HiSax: ISDNLink config port %x-%x already in use\n",
cs->hw.asus.cfg_reg,
cs->hw.asus.cfg_reg + bytecnt);
return (0);
}
printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n",
cs->hw.asus.cfg_reg, cs->irq);
setup_isac(cs);
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Asus_card_msg;
val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE,
cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID);
if ((val == 1) || (val == 2)) {
cs->subtyp = ASUS_IPAC;
cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE;
cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
cs->readisac = &ReadISAC_IPAC;
cs->writeisac = &WriteISAC_IPAC;
cs->readisacfifo = &ReadISACfifo_IPAC;
cs->writeisacfifo = &WriteISACfifo_IPAC;
cs->irq_func = &asuscom_interrupt_ipac;
printk(KERN_INFO "Asus: IPAC version %x\n", val);
} else {
cs->subtyp = ASUS_ISACHSCX;
cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR;
cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC;
cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX;
cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7;
cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS;
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->irq_func = &asuscom_interrupt;
ISACVersion(cs, "ISDNLink:");
if (HscxVersion(cs, "ISDNLink:")) {
printk(KERN_WARNING
"ISDNLink: wrong HSCX versions check IO address\n");
release_io_asuscom(cs);
return (0);
}
}
return (1);
}

View file

@ -1,307 +0,0 @@
/* $Id: avm_a1.c,v 2.15.2.4 2004/01/13 21:46:03 keil Exp $
*
* low level stuff for AVM A1 (Fritz) isdn cards
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
static const char *avm_revision = "$Revision: 2.15.2.4 $";
#define AVM_A1_STAT_ISAC 0x01
#define AVM_A1_STAT_HSCX 0x02
#define AVM_A1_STAT_TIMER 0x04
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
static inline u_char
readreg(unsigned int adr, u_char off)
{
return (bytein(adr + off));
}
static inline void
writereg(unsigned int adr, u_char off, u_char data)
{
byteout(adr + off, data);
}
static inline void
read_fifo(unsigned int adr, u_char *data, int size)
{
insb(adr, data, size);
}
static void
write_fifo(unsigned int adr, u_char *data, int size)
{
outsb(adr, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.avm.isac, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.avm.isac, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
read_fifo(cs->hw.avm.isacfifo, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
write_fifo(cs->hw.avm.isacfifo, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.avm.hscx[hscx], offset));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.avm.hscx[hscx], offset, value);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg)
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data)
#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
avm_a1_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, sval;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) {
if (!(sval & AVM_A1_STAT_TIMER)) {
byteout(cs->hw.avm.cfg_reg, 0x1E);
sval = bytein(cs->hw.avm.cfg_reg);
} else if (cs->debug & L1_DEB_INTSTAT)
debugl1(cs, "avm IntStatus %x", sval);
if (!(sval & AVM_A1_STAT_HSCX)) {
val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA);
if (val)
hscx_int_main(cs, val);
}
if (!(sval & AVM_A1_STAT_ISAC)) {
val = readreg(cs->hw.avm.isac, ISAC_ISTA);
if (val)
isac_interrupt(cs, val);
}
}
writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF);
writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF);
writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.avm.isac, ISAC_MASK, 0x0);
writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0);
writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static inline void
release_ioregs(struct IsdnCardState *cs, int mask)
{
release_region(cs->hw.avm.cfg_reg, 8);
if (mask & 1)
release_region(cs->hw.avm.isac + 32, 32);
if (mask & 2)
release_region(cs->hw.avm.isacfifo, 1);
if (mask & 4)
release_region(cs->hw.avm.hscx[0] + 32, 32);
if (mask & 8)
release_region(cs->hw.avm.hscxfifo[0], 1);
if (mask & 0x10)
release_region(cs->hw.avm.hscx[1] + 32, 32);
if (mask & 0x20)
release_region(cs->hw.avm.hscxfifo[1], 1);
}
static int
AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
return (0);
case CARD_RELEASE:
release_ioregs(cs, 0x3f);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
inithscxisac(cs, 1);
byteout(cs->hw.avm.cfg_reg, 0x16);
byteout(cs->hw.avm.cfg_reg, 0x1E);
inithscxisac(cs, 2);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
int setup_avm_a1(struct IsdnCard *card)
{
u_char val;
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, avm_revision);
printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_A1)
return (0);
cs->hw.avm.cfg_reg = card->para[1] + 0x1800;
cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20;
cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20;
cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20;
cs->hw.avm.isacfifo = card->para[1] + 0x1000;
cs->hw.avm.hscxfifo[0] = card->para[1];
cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800;
cs->irq = card->para[0];
if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) {
printk(KERN_WARNING
"HiSax: AVM A1 config port %x-%x already in use\n",
cs->hw.avm.cfg_reg,
cs->hw.avm.cfg_reg + 8);
return (0);
}
if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) {
printk(KERN_WARNING
"HiSax: AVM A1 isac ports %x-%x already in use\n",
cs->hw.avm.isac + 32,
cs->hw.avm.isac + 64);
release_ioregs(cs, 0);
return (0);
}
if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) {
printk(KERN_WARNING
"HiSax: AVM A1 isac fifo port %x already in use\n",
cs->hw.avm.isacfifo);
release_ioregs(cs, 1);
return (0);
}
if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) {
printk(KERN_WARNING
"HiSax: AVM A1 hscx A ports %x-%x already in use\n",
cs->hw.avm.hscx[0] + 32,
cs->hw.avm.hscx[0] + 64);
release_ioregs(cs, 3);
return (0);
}
if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) {
printk(KERN_WARNING
"HiSax: AVM A1 hscx A fifo port %x already in use\n",
cs->hw.avm.hscxfifo[0]);
release_ioregs(cs, 7);
return (0);
}
if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) {
printk(KERN_WARNING
"HiSax: AVM A1 hscx B ports %x-%x already in use\n",
cs->hw.avm.hscx[1] + 32,
cs->hw.avm.hscx[1] + 64);
release_ioregs(cs, 0xf);
return (0);
}
if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) {
printk(KERN_WARNING
"HiSax: AVM A1 hscx B fifo port %x already in use\n",
cs->hw.avm.hscxfifo[1]);
release_ioregs(cs, 0x1f);
return (0);
}
byteout(cs->hw.avm.cfg_reg, 0x0);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg, 0x1);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg, 0x0);
HZDELAY(HZ / 5 + 1);
val = cs->irq;
if (val == 9)
val = 2;
byteout(cs->hw.avm.cfg_reg + 1, val);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg, 0x0);
HZDELAY(HZ / 5 + 1);
val = bytein(cs->hw.avm.cfg_reg);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
cs->hw.avm.cfg_reg, val);
val = bytein(cs->hw.avm.cfg_reg + 3);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
cs->hw.avm.cfg_reg + 3, val);
val = bytein(cs->hw.avm.cfg_reg + 2);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
cs->hw.avm.cfg_reg + 2, val);
val = bytein(cs->hw.avm.cfg_reg);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
cs->hw.avm.cfg_reg, val);
printk(KERN_INFO "HiSax: AVM A1 config irq:%d cfg:0x%X\n",
cs->irq,
cs->hw.avm.cfg_reg);
printk(KERN_INFO
"HiSax: isac:0x%X/0x%X\n",
cs->hw.avm.isac + 32, cs->hw.avm.isacfifo);
printk(KERN_INFO
"HiSax: hscx A:0x%X/0x%X hscx B:0x%X/0x%X\n",
cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0],
cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
setup_isac(cs);
cs->cardmsg = &AVM_card_msg;
cs->irq_func = &avm_a1_interrupt;
ISACVersion(cs, "AVM A1:");
if (HscxVersion(cs, "AVM A1:")) {
printk(KERN_WARNING
"AVM A1: wrong HSCX versions check IO address\n");
release_ioregs(cs, 0x3f);
return (0);
}
return (1);
}

View file

@ -1,267 +0,0 @@
/* $Id: avm_a1p.c,v 2.9.2.5 2004/01/24 20:47:19 keil Exp $
*
* low level stuff for the following AVM cards:
* A1 PCMCIA
* FRITZ!Card PCMCIA
* FRITZ!Card PCMCIA 2.0
*
* Author Carsten Paeth
* Copyright 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/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
/* register offsets */
#define ADDRREG_OFFSET 0x02
#define DATAREG_OFFSET 0x03
#define ASL0_OFFSET 0x04
#define ASL1_OFFSET 0x05
#define MODREG_OFFSET 0x06
#define VERREG_OFFSET 0x07
/* address offsets */
#define ISAC_FIFO_OFFSET 0x00
#define ISAC_REG_OFFSET 0x20
#define HSCX_CH_DIFF 0x40
#define HSCX_FIFO_OFFSET 0x80
#define HSCX_REG_OFFSET 0xa0
/* read bits ASL0 */
#define ASL0_R_TIMER 0x10 /* active low */
#define ASL0_R_ISAC 0x20 /* active low */
#define ASL0_R_HSCX 0x40 /* active low */
#define ASL0_R_TESTBIT 0x80
#define ASL0_R_IRQPENDING (ASL0_R_ISAC | ASL0_R_HSCX | ASL0_R_TIMER)
/* write bits ASL0 */
#define ASL0_W_RESET 0x01
#define ASL0_W_TDISABLE 0x02
#define ASL0_W_TRESET 0x04
#define ASL0_W_IRQENABLE 0x08
#define ASL0_W_TESTBIT 0x80
/* write bits ASL1 */
#define ASL1_W_LED0 0x10
#define ASL1_W_LED1 0x20
#define ASL1_W_ENABLE_S0 0xC0
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
static const char *avm_revision = "$Revision: 2.9.2.5 $";
static inline u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
u_char ret;
offset -= 0x20;
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_REG_OFFSET + offset);
ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET);
return ret;
}
static inline void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
offset -= 0x20;
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_REG_OFFSET + offset);
byteout(cs->hw.avm.cfg_reg + DATAREG_OFFSET, value);
}
static inline void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_FIFO_OFFSET);
insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
}
static inline void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_FIFO_OFFSET);
outsb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
}
static inline u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
u_char ret;
offset -= 0x20;
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
HSCX_REG_OFFSET + hscx * HSCX_CH_DIFF + offset);
ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET);
return ret;
}
static inline void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
offset -= 0x20;
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
HSCX_REG_OFFSET + hscx * HSCX_CH_DIFF + offset);
byteout(cs->hw.avm.cfg_reg + DATAREG_OFFSET, value);
}
static inline void
ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
{
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
HSCX_FIFO_OFFSET + hscx * HSCX_CH_DIFF);
insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
}
static inline void
WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
{
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
HSCX_FIFO_OFFSET + hscx * HSCX_CH_DIFF);
outsb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
avm_a1p_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, sval;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
while ((sval = (~bytein(cs->hw.avm.cfg_reg + ASL0_OFFSET) & ASL0_R_IRQPENDING))) {
if (cs->debug & L1_DEB_INTSTAT)
debugl1(cs, "avm IntStatus %x", sval);
if (sval & ASL0_R_HSCX) {
val = ReadHSCX(cs, 1, HSCX_ISTA);
if (val)
hscx_int_main(cs, val);
}
if (sval & ASL0_R_ISAC) {
val = ReadISAC(cs, ISAC_ISTA);
if (val)
isac_interrupt(cs, val);
}
}
WriteHSCX(cs, 0, HSCX_MASK, 0xff);
WriteHSCX(cs, 1, HSCX_MASK, 0xff);
WriteISAC(cs, ISAC_MASK, 0xff);
WriteISAC(cs, ISAC_MASK, 0x00);
WriteHSCX(cs, 0, HSCX_MASK, 0x00);
WriteHSCX(cs, 1, HSCX_MASK, 0x00);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static int
AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_RESET);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
spin_unlock_irqrestore(&cs->lock, flags);
return 0;
case CARD_RELEASE:
/* free_irq is done in HiSax_closecard(). */
/* free_irq(cs->irq, cs); */
return 0;
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_TDISABLE | ASL0_W_TRESET | ASL0_W_IRQENABLE);
clear_pending_isac_ints(cs);
clear_pending_hscx_ints(cs);
inithscxisac(cs, 1);
inithscxisac(cs, 2);
spin_unlock_irqrestore(&cs->lock, flags);
return 0;
case CARD_TEST:
/* we really don't need it for the PCMCIA Version */
return 0;
default:
/* all card drivers ignore others, so we do the same */
return 0;
}
return 0;
}
int setup_avm_a1_pcmcia(struct IsdnCard *card)
{
u_char model, vers;
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, avm_revision);
printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n",
HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_A1_PCMCIA)
return (0);
cs->hw.avm.cfg_reg = card->para[1];
cs->irq = card->para[0];
byteout(cs->hw.avm.cfg_reg + ASL1_OFFSET, ASL1_W_ENABLE_S0);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_RESET);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_TDISABLE | ASL0_W_TRESET);
model = bytein(cs->hw.avm.cfg_reg + MODREG_OFFSET);
vers = bytein(cs->hw.avm.cfg_reg + VERREG_OFFSET);
printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n",
cs->hw.avm.cfg_reg, cs->irq, model, vers);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &AVM_card_msg;
cs->irq_flags = IRQF_SHARED;
cs->irq_func = &avm_a1p_interrupt;
ISACVersion(cs, "AVM A1 PCMCIA:");
if (HscxVersion(cs, "AVM A1 PCMCIA:")) {
printk(KERN_WARNING
"AVM A1 PCMCIA: wrong HSCX versions check IO address\n");
return (0);
}
return (1);
}

View file

@ -1,904 +0,0 @@
/* $Id: avm_pci.c,v 1.29.2.4 2004/02/11 13:21:32 keil Exp $
*
* low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to AVM, Berlin for information
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "isdnl1.h"
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/isapnp.h>
#include <linux/interrupt.h>
static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
#define AVM_FRITZ_PCI 1
#define AVM_FRITZ_PNP 2
#define HDLC_FIFO 0x0
#define HDLC_STATUS 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_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 0x3f00
#define HDLC_CMD_XRS 0x80
#define HDLC_CMD_XME 0x01
#define HDLC_CMD_RRS 0x20
#define HDLC_CMD_XML_MASK 0x3f00
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
register u_char val;
outb(idx, cs->hw.avm.cfg_reg + 4);
val = inb(cs->hw.avm.isac + (offset & 0xf));
return (val);
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
outb(idx, cs->hw.avm.cfg_reg + 4);
outb(value, cs->hw.avm.isac + (offset & 0xf));
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
insb(cs->hw.avm.isac, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
outsb(cs->hw.avm.isac, data, size);
}
static inline u_int
ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset)
{
register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
register u_int val;
outl(idx, cs->hw.avm.cfg_reg + 4);
val = inl(cs->hw.avm.isac + offset);
return (val);
}
static inline void
WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value)
{
register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
outl(idx, cs->hw.avm.cfg_reg + 4);
outl(value, cs->hw.avm.isac + offset);
}
static inline u_char
ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset)
{
register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
register u_char val;
outb(idx, cs->hw.avm.cfg_reg + 4);
val = inb(cs->hw.avm.isac + offset);
return (val);
}
static inline void
WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
{
register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
outb(idx, cs->hw.avm.cfg_reg + 4);
outb(value, cs->hw.avm.isac + offset);
}
static u_char
ReadHDLC_s(struct IsdnCardState *cs, int chan, u_char offset)
{
return (0xff & ReadHDLCPCI(cs, chan, offset));
}
static void
WriteHDLC_s(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
{
WriteHDLCPCI(cs, chan, offset, value);
}
static inline
struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel)
{
if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
return (&cs->bcs[0]);
else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
return (&cs->bcs[1]);
else
return (NULL);
}
static void
write_ctrl(struct BCState *bcs, int which) {
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "hdlc %c wr%x ctrl %x",
'A' + bcs->channel, which, bcs->hw.hdlc.ctrl.ctrl);
if (bcs->cs->subtyp == AVM_FRITZ_PCI) {
WriteHDLCPCI(bcs->cs, bcs->channel, HDLC_STATUS, bcs->hw.hdlc.ctrl.ctrl);
} else {
if (which & 4)
WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 2,
bcs->hw.hdlc.ctrl.sr.mode);
if (which & 2)
WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 1,
bcs->hw.hdlc.ctrl.sr.xml);
if (which & 1)
WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS,
bcs->hw.hdlc.ctrl.sr.cmd);
}
}
static void
modehdlc(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
int hdlc = bcs->channel;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hdlc %c mode %d --> %d ichan %d --> %d",
'A' + hdlc, bcs->mode, mode, hdlc, bc);
bcs->hw.hdlc.ctrl.ctrl = 0;
switch (mode) {
case (-1): /* used for init */
bcs->mode = 1;
bcs->channel = bc;
bc = 0;
/* fall through */
case (L1_MODE_NULL):
if (bcs->mode == L1_MODE_NULL)
return;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
write_ctrl(bcs, 5);
bcs->mode = L1_MODE_NULL;
bcs->channel = bc;
break;
case (L1_MODE_TRANS):
bcs->mode = mode;
bcs->channel = bc;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
write_ctrl(bcs, 5);
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
write_ctrl(bcs, 1);
bcs->hw.hdlc.ctrl.sr.cmd = 0;
schedule_event(bcs, B_XMTBUFREADY);
break;
case (L1_MODE_HDLC):
bcs->mode = mode;
bcs->channel = bc;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG;
write_ctrl(bcs, 5);
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
write_ctrl(bcs, 1);
bcs->hw.hdlc.ctrl.sr.cmd = 0;
schedule_event(bcs, B_XMTBUFREADY);
break;
}
}
static inline void
hdlc_empty_fifo(struct BCState *bcs, int count)
{
register u_int *ptr;
u_char *p;
u_char idx = bcs->channel ? AVM_HDLC_2 : AVM_HDLC_1;
int cnt = 0;
struct IsdnCardState *cs = bcs->cs;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hdlc_empty_fifo %d", count);
if (bcs->hw.hdlc.rcvidx + count > HSCX_BUFMAX) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "hdlc_empty_fifo: incoming packet too large");
return;
}
p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx;
ptr = (u_int *)p;
bcs->hw.hdlc.rcvidx += count;
if (cs->subtyp == AVM_FRITZ_PCI) {
outl(idx, cs->hw.avm.cfg_reg + 4);
while (cnt < count) {
#ifdef __powerpc__
*ptr++ = in_be32((unsigned *)(cs->hw.avm.isac + _IO_BASE));
#else
*ptr++ = inl(cs->hw.avm.isac);
#endif /* __powerpc__ */
cnt += 4;
}
} else {
outb(idx, cs->hw.avm.cfg_reg + 4);
while (cnt < count) {
*p++ = inb(cs->hw.avm.isac);
cnt++;
}
}
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
if (cs->subtyp == AVM_FRITZ_PNP)
p = (u_char *) ptr;
t += sprintf(t, "hdlc_empty_fifo %c cnt %d",
bcs->channel ? 'B' : 'A', count);
QuickHex(t, p, count);
debugl1(cs, "%s", bcs->blog);
}
}
static inline void
hdlc_fill_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int count, cnt = 0;
int fifo_size = 32;
u_char *p;
u_int *ptr;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hdlc_fill_fifo");
if (!bcs->tx_skb)
return;
if (bcs->tx_skb->len <= 0)
return;
bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME;
if (bcs->tx_skb->len > fifo_size) {
count = fifo_size;
} else {
count = bcs->tx_skb->len;
if (bcs->mode != L1_MODE_TRANS)
bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME;
}
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hdlc_fill_fifo %d/%u", count, bcs->tx_skb->len);
p = bcs->tx_skb->data;
ptr = (u_int *)p;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.hdlc.count += count;
bcs->hw.hdlc.ctrl.sr.xml = ((count == fifo_size) ? 0 : count);
write_ctrl(bcs, 3); /* sets the correct index too */
if (cs->subtyp == AVM_FRITZ_PCI) {
while (cnt < count) {
#ifdef __powerpc__
out_be32((unsigned *)(cs->hw.avm.isac + _IO_BASE), *ptr++);
#else
outl(*ptr++, cs->hw.avm.isac);
#endif /* __powerpc__ */
cnt += 4;
}
} else {
while (cnt < count) {
outb(*p++, cs->hw.avm.isac);
cnt++;
}
}
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
if (cs->subtyp == AVM_FRITZ_PNP)
p = (u_char *) ptr;
t += sprintf(t, "hdlc_fill_fifo %c cnt %d",
bcs->channel ? 'B' : 'A', count);
QuickHex(t, p, count);
debugl1(cs, "%s", bcs->blog);
}
}
static void
HDLC_irq(struct BCState *bcs, u_int stat) {
int len;
struct sk_buff *skb;
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat);
if (stat & HDLC_INT_RPR) {
if (stat & HDLC_STAT_RDO) {
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "RDO");
else
debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat);
bcs->hw.hdlc.ctrl.sr.xml = 0;
bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_RRS;
write_ctrl(bcs, 1);
bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS;
write_ctrl(bcs, 1);
bcs->hw.hdlc.rcvidx = 0;
} else {
if (!(len = (stat & HDLC_STAT_RML_MASK) >> 8))
len = 32;
hdlc_empty_fifo(bcs, len);
if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) {
if (((stat & HDLC_STAT_CRCVFRRAB) == HDLC_STAT_CRCVFR) ||
(bcs->mode == L1_MODE_TRANS)) {
if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx)))
printk(KERN_WARNING "HDLC: receive out of memory\n");
else {
skb_put_data(skb,
bcs->hw.hdlc.rcvbuf,
bcs->hw.hdlc.rcvidx);
skb_queue_tail(&bcs->rqueue, skb);
}
bcs->hw.hdlc.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
} else {
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "invalid frame");
else
debugl1(bcs->cs, "ch%d invalid frame %#x", bcs->channel, stat);
bcs->hw.hdlc.rcvidx = 0;
}
}
}
}
if (stat & HDLC_INT_XDU) {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->hw.hdlc.count);
bcs->tx_cnt += bcs->hw.hdlc.count;
bcs->hw.hdlc.count = 0;
if (bcs->cs->debug & L1_DEB_WARN)
debugl1(bcs->cs, "ch%d XDU", bcs->channel);
} else if (bcs->cs->debug & L1_DEB_WARN)
debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel);
bcs->hw.hdlc.ctrl.sr.xml = 0;
bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS;
write_ctrl(bcs, 1);
bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS;
write_ctrl(bcs, 1);
hdlc_fill_fifo(bcs);
} else if (stat & HDLC_INT_XPR) {
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
hdlc_fill_fifo(bcs);
return;
} else {
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += bcs->hw.hdlc.count;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hdlc.count = 0;
bcs->tx_skb = NULL;
}
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
bcs->hw.hdlc.count = 0;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
hdlc_fill_fifo(bcs);
} else {
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
schedule_event(bcs, B_XMTBUFREADY);
}
}
}
static inline void
HDLC_irq_main(struct IsdnCardState *cs)
{
u_int stat;
struct BCState *bcs;
if (cs->subtyp == AVM_FRITZ_PCI) {
stat = ReadHDLCPCI(cs, 0, HDLC_STATUS);
} else {
stat = ReadHDLCPnP(cs, 0, HDLC_STATUS);
if (stat & HDLC_INT_RPR)
stat |= (ReadHDLCPnP(cs, 0, HDLC_STATUS + 1)) << 8;
}
if (stat & HDLC_INT_MASK) {
if (!(bcs = Sel_BCS(cs, 0))) {
if (cs->debug)
debugl1(cs, "hdlc spurious channel 0 IRQ");
} else
HDLC_irq(bcs, stat);
}
if (cs->subtyp == AVM_FRITZ_PCI) {
stat = ReadHDLCPCI(cs, 1, HDLC_STATUS);
} else {
stat = ReadHDLCPnP(cs, 1, HDLC_STATUS);
if (stat & HDLC_INT_RPR)
stat |= (ReadHDLCPnP(cs, 1, HDLC_STATUS + 1)) << 8;
}
if (stat & HDLC_INT_MASK) {
if (!(bcs = Sel_BCS(cs, 1))) {
if (cs->debug)
debugl1(cs, "hdlc spurious channel 1 IRQ");
} else
HDLC_irq(bcs, stat);
}
}
static void
hdlc_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
struct sk_buff *skb = arg;
u_long flags;
switch (pr) {
case (PH_DATA | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->hw.hdlc.count = 0;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
printk(KERN_WARNING "hdlc_l2l1: this shouldn't happen\n");
} else {
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->tx_skb = skb;
bcs->hw.hdlc.count = 0;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | REQUEST):
if (!bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (PH_ACTIVATE | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
modehdlc(bcs, st->l1.mode, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
modehdlc(bcs, 0, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
static void
close_hdlcstate(struct BCState *bcs)
{
modehdlc(bcs, 0, 0);
if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
kfree(bcs->hw.hdlc.rcvbuf);
bcs->hw.hdlc.rcvbuf = NULL;
kfree(bcs->blog);
bcs->blog = NULL;
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
}
static int
open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
if (!(bcs->hw.hdlc.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for hdlc.rcvbuf\n");
return (1);
}
if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for bcs->blog\n");
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
kfree(bcs->hw.hdlc.rcvbuf);
bcs->hw.hdlc.rcvbuf = NULL;
return (2);
}
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->hw.hdlc.rcvidx = 0;
bcs->tx_cnt = 0;
return (0);
}
static int
setstack_hdlc(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
if (open_hdlcstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
st->l2.l2l1 = hdlc_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
#if 0
void __init
clear_pending_hdlc_ints(struct IsdnCardState *cs)
{
u_int val;
if (cs->subtyp == AVM_FRITZ_PCI) {
val = ReadHDLCPCI(cs, 0, HDLC_STATUS);
debugl1(cs, "HDLC 1 STA %x", val);
val = ReadHDLCPCI(cs, 1, HDLC_STATUS);
debugl1(cs, "HDLC 2 STA %x", val);
} else {
val = ReadHDLCPnP(cs, 0, HDLC_STATUS);
debugl1(cs, "HDLC 1 STA %x", val);
val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 1);
debugl1(cs, "HDLC 1 RML %x", val);
val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 2);
debugl1(cs, "HDLC 1 MODE %x", val);
val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 3);
debugl1(cs, "HDLC 1 VIN %x", val);
val = ReadHDLCPnP(cs, 1, HDLC_STATUS);
debugl1(cs, "HDLC 2 STA %x", val);
val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 1);
debugl1(cs, "HDLC 2 RML %x", val);
val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 2);
debugl1(cs, "HDLC 2 MODE %x", val);
val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 3);
debugl1(cs, "HDLC 2 VIN %x", val);
}
}
#endif /* 0 */
static void
inithdlc(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_hdlc;
cs->bcs[1].BC_SetStack = setstack_hdlc;
cs->bcs[0].BC_Close = close_hdlcstate;
cs->bcs[1].BC_Close = close_hdlcstate;
modehdlc(cs->bcs, -1, 0);
modehdlc(cs->bcs + 1, -1, 1);
}
static irqreturn_t
avm_pcipnp_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_long flags;
u_char val;
u_char sval;
spin_lock_irqsave(&cs->lock, flags);
sval = inb(cs->hw.avm.cfg_reg + 2);
if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
/* possible a shared IRQ reqest */
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
val = ReadISAC(cs, ISAC_ISTA);
isac_interrupt(cs, val);
}
if (!(sval & AVM_STATUS0_IRQ_HDLC)) {
HDLC_irq_main(cs);
}
WriteISAC(cs, ISAC_MASK, 0xFF);
WriteISAC(cs, ISAC_MASK, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
reset_avmpcipnp(struct IsdnCardState *cs)
{
printk(KERN_INFO "AVM PCI/PnP: reset\n");
outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2);
mdelay(10);
outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3);
mdelay(10);
printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3));
}
static int
AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_avmpcipnp(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
outb(0, cs->hw.avm.cfg_reg + 2);
release_region(cs->hw.avm.cfg_reg, 32);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
reset_avmpcipnp(cs);
clear_pending_isac_ints(cs);
initisac(cs);
inithdlc(cs);
outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER,
cs->hw.avm.cfg_reg + 2);
WriteISAC(cs, ISAC_MASK, 0);
outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |
AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
/* RESET Receiver and Transmitter */
WriteISAC(cs, ISAC_CMDR, 0x41);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int avm_setup_rest(struct IsdnCardState *cs)
{
u_int val, ver;
cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
if (!request_region(cs->hw.avm.cfg_reg, 32,
(cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
printk(KERN_WARNING
"HiSax: Fritz!PCI/PNP config port %x-%x already in use\n",
cs->hw.avm.cfg_reg,
cs->hw.avm.cfg_reg + 31);
return (0);
}
switch (cs->subtyp) {
case AVM_FRITZ_PCI:
val = inl(cs->hw.avm.cfg_reg);
printk(KERN_INFO "AVM PCI: stat %#x\n", val);
printk(KERN_INFO "AVM PCI: Class %X Rev %d\n",
val & 0xff, (val >> 8) & 0xff);
cs->BC_Read_Reg = &ReadHDLC_s;
cs->BC_Write_Reg = &WriteHDLC_s;
break;
case AVM_FRITZ_PNP:
val = inb(cs->hw.avm.cfg_reg);
ver = inb(cs->hw.avm.cfg_reg + 1);
printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver);
cs->BC_Read_Reg = &ReadHDLCPnP;
cs->BC_Write_Reg = &WriteHDLCPnP;
break;
default:
printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp);
return (0);
}
printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n",
(cs->subtyp == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" : "AVM Fritz!PnP",
cs->irq, cs->hw.avm.cfg_reg);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Send_Data = &hdlc_fill_fifo;
cs->cardmsg = &AVM_card_msg;
cs->irq_func = &avm_pcipnp_interrupt;
cs->writeisac(cs, ISAC_MASK, 0xFF);
ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
return (1);
}
#ifndef __ISAPNP__
static int avm_pnp_setup(struct IsdnCardState *cs)
{
return (1); /* no-op: success */
}
#else
static struct pnp_card *pnp_avm_c = NULL;
static int avm_pnp_setup(struct IsdnCardState *cs)
{
struct pnp_dev *pnp_avm_d = NULL;
if (!isapnp_present())
return (1); /* no-op: success */
if ((pnp_avm_c = pnp_find_card(
ISAPNP_VENDOR('A', 'V', 'M'),
ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
ISAPNP_VENDOR('A', 'V', 'M'),
ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
int err;
pnp_disable_dev(pnp_avm_d);
err = pnp_activate_dev(pnp_avm_d);
if (err < 0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
__func__, err);
return (0);
}
cs->hw.avm.cfg_reg =
pnp_port_start(pnp_avm_d, 0);
cs->irq = pnp_irq(pnp_avm_d, 0);
if (cs->irq == -1) {
printk(KERN_ERR "FritzPnP:No IRQ\n");
return (0);
}
if (!cs->hw.avm.cfg_reg) {
printk(KERN_ERR "FritzPnP:No IO address\n");
return (0);
}
cs->subtyp = AVM_FRITZ_PNP;
return (2); /* goto 'ready' label */
}
}
return (1);
}
#endif /* __ISAPNP__ */
#ifndef CONFIG_PCI
static int avm_pci_setup(struct IsdnCardState *cs)
{
return (1); /* no-op: success */
}
#else
static struct pci_dev *dev_avm = NULL;
static int avm_pci_setup(struct IsdnCardState *cs)
{
if ((dev_avm = hisax_find_pci_device(PCI_VENDOR_ID_AVM,
PCI_DEVICE_ID_AVM_A1, dev_avm))) {
if (pci_enable_device(dev_avm))
return (0);
cs->irq = dev_avm->irq;
if (!cs->irq) {
printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
return (0);
}
cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
if (!cs->hw.avm.cfg_reg) {
printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
return (0);
}
cs->subtyp = AVM_FRITZ_PCI;
} else {
printk(KERN_WARNING "FritzPCI: No PCI card found\n");
return (0);
}
cs->irq_flags |= IRQF_SHARED;
return (1);
}
#endif /* CONFIG_PCI */
int setup_avm_pcipnp(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
int rc;
strcpy(tmp, avm_pci_rev);
printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_FRITZPCI)
return (0);
if (card->para[1]) {
/* old manual method */
cs->hw.avm.cfg_reg = card->para[1];
cs->irq = card->para[0];
cs->subtyp = AVM_FRITZ_PNP;
goto ready;
}
rc = avm_pnp_setup(cs);
if (rc < 1)
return (0);
if (rc == 2)
goto ready;
rc = avm_pci_setup(cs);
if (rc < 1)
return (0);
ready:
return avm_setup_rest(cs);
}

View file

@ -1,162 +0,0 @@
/*
* PCMCIA client driver for AVM A1 / Fritz!PCMCIA
*
* Author Carsten Paeth
* Copyright 1998-2001 by Carsten Paeth <calle@calle.in-berlin.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <asm/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include "hisax_cfg.h"
MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
static int isdnprot = 2;
module_param(isdnprot, int, 0);
/*====================================================================*/
static int avma1cs_config(struct pcmcia_device *link);
static void avma1cs_release(struct pcmcia_device *link);
static void avma1cs_detach(struct pcmcia_device *p_dev);
static int avma1cs_probe(struct pcmcia_device *p_dev)
{
dev_dbg(&p_dev->dev, "avma1cs_attach()\n");
/* General socket configuration */
p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
p_dev->config_index = 1;
p_dev->config_regs = PRESENT_OPTION;
return avma1cs_config(p_dev);
} /* avma1cs_attach */
static void avma1cs_detach(struct pcmcia_device *link)
{
dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link);
avma1cs_release(link);
kfree(link->priv);
} /* avma1cs_detach */
static int avma1cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
{
p_dev->resource[0]->end = 16;
p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
p_dev->io_lines = 5;
return pcmcia_request_io(p_dev);
}
static int avma1cs_config(struct pcmcia_device *link)
{
int i = -1;
char devname[128];
IsdnCard_t icard;
int busy = 0;
dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link);
devname[0] = 0;
if (link->prod_id[1])
strlcpy(devname, link->prod_id[1], sizeof(devname));
if (pcmcia_loop_config(link, avma1cs_configcheck, NULL))
return -ENODEV;
do {
/*
* allocate an interrupt line
*/
if (!link->irq) {
/* undo */
pcmcia_disable_device(link);
break;
}
/*
* configure the PCMCIA socket
*/
i = pcmcia_enable_device(link);
if (i != 0) {
pcmcia_disable_device(link);
break;
}
} while (0);
/* If any step failed, release any partially configured state */
if (i != 0) {
avma1cs_release(link);
return -ENODEV;
}
icard.para[0] = link->irq;
icard.para[1] = link->resource[0]->start;
icard.protocol = isdnprot;
icard.typ = ISDN_CTYPE_A1_PCMCIA;
i = hisax_init_pcmcia(link, &busy, &icard);
if (i < 0) {
printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 "
"PCMCIA %d at i/o %#x\n", i,
(unsigned int) link->resource[0]->start);
avma1cs_release(link);
return -ENODEV;
}
link->priv = (void *) (unsigned long) i;
return 0;
} /* avma1cs_config */
static void avma1cs_release(struct pcmcia_device *link)
{
unsigned long minor = (unsigned long) link->priv;
dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link);
/* now unregister function with hisax */
HiSax_closecard(minor);
pcmcia_disable_device(link);
} /* avma1cs_release */
static const struct pcmcia_device_id avma1cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
static struct pcmcia_driver avma1cs_driver = {
.owner = THIS_MODULE,
.name = "avma1_cs",
.probe = avma1cs_probe,
.remove = avma1cs_detach,
.id_table = avma1cs_ids,
};
module_pcmcia_driver(avma1cs_driver);

View file

@ -1,358 +0,0 @@
/* $Id: bkm_a4t.c,v 1.22.2.4 2004/01/14 16:04:48 keil Exp $
*
* low level stuff for T-Berkom A4T
*
* Author Roland Klabunde
* Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "jade.h"
#include "isdnl1.h"
#include <linux/pci.h>
#include "bkm_ax.h"
static const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $";
static inline u_char
readreg(unsigned int ale, unsigned long adr, u_char off)
{
register u_int ret;
unsigned int *po = (unsigned int *) adr; /* Postoffice */
*po = (GCS_2 | PO_WRITE | off);
__WAITI20__(po);
*po = (ale | PO_READ);
__WAITI20__(po);
ret = *po;
return ((unsigned char) ret);
}
static inline void
readfifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size)
{
int i;
for (i = 0; i < size; i++)
*data++ = readreg(ale, adr, off);
}
static inline void
writereg(unsigned int ale, unsigned long adr, u_char off, u_char data)
{
unsigned int *po = (unsigned int *) adr; /* Postoffice */
*po = (GCS_2 | PO_WRITE | off);
__WAITI20__(po);
*po = (ale | PO_WRITE | data);
__WAITI20__(po);
}
static inline void
writefifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size)
{
int i;
for (i = 0; i < size; i++)
writereg(ale, adr, off, *data++);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
}
static u_char
ReadJADE(struct IsdnCardState *cs, int jade, u_char offset)
{
return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80))));
}
static void
WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value)
{
writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value);
}
/*
* fast interrupt JADE stuff goes here
*/
#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale, \
cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)))
#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale, \
cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data)
#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale, \
cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.jade_ale, \
cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
#include "jade_irq.c"
static irqreturn_t
bkm_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val = 0;
u_long flags;
I20_REGISTER_FILE *pI20_Regs;
spin_lock_irqsave(&cs->lock, flags);
pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
/* ISDN interrupt pending? */
if (pI20_Regs->i20IntStatus & intISDN) {
/* Reset the ISDN interrupt */
pI20_Regs->i20IntStatus = intISDN;
/* Disable ISDN interrupt */
pI20_Regs->i20IntCtrl &= ~intISDN;
/* Channel A first */
val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80);
if (val) {
jade_int_main(cs, val, 0);
}
/* Channel B */
val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0);
if (val) {
jade_int_main(cs, val, 1);
}
/* D-Channel */
val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA);
if (val) {
isac_interrupt(cs, val);
}
/* Reenable ISDN interrupt */
pI20_Regs->i20IntCtrl |= intISDN;
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
} else {
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
}
static void
release_io_bkm(struct IsdnCardState *cs)
{
if (cs->hw.ax.base) {
iounmap((void *) cs->hw.ax.base);
cs->hw.ax.base = 0;
}
}
static void
enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
{
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
if (bEnable)
pI20_Regs->i20IntCtrl |= (intISDN | intPCI);
else
/* CAUTION: This disables the video capture driver too */
pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI);
}
}
static void
reset_bkm(struct IsdnCardState *cs)
{
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
/* Issue the I20 soft reset */
pI20_Regs->i20SysControl = 0xFF; /* all in */
mdelay(10);
/* Remove the soft reset */
pI20_Regs->i20SysControl = sysRESET | 0xFF;
mdelay(10);
/* Set our configuration */
pI20_Regs->i20SysControl = sysRESET | sysCFG;
/* Issue ISDN reset */
pI20_Regs->i20GuestControl = guestWAIT_CFG |
g_A4T_JADE_RES |
g_A4T_ISAR_RES |
g_A4T_ISAC_RES |
g_A4T_JADE_BOOTR |
g_A4T_ISAR_BOOTR;
mdelay(10);
/* Remove RESET state from ISDN */
pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
g_A4T_JADE_RES |
g_A4T_ISAR_RES);
mdelay(10);
}
}
static int
BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
/* Disable ints */
spin_lock_irqsave(&cs->lock, flags);
enable_bkm_int(cs, 0);
reset_bkm(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
/* Sanity */
spin_lock_irqsave(&cs->lock, flags);
enable_bkm_int(cs, 0);
reset_bkm(cs);
spin_unlock_irqrestore(&cs->lock, flags);
release_io_bkm(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
clear_pending_isac_ints(cs);
clear_pending_jade_ints(cs);
initisac(cs);
initjade(cs);
/* Enable ints */
enable_bkm_int(cs, 1);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int a4t_pci_probe(struct pci_dev *dev_a4t, struct IsdnCardState *cs,
u_int *found, u_int *pci_memaddr)
{
u16 sub_sys;
u16 sub_vendor;
sub_vendor = dev_a4t->subsystem_vendor;
sub_sys = dev_a4t->subsystem_device;
if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
if (pci_enable_device(dev_a4t))
return (0); /* end loop & function */
*found = 1;
*pci_memaddr = pci_resource_start(dev_a4t, 0);
cs->irq = dev_a4t->irq;
return (1); /* end loop */
}
return (-1); /* continue looping */
}
static int a4t_cs_init(struct IsdnCard *card, struct IsdnCardState *cs,
u_int pci_memaddr)
{
I20_REGISTER_FILE *pI20_Regs;
if (!cs->irq) { /* IRQ range check ?? */
printk(KERN_WARNING "HiSax: Telekom A4T: No IRQ\n");
return (0);
}
cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096);
/* Check suspecious address */
pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) {
printk(KERN_WARNING "HiSax: Telekom A4T address "
"%lx-%lx suspicious\n",
cs->hw.ax.base, cs->hw.ax.base + 4096);
iounmap((void *) cs->hw.ax.base);
cs->hw.ax.base = 0;
return (0);
}
cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET;
cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
cs->hw.ax.isac_ale = GCS_1;
cs->hw.ax.jade_ale = GCS_3;
printk(KERN_INFO "HiSax: Telekom A4T: Card configured at "
"0x%lX IRQ %d\n",
cs->hw.ax.base, cs->irq);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadJADE;
cs->BC_Write_Reg = &WriteJADE;
cs->BC_Send_Data = &jade_fill_fifo;
cs->cardmsg = &BKM_card_msg;
cs->irq_func = &bkm_interrupt;
cs->irq_flags |= IRQF_SHARED;
ISACVersion(cs, "Telekom A4T:");
/* Jade version */
JadeVersion(cs, "Telekom A4T:");
return (1);
}
static struct pci_dev *dev_a4t = NULL;
int setup_bkm_a4t(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
u_int pci_memaddr = 0, found = 0;
int ret;
strcpy(tmp, bkm_a4t_revision);
printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
cs->subtyp = BKM_A4T;
} else
return (0);
while ((dev_a4t = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN,
PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
ret = a4t_pci_probe(dev_a4t, cs, &found, &pci_memaddr);
if (!ret)
return (0);
if (ret > 0)
break;
}
if (!found) {
printk(KERN_WARNING "HiSax: Telekom A4T: Card not found\n");
return (0);
}
if (!pci_memaddr) {
printk(KERN_WARNING "HiSax: Telekom A4T: "
"No Memory base address\n");
return (0);
}
return a4t_cs_init(card, cs, pci_memaddr);
}

View file

@ -1,433 +0,0 @@
/* $Id: bkm_a8.c,v 1.22.2.4 2004/01/15 14:02:34 keil Exp $
*
* low level stuff for Scitel Quadro (4*S0, passive)
*
* Author Roland Klabunde
* Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "ipac.h"
#include "hscx.h"
#include "isdnl1.h"
#include <linux/pci.h>
#include "bkm_ax.h"
#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
static const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $";
static const char *sct_quadro_subtypes[] =
{
"",
"#1",
"#2",
"#3",
"#4"
};
#define wordout(addr, val) outw(val, addr)
#define wordin(addr) inw(addr)
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
wordout(ale, off);
ret = wordin(adr) & 0xFF;
return (ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
int i;
wordout(ale, off);
for (i = 0; i < size; i++)
data[i] = wordin(adr) & 0xFF;
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
wordout(ale, off);
wordout(adr, data);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
int i;
wordout(ale, off);
for (i = 0; i < size; i++)
wordout(adr, data[i]);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0)));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
}
/* Set the specific ipac to active */
static void
set_ipac_active(struct IsdnCardState *cs, u_int active)
{
/* set irq mask */
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK,
active ? 0xc0 : 0xff);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \
cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0))
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \
cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \
cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \
cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
bkm_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val, icnt = 5;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
if (!(ista & 0x3f)) { /* not this IPAC */
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
Start_IPAC:
if (cs->debug & L1_DEB_IPAC)
debugl1(cs, "IPAC ISTA %02X", ista);
if (ista & 0x0f) {
val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40);
if (ista & 0x01)
val |= 0x01;
if (ista & 0x04)
val |= 0x02;
if (ista & 0x08)
val |= 0x04;
if (val) {
hscx_int_main(cs, val);
}
}
if (ista & 0x20) {
val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80);
if (val) {
isac_interrupt(cs, val);
}
}
if (ista & 0x10) {
val = 0x01;
isac_interrupt(cs, val);
}
ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
if ((ista & 0x3f) && icnt) {
icnt--;
goto Start_IPAC;
}
if (!icnt)
printk(KERN_WARNING "HiSax: Scitel Quadro (%s) IRQ LOOP\n",
sct_quadro_subtypes[cs->subtyp]);
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_sct_quadro(struct IsdnCardState *cs)
{
release_region(cs->hw.ax.base & 0xffffffc0, 128);
if (cs->subtyp == SCT_1)
release_region(cs->hw.ax.plx_adr, 64);
}
static void
enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
{
if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
if (bEnable)
wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
else
wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
}
}
static void
reset_bkm(struct IsdnCardState *cs)
{
if (cs->subtyp == SCT_1) {
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
mdelay(10);
/* Remove the soft reset */
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
mdelay(10);
}
}
static int
BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
/* Disable ints */
set_ipac_active(cs, 0);
enable_bkm_int(cs, 0);
reset_bkm(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
/* Sanity */
spin_lock_irqsave(&cs->lock, flags);
set_ipac_active(cs, 0);
enable_bkm_int(cs, 0);
spin_unlock_irqrestore(&cs->lock, flags);
release_io_sct_quadro(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
cs->debug |= L1_DEB_IPAC;
set_ipac_active(cs, 1);
inithscxisac(cs, 3);
/* Enable ints */
enable_bkm_int(cs, 1);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int sct_alloc_io(u_int adr, u_int len)
{
if (!request_region(adr, len, "scitel")) {
printk(KERN_WARNING
"HiSax: Scitel port %#x-%#x already in use\n",
adr, adr + len);
return (1);
}
return (0);
}
static struct pci_dev *dev_a8 = NULL;
static u16 sub_vendor_id = 0;
static u16 sub_sys_id = 0;
static u_char pci_bus = 0;
static u_char pci_device_fn = 0;
static u_char pci_irq = 0;
int setup_sct_quadro(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
u_int found = 0;
u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
strcpy(tmp, sct_quadro_revision);
printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
cs->subtyp = SCT_1; /* Preset */
} else
return (0);
/* Identify subtype by para[0] */
if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
cs->subtyp = card->para[0];
else {
printk(KERN_WARNING "HiSax: Scitel Quadro: Invalid "
"subcontroller in configuration, default to 1\n");
return (0);
}
if ((cs->subtyp != SCT_1) && ((sub_sys_id != PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) ||
(sub_vendor_id != PCI_VENDOR_ID_BERKOM)))
return (0);
if (cs->subtyp == SCT_1) {
while ((dev_a8 = hisax_find_pci_device(PCI_VENDOR_ID_PLX,
PCI_DEVICE_ID_PLX_9050, dev_a8))) {
sub_vendor_id = dev_a8->subsystem_vendor;
sub_sys_id = dev_a8->subsystem_device;
if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) &&
(sub_vendor_id == PCI_VENDOR_ID_BERKOM)) {
if (pci_enable_device(dev_a8))
return (0);
pci_ioaddr1 = pci_resource_start(dev_a8, 1);
pci_irq = dev_a8->irq;
pci_bus = dev_a8->bus->number;
pci_device_fn = dev_a8->devfn;
found = 1;
break;
}
}
if (!found) {
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
"Card not found\n",
sct_quadro_subtypes[cs->subtyp]);
return (0);
}
#ifdef ATTEMPT_PCI_REMAPPING
/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
if ((pci_ioaddr1 & 0x80) && (dev_a8->revision == 1)) {
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
"PLX rev 1, remapping required!\n",
sct_quadro_subtypes[cs->subtyp]);
/* Restart PCI negotiation */
pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, (u_int)-1);
/* Move up by 0x80 byte */
pci_ioaddr1 += 0x80;
pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, pci_ioaddr1);
dev_a8->resource[1].start = pci_ioaddr1;
}
#endif /* End HACK */
}
if (!pci_irq) { /* IRQ range check ?? */
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): No IRQ\n",
sct_quadro_subtypes[cs->subtyp]);
return (0);
}
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_4, &pci_ioaddr4);
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_5, &pci_ioaddr5);
if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) {
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
"No IO base address(es)\n",
sct_quadro_subtypes[cs->subtyp]);
return (0);
}
pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK;
/* Take over */
cs->irq = pci_irq;
cs->irq_flags |= IRQF_SHARED;
/* pci_ioaddr1 is unique to all subdevices */
/* pci_ioaddr2 is for the fourth subdevice only */
/* pci_ioaddr3 is for the third subdevice only */
/* pci_ioaddr4 is for the second subdevice only */
/* pci_ioaddr5 is for the first subdevice only */
cs->hw.ax.plx_adr = pci_ioaddr1;
/* Enter all ipac_base addresses */
switch (cs->subtyp) {
case 1:
cs->hw.ax.base = pci_ioaddr5 + 0x00;
if (sct_alloc_io(pci_ioaddr1, 128))
return (0);
if (sct_alloc_io(pci_ioaddr5, 64))
return (0);
/* disable all IPAC */
writereg(pci_ioaddr5, pci_ioaddr5 + 4,
IPAC_MASK, 0xFF);
writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c,
IPAC_MASK, 0xFF);
writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14,
IPAC_MASK, 0xFF);
writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24,
IPAC_MASK, 0xFF);
break;
case 2:
cs->hw.ax.base = pci_ioaddr4 + 0x08;
if (sct_alloc_io(pci_ioaddr4, 64))
return (0);
break;
case 3:
cs->hw.ax.base = pci_ioaddr3 + 0x10;
if (sct_alloc_io(pci_ioaddr3, 64))
return (0);
break;
case 4:
cs->hw.ax.base = pci_ioaddr2 + 0x20;
if (sct_alloc_io(pci_ioaddr2, 64))
return (0);
break;
}
/* For isac and hscx data path */
cs->hw.ax.data_adr = cs->hw.ax.base + 4;
printk(KERN_INFO "HiSax: Scitel Quadro (%s) configured at "
"0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %d\n",
sct_quadro_subtypes[cs->subtyp],
cs->hw.ax.plx_adr,
cs->hw.ax.base,
cs->hw.ax.data_adr,
cs->irq);
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &BKM_card_msg;
cs->irq_func = &bkm_interrupt_ipac;
printk(KERN_INFO "HiSax: Scitel Quadro (%s): IPAC Version %d\n",
sct_quadro_subtypes[cs->subtyp],
readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
return (1);
}

View file

@ -1,119 +0,0 @@
/* $Id: bkm_ax.h,v 1.5.6.3 2001/09/23 22:24:46 kai Exp $
*
* low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive)
*
* Author Roland Klabunde
* Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef __BKM_AX_H__
#define __BKM_AX_H__
/* Supported boards (subtypes) */
#define SCT_1 1
#define SCT_2 2
#define SCT_3 3
#define SCT_4 4
#define BKM_A4T 5
#define PLX_ADDR_PLX 0x14 /* Addr PLX configuration */
#define PLX_ADDR_ISAC 0x18 /* Addr ISAC */
#define PLX_ADDR_HSCX 0x1C /* Addr HSCX */
#define PLX_ADDR_ALE 0x20 /* Addr ALE */
#define PLX_ADDR_ALEPLUS 0x24 /* Next Addr behind ALE */
#define PLX_SUBVEN 0x2C /* Offset SubVendor */
#define PLX_SUBSYS 0x2E /* Offset SubSystem */
/* Application specific registers I20 (Siemens SZB6120H) */
typedef struct {
/* Video front end horizontal configuration register */
volatile u_int i20VFEHorzCfg; /* Offset 00 */
/* Video front end vertical configuration register */
volatile u_int i20VFEVertCfg; /* Offset 04 */
/* Video front end scaler and pixel format register */
volatile u_int i20VFEScaler; /* Offset 08 */
/* Video display top register */
volatile u_int i20VDispTop; /* Offset 0C */
/* Video display bottom register */
volatile u_int i20VDispBottom; /* Offset 10 */
/* Video stride, status and frame grab register */
volatile u_int i20VidFrameGrab;/* Offset 14 */
/* Video display configuration register */
volatile u_int i20VDispCfg; /* Offset 18 */
/* Video masking map top */
volatile u_int i20VMaskTop; /* Offset 1C */
/* Video masking map bottom */
volatile u_int i20VMaskBottom; /* Offset 20 */
/* Overlay control register */
volatile u_int i20OvlyControl; /* Offset 24 */
/* System, PCI and general purpose pins control register */
volatile u_int i20SysControl; /* Offset 28 */
#define sysRESET 0x01000000 /* bit 24:Softreset (Low) */
/* GPIO 4...0: Output fixed for our cfg! */
#define sysCFG 0x000000E0 /* GPIO 7,6,5: Input */
/* General purpose pins and guest bus control register */
volatile u_int i20GuestControl;/* Offset 2C */
#define guestWAIT_CFG 0x00005555 /* 4 PCI waits for all */
#define guestISDN_INT_E 0x01000000 /* ISDN Int en (low) */
#define guestVID_INT_E 0x02000000 /* Video interrupt en (low) */
#define guestADI1_INT_R 0x04000000 /* ADI #1 int req (low) */
#define guestADI2_INT_R 0x08000000 /* ADI #2 int req (low) */
#define guestISDN_RES 0x10000000 /* ISDN reset bit (high) */
#define guestADI1_INT_S 0x20000000 /* ADI #1 int pending (low) */
#define guestADI2_INT_S 0x40000000 /* ADI #2 int pending (low) */
#define guestISDN_INT_S 0x80000000 /* ISAC int pending (low) */
#define g_A4T_JADE_RES 0x01000000 /* JADE Reset (High) */
#define g_A4T_ISAR_RES 0x02000000 /* ISAR Reset (High) */
#define g_A4T_ISAC_RES 0x04000000 /* ISAC Reset (High) */
#define g_A4T_JADE_BOOTR 0x08000000 /* JADE enable boot SRAM (Low) NOT USED */
#define g_A4T_ISAR_BOOTR 0x10000000 /* ISAR enable boot SRAM (Low) NOT USED */
#define g_A4T_JADE_INT_S 0x20000000 /* JADE interrupt pnd (Low) */
#define g_A4T_ISAR_INT_S 0x40000000 /* ISAR interrupt pnd (Low) */
#define g_A4T_ISAC_INT_S 0x80000000 /* ISAC interrupt pnd (Low) */
volatile u_int i20CodeSource; /* Offset 30 */
volatile u_int i20CodeXferCtrl;/* Offset 34 */
volatile u_int i20CodeMemPtr; /* Offset 38 */
volatile u_int i20IntStatus; /* Offset 3C */
volatile u_int i20IntCtrl; /* Offset 40 */
#define intISDN 0x40000000 /* GIRQ1En (ISAC/ADI) (High) */
#define intVID 0x20000000 /* GIRQ0En (VSYNC) (High) */
#define intCOD 0x10000000 /* CodRepIrqEn (High) */
#define intPCI 0x01000000 /* PCI IntA enable (High) */
volatile u_int i20I2CCtrl; /* Offset 44 */
} I20_REGISTER_FILE, *PI20_REGISTER_FILE;
/*
* Postoffice structure for A4T
*
*/
#define PO_OFFSET 0x00000200 /* Postoffice offset from base */
#define GCS_0 0x00000000 /* Guest bus chip selects */
#define GCS_1 0x00100000
#define GCS_2 0x00200000
#define GCS_3 0x00300000
#define PO_READ 0x00000000 /* R/W from/to guest bus */
#define PO_WRITE 0x00800000
#define PO_PEND 0x02000000
#define POSTOFFICE(postoffice) *(volatile unsigned int *)(postoffice)
/* Wait unlimited (don't worry) */
#define __WAITI20__(postoffice) \
do { \
while ((POSTOFFICE(postoffice) & PO_PEND)) ; \
} while (0)
#endif /* __BKM_AX_H__ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,218 +0,0 @@
/*======================================================================
An elsa_cs PCMCIA client driver
This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The initial developer of the original code is David A. Hinds
<dahinds@users.sourceforge.net>. Portions created by David A. Hinds
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus
Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved.
Alternatively, the contents of this file may be used under the
terms of the GNU General Public License version 2 (the "GPL"), in
which case the provisions of the GPL are applicable instead of the
above. If you wish to allow the use of your version of this file
only under the terms of the GPL and not to allow others to use
your version of this file under the MPL, indicate your decision
by deleting the provisions above and replace them with the notice
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
======================================================================*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
#include "hisax_cfg.h"
MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
MODULE_AUTHOR("Klaus Lichtenwalder");
MODULE_LICENSE("Dual MPL/GPL");
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
static int protocol = 2; /* EURO-ISDN Default */
module_param(protocol, int, 0);
static int elsa_cs_config(struct pcmcia_device *link);
static void elsa_cs_release(struct pcmcia_device *link);
static void elsa_cs_detach(struct pcmcia_device *p_dev);
typedef struct local_info_t {
struct pcmcia_device *p_dev;
int busy;
int cardnr;
} local_info_t;
static int elsa_cs_probe(struct pcmcia_device *link)
{
local_info_t *local;
dev_dbg(&link->dev, "elsa_cs_attach()\n");
/* Allocate space for private device-specific data */
local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) return -ENOMEM;
local->p_dev = link;
link->priv = local;
local->cardnr = -1;
return elsa_cs_config(link);
} /* elsa_cs_attach */
static void elsa_cs_detach(struct pcmcia_device *link)
{
local_info_t *info = link->priv;
dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link);
info->busy = 1;
elsa_cs_release(link);
kfree(info);
} /* elsa_cs_detach */
static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
{
int j;
p_dev->io_lines = 3;
p_dev->resource[0]->end = 8;
p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
if (!pcmcia_request_io(p_dev))
return 0;
} else {
printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
for (j = 0x2f0; j > 0x100; j -= 0x10) {
p_dev->resource[0]->start = j;
if (!pcmcia_request_io(p_dev))
return 0;
}
}
return -ENODEV;
}
static int elsa_cs_config(struct pcmcia_device *link)
{
int i;
IsdnCard_t icard;
dev_dbg(&link->dev, "elsa_config(0x%p)\n", link);
link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
if (i != 0)
goto failed;
if (!link->irq)
goto failed;
i = pcmcia_enable_device(link);
if (i != 0)
goto failed;
icard.para[0] = link->irq;
icard.para[1] = link->resource[0]->start;
icard.protocol = protocol;
icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard);
if (i < 0) {
printk(KERN_ERR "elsa_cs: failed to initialize Elsa "
"PCMCIA %d with %pR\n", i, link->resource[0]);
elsa_cs_release(link);
} else
((local_info_t *)link->priv)->cardnr = i;
return 0;
failed:
elsa_cs_release(link);
return -ENODEV;
} /* elsa_cs_config */
static void elsa_cs_release(struct pcmcia_device *link)
{
local_info_t *local = link->priv;
dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link);
if (local) {
if (local->cardnr >= 0) {
/* no unregister function with hisax */
HiSax_closecard(local->cardnr);
}
}
pcmcia_disable_device(link);
} /* elsa_cs_release */
static int elsa_suspend(struct pcmcia_device *link)
{
local_info_t *dev = link->priv;
dev->busy = 1;
return 0;
}
static int elsa_resume(struct pcmcia_device *link)
{
local_info_t *dev = link->priv;
dev->busy = 0;
return 0;
}
static const struct pcmcia_device_id elsa_ids[] = {
PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
static struct pcmcia_driver elsa_cs_driver = {
.owner = THIS_MODULE,
.name = "elsa_cs",
.probe = elsa_cs_probe,
.remove = elsa_cs_detach,
.id_table = elsa_ids,
.suspend = elsa_suspend,
.resume = elsa_resume,
};
module_pcmcia_driver(elsa_cs_driver);

View file

@ -1,659 +0,0 @@
/* $Id: elsa_ser.c,v 2.14.2.3 2004/02/11 13:21:33 keil Exp $
*
* stuff for the serial modem on ELSA cards
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/serial.h>
#include <linux/serial_reg.h>
#include <linux/slab.h>
#define MAX_MODEM_BUF 256
#define WAKEUP_CHARS (MAX_MODEM_BUF / 2)
#define RS_ISR_PASS_LIMIT 256
#define BASE_BAUD (1843200 / 16)
//#define SERIAL_DEBUG_OPEN 1
//#define SERIAL_DEBUG_INTR 1
//#define SERIAL_DEBUG_FLOW 1
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_FLOW
#undef SERIAL_DEBUG_REG
//#define SERIAL_DEBUG_REG 1
#ifdef SERIAL_DEBUG_REG
static u_char deb[32];
const char *ModemIn[] = {"RBR", "IER", "IIR", "LCR", "MCR", "LSR", "MSR", "SCR"};
const char *ModemOut[] = {"THR", "IER", "FCR", "LCR", "MCR", "LSR", "MSR", "SCR"};
#endif
static char *MInit_1 = "AT&F&C1E0&D2\r\0";
static char *MInit_2 = "ATL2M1S64=13\r\0";
static char *MInit_3 = "AT+FCLASS=0\r\0";
static char *MInit_4 = "ATV1S2=128X1\r\0";
static char *MInit_5 = "AT\\V8\\N3\r\0";
static char *MInit_6 = "ATL0M0&G0%E1\r\0";
static char *MInit_7 = "AT%L1%M0%C3\r\0";
static char *MInit_speed28800 = "AT%G0%B28800\r\0";
static char *MInit_dialout = "ATs7=60 x1 d\r\0";
static char *MInit_dialin = "ATs7=60 x1 a\r\0";
static inline unsigned int serial_in(struct IsdnCardState *cs, int offset)
{
#ifdef SERIAL_DEBUG_REG
u_int val = inb(cs->hw.elsa.base + 8 + offset);
debugl1(cs, "in %s %02x", ModemIn[offset], val);
return (val);
#else
return inb(cs->hw.elsa.base + 8 + offset);
#endif
}
static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset)
{
#ifdef SERIAL_DEBUG_REG
#ifdef ELSA_SERIAL_NOPAUSE_IO
u_int val = inb(cs->hw.elsa.base + 8 + offset);
debugl1(cs, "inp %s %02x", ModemIn[offset], val);
#else
u_int val = inb_p(cs->hw.elsa.base + 8 + offset);
debugl1(cs, "inP %s %02x", ModemIn[offset], val);
#endif
return (val);
#else
#ifdef ELSA_SERIAL_NOPAUSE_IO
return inb(cs->hw.elsa.base + 8 + offset);
#else
return inb_p(cs->hw.elsa.base + 8 + offset);
#endif
#endif
}
static inline void serial_out(struct IsdnCardState *cs, int offset, int value)
{
#ifdef SERIAL_DEBUG_REG
debugl1(cs, "out %s %02x", ModemOut[offset], value);
#endif
outb(value, cs->hw.elsa.base + 8 + offset);
}
static inline void serial_outp(struct IsdnCardState *cs, int offset,
int value)
{
#ifdef SERIAL_DEBUG_REG
#ifdef ELSA_SERIAL_NOPAUSE_IO
debugl1(cs, "outp %s %02x", ModemOut[offset], value);
#else
debugl1(cs, "outP %s %02x", ModemOut[offset], value);
#endif
#endif
#ifdef ELSA_SERIAL_NOPAUSE_IO
outb(value, cs->hw.elsa.base + 8 + offset);
#else
outb_p(value, cs->hw.elsa.base + 8 + offset);
#endif
}
/*
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
static void change_speed(struct IsdnCardState *cs, int baud)
{
int quot = 0, baud_base;
unsigned cval, fcr = 0;
/* byte size and parity */
cval = 0x03;
/* Determine divisor based on baud rate */
baud_base = BASE_BAUD;
quot = baud_base / baud;
/* If the quotient is ever zero, default to 9600 bps */
if (!quot)
quot = baud_base / 9600;
/* Set up FIFO's */
if ((baud_base / quot) < 2400)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
serial_outp(cs, UART_FCR, fcr);
/* CTS flow control flag and modem status interrupts */
cs->hw.elsa.IER &= ~UART_IER_MSI;
cs->hw.elsa.IER |= UART_IER_MSI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER);
debugl1(cs, "modem quot=0x%x", quot);
serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
serial_outp(cs, UART_DLL, quot & 0xff); /* LS of divisor */
serial_outp(cs, UART_DLM, quot >> 8); /* MS of divisor */
serial_outp(cs, UART_LCR, cval); /* reset DLAB */
serial_inp(cs, UART_RX);
}
static int mstartup(struct IsdnCardState *cs)
{
int retval = 0;
/*
* Clear the FIFO buffers and disable them
* (they will be reenabled in change_speed())
*/
serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
/*
* At this point there's no way the LSR could still be 0xFF;
* if it is, then bail out, because there's likely no UART
* here.
*/
if (serial_inp(cs, UART_LSR) == 0xff) {
retval = -ENODEV;
goto errout;
}
/*
* Clear the interrupt registers.
*/
(void) serial_inp(cs, UART_RX);
(void) serial_inp(cs, UART_IIR);
(void) serial_inp(cs, UART_MSR);
/*
* Now, initialize the UART
*/
serial_outp(cs, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
cs->hw.elsa.MCR = 0;
cs->hw.elsa.MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
serial_outp(cs, UART_MCR, cs->hw.elsa.MCR);
/*
* Finally, enable interrupts
*/
cs->hw.elsa.IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER); /* enable interrupts */
/*
* And clear the interrupt registers again for luck.
*/
(void)serial_inp(cs, UART_LSR);
(void)serial_inp(cs, UART_RX);
(void)serial_inp(cs, UART_IIR);
(void)serial_inp(cs, UART_MSR);
cs->hw.elsa.transcnt = cs->hw.elsa.transp = 0;
cs->hw.elsa.rcvcnt = cs->hw.elsa.rcvp = 0;
/*
* and set the speed of the serial port
*/
change_speed(cs, BASE_BAUD);
cs->hw.elsa.MFlag = 1;
errout:
return retval;
}
/*
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
static void mshutdown(struct IsdnCardState *cs)
{
#ifdef SERIAL_DEBUG_OPEN
printk(KERN_DEBUG"Shutting down serial ....");
#endif
/*
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq
* here so the queue might never be waken up
*/
cs->hw.elsa.IER = 0;
serial_outp(cs, UART_IER, 0x00); /* disable all intrs */
cs->hw.elsa.MCR &= ~UART_MCR_OUT2;
/* disable break condition */
serial_outp(cs, UART_LCR, serial_inp(cs, UART_LCR) & ~UART_LCR_SBC);
cs->hw.elsa.MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
serial_outp(cs, UART_MCR, cs->hw.elsa.MCR);
/* disable FIFO's */
serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
serial_inp(cs, UART_RX); /* read data port to reset things */
#ifdef SERIAL_DEBUG_OPEN
printk(" done\n");
#endif
}
static inline int
write_modem(struct BCState *bcs) {
int ret = 0;
struct IsdnCardState *cs = bcs->cs;
int count, len, fp;
if (!bcs->tx_skb)
return 0;
if (bcs->tx_skb->len <= 0)
return 0;
len = bcs->tx_skb->len;
if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt)
len = MAX_MODEM_BUF - cs->hw.elsa.transcnt;
fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
fp &= (MAX_MODEM_BUF - 1);
count = len;
if (count > MAX_MODEM_BUF - fp) {
count = MAX_MODEM_BUF - fp;
skb_copy_from_linear_data(bcs->tx_skb,
cs->hw.elsa.transbuf + fp, count);
skb_pull(bcs->tx_skb, count);
cs->hw.elsa.transcnt += count;
ret = count;
count = len - count;
fp = 0;
}
skb_copy_from_linear_data(bcs->tx_skb,
cs->hw.elsa.transbuf + fp, count);
skb_pull(bcs->tx_skb, count);
cs->hw.elsa.transcnt += count;
ret += count;
if (cs->hw.elsa.transcnt &&
!(cs->hw.elsa.IER & UART_IER_THRI)) {
cs->hw.elsa.IER |= UART_IER_THRI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER);
}
return (ret);
}
static inline void
modem_fill(struct BCState *bcs) {
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
write_modem(bcs);
return;
} else {
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += bcs->hw.hscx.count;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
}
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
bcs->hw.hscx.count = 0;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
write_modem(bcs);
} else {
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
schedule_event(bcs, B_XMTBUFREADY);
}
}
static inline void receive_chars(struct IsdnCardState *cs,
int *status)
{
unsigned char ch;
struct sk_buff *skb;
do {
ch = serial_in(cs, UART_RX);
if (cs->hw.elsa.rcvcnt >= MAX_MODEM_BUF)
break;
cs->hw.elsa.rcvbuf[cs->hw.elsa.rcvcnt++] = ch;
#ifdef SERIAL_DEBUG_INTR
printk("DR%02x:%02x...", ch, *status);
#endif
if (*status & (UART_LSR_BI | UART_LSR_PE |
UART_LSR_FE | UART_LSR_OE)) {
#ifdef SERIAL_DEBUG_INTR
printk("handling exept....");
#endif
}
*status = serial_inp(cs, UART_LSR);
} while (*status & UART_LSR_DR);
if (cs->hw.elsa.MFlag == 2) {
if (!(skb = dev_alloc_skb(cs->hw.elsa.rcvcnt)))
printk(KERN_WARNING "ElsaSER: receive out of memory\n");
else {
skb_put_data(skb, cs->hw.elsa.rcvbuf,
cs->hw.elsa.rcvcnt);
skb_queue_tail(&cs->hw.elsa.bcs->rqueue, skb);
}
schedule_event(cs->hw.elsa.bcs, B_RCVBUFREADY);
} else {
char tmp[128];
char *t = tmp;
t += sprintf(t, "modem read cnt %d", cs->hw.elsa.rcvcnt);
QuickHex(t, cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt);
debugl1(cs, "%s", tmp);
}
cs->hw.elsa.rcvcnt = 0;
}
static inline void transmit_chars(struct IsdnCardState *cs, int *intr_done)
{
int count;
debugl1(cs, "transmit_chars: p(%x) cnt(%x)", cs->hw.elsa.transp,
cs->hw.elsa.transcnt);
if (cs->hw.elsa.transcnt <= 0) {
cs->hw.elsa.IER &= ~UART_IER_THRI;
serial_out(cs, UART_IER, cs->hw.elsa.IER);
return;
}
count = 16;
do {
serial_outp(cs, UART_TX, cs->hw.elsa.transbuf[cs->hw.elsa.transp++]);
if (cs->hw.elsa.transp >= MAX_MODEM_BUF)
cs->hw.elsa.transp = 0;
if (--cs->hw.elsa.transcnt <= 0)
break;
} while (--count > 0);
if ((cs->hw.elsa.transcnt < WAKEUP_CHARS) && (cs->hw.elsa.MFlag == 2))
modem_fill(cs->hw.elsa.bcs);
#ifdef SERIAL_DEBUG_INTR
printk("THRE...");
#endif
if (intr_done)
*intr_done = 0;
if (cs->hw.elsa.transcnt <= 0) {
cs->hw.elsa.IER &= ~UART_IER_THRI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER);
}
}
static void rs_interrupt_elsa(struct IsdnCardState *cs)
{
int status, iir, msr;
int pass_counter = 0;
#ifdef SERIAL_DEBUG_INTR
printk(KERN_DEBUG "rs_interrupt_single(%d)...", cs->irq);
#endif
do {
status = serial_inp(cs, UART_LSR);
debugl1(cs, "rs LSR %02x", status);
#ifdef SERIAL_DEBUG_INTR
printk("status = %x...", status);
#endif
if (status & UART_LSR_DR)
receive_chars(cs, &status);
if (status & UART_LSR_THRE)
transmit_chars(cs, NULL);
if (pass_counter++ > RS_ISR_PASS_LIMIT) {
printk("rs_single loop break.\n");
break;
}
iir = serial_inp(cs, UART_IIR);
debugl1(cs, "rs IIR %02x", iir);
if ((iir & 0xf) == 0) {
msr = serial_inp(cs, UART_MSR);
debugl1(cs, "rs MSR %02x", msr);
}
} while (!(iir & UART_IIR_NO_INT));
#ifdef SERIAL_DEBUG_INTR
printk("end.\n");
#endif
}
extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs);
extern void modehscx(struct BCState *bcs, int mode, int bc);
extern void hscx_l2l1(struct PStack *st, int pr, void *arg);
static void
close_elsastate(struct BCState *bcs)
{
modehscx(bcs, 0, bcs->channel);
if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
if (bcs->hw.hscx.rcvbuf) {
if (bcs->mode != L1_MODE_MODEM)
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
}
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
}
static void
modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
int count, fp;
u_char *msg = buf;
if (!len)
return;
if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) {
return;
}
fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
fp &= (MAX_MODEM_BUF - 1);
count = len;
if (count > MAX_MODEM_BUF - fp) {
count = MAX_MODEM_BUF - fp;
memcpy(cs->hw.elsa.transbuf + fp, msg, count);
cs->hw.elsa.transcnt += count;
msg += count;
count = len - count;
fp = 0;
}
memcpy(cs->hw.elsa.transbuf + fp, msg, count);
cs->hw.elsa.transcnt += count;
if (cs->hw.elsa.transcnt &&
!(cs->hw.elsa.IER & UART_IER_THRI)) {
cs->hw.elsa.IER |= UART_IER_THRI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER);
}
}
static void
modem_set_init(struct IsdnCardState *cs) {
int timeout;
#define RCV_DELAY 20
modem_write_cmd(cs, MInit_1, strlen(MInit_1));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_2, strlen(MInit_2));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_3, strlen(MInit_3));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_4, strlen(MInit_4));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_5, strlen(MInit_5));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_6, strlen(MInit_6));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_7, strlen(MInit_7));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
}
static void
modem_set_dial(struct IsdnCardState *cs, int outgoing) {
int timeout;
#define RCV_DELAY 20
modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
if (outgoing)
modem_write_cmd(cs, MInit_dialout, strlen(MInit_dialout));
else
modem_write_cmd(cs, MInit_dialin, strlen(MInit_dialin));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
}
static void
modem_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
struct sk_buff *skb = arg;
u_long flags;
if (pr == (PH_DATA | REQUEST)) {
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->hw.hscx.count = 0;
write_modem(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
} else if (pr == (PH_ACTIVATE | REQUEST)) {
test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
set_arcofi(bcs->cs, st->l1.bc);
mstartup(bcs->cs);
modem_set_dial(bcs->cs, test_bit(FLG_ORIG, &st->l2.flag));
bcs->cs->hw.elsa.MFlag = 2;
} else if (pr == (PH_DEACTIVATE | REQUEST)) {
test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
bcs->cs->dc.isac.arcofi_bc = st->l1.bc;
arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0);
wait_event_interruptible(bcs->cs->dc.isac.arcofi_wait,
bcs->cs->dc.isac.arcofi_state == ARCOFI_NOP);
bcs->cs->hw.elsa.MFlag = 1;
} else {
printk(KERN_WARNING "ElsaSer: unknown pr %x\n", pr);
}
}
static int
setstack_elsa(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
switch (st->l1.mode) {
case L1_MODE_HDLC:
case L1_MODE_TRANS:
if (open_hscxstate(st->l1.hardware, bcs))
return (-1);
st->l2.l2l1 = hscx_l2l1;
break;
case L1_MODE_MODEM:
bcs->mode = L1_MODE_MODEM;
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
bcs->hw.hscx.rcvbuf = bcs->cs->hw.elsa.rcvbuf;
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->hw.hscx.rcvidx = 0;
bcs->tx_cnt = 0;
bcs->cs->hw.elsa.bcs = bcs;
st->l2.l2l1 = modem_l2l1;
break;
}
st->l1.bcs = bcs;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
static void
init_modem(struct IsdnCardState *cs) {
cs->bcs[0].BC_SetStack = setstack_elsa;
cs->bcs[1].BC_SetStack = setstack_elsa;
cs->bcs[0].BC_Close = close_elsastate;
cs->bcs[1].BC_Close = close_elsastate;
if (!(cs->hw.elsa.rcvbuf = kmalloc(MAX_MODEM_BUF,
GFP_ATOMIC))) {
printk(KERN_WARNING
"Elsa: No modem mem hw.elsa.rcvbuf\n");
return;
}
if (!(cs->hw.elsa.transbuf = kmalloc(MAX_MODEM_BUF,
GFP_ATOMIC))) {
printk(KERN_WARNING
"Elsa: No modem mem hw.elsa.transbuf\n");
kfree(cs->hw.elsa.rcvbuf);
cs->hw.elsa.rcvbuf = NULL;
return;
}
if (mstartup(cs)) {
printk(KERN_WARNING "Elsa: problem startup modem\n");
}
modem_set_init(cs);
}
static void
release_modem(struct IsdnCardState *cs) {
cs->hw.elsa.MFlag = 0;
if (cs->hw.elsa.transbuf) {
if (cs->hw.elsa.rcvbuf) {
mshutdown(cs);
kfree(cs->hw.elsa.rcvbuf);
cs->hw.elsa.rcvbuf = NULL;
}
kfree(cs->hw.elsa.transbuf);
cs->hw.elsa.transbuf = NULL;
}
}

View file

@ -1,420 +0,0 @@
/* enternow_pci.c,v 0.99 2001/10/02
*
* enternow_pci.c Card-specific routines for
* Formula-n enter:now ISDN PCI ab
* Gerdes AG Power ISDN PCI
* Woerltronic SA 16 PCI
* (based on HiSax driver by Karsten Keil)
*
* Author Christoph Ersfeld <info@formula-n.de>
* Formula-n Europe AG (www.formula-n.com)
* previously Gerdes AG
*
*
* This file is (c) under GNU PUBLIC LICENSE
*
* Notes:
* This driver interfaces to netjet.c which performs B-channel
* processing.
*
* Version 0.99 is the first release of this driver and there are
* certainly a few bugs.
* It isn't testet on linux 2.4 yet, so consider this code to be
* beta.
*
* Please don't report me any malfunction without sending
* (compressed) debug-logs.
* It would be nearly impossible to retrace it.
*
* Log D-channel-processing as follows:
*
* 1. Load hisax with card-specific parameters, this example ist for
* Formula-n enter:now ISDN PCI and compatible
* (f.e. Gerdes Power ISDN PCI)
*
* modprobe hisax type=41 protocol=2 id=gerdes
*
* if you chose an other value for id, you need to modify the
* code below, too.
*
* 2. set debug-level
*
* hisaxctrl gerdes 1 0x3ff
* hisaxctrl gerdes 11 0x4f
* cat /dev/isdnctrl >> ~/log &
*
* Please take also a look into /var/log/messages if there is
* anything importand concerning HISAX.
*
*
* Credits:
* Programming the driver for Formula-n enter:now ISDN PCI and
* necessary the driver for the used Amd 7930 D-channel-controller
* was spnsored by Formula-n Europe AG.
* Thanks to Karsten Keil and Petr Novak, who gave me support in
* Hisax-specific questions.
* I want so say special thanks to Carl-Friedrich Braun, who had to
* answer a lot of questions about generally ISDN and about handling
* of the Amd-Chip.
*
*/
#include "hisax.h"
#include "isac.h"
#include "isdnl1.h"
#include "amd7930_fn.h"
#include <linux/interrupt.h>
#include <linux/ppp_defs.h>
#include <linux/pci.h>
#include <linux/init.h>
#include "netjet.h"
static const char *enternow_pci_rev = "$Revision: 1.1.4.5 $";
/* for PowerISDN PCI */
#define TJ_AMD_IRQ 0x20
#define TJ_LED1 0x40
#define TJ_LED2 0x80
/* The window to [the] AMD [chip]...
* From address hw.njet.base + TJ_AMD_PORT onwards, the AMD
* maps [consecutive/multiple] 8 bits into the TigerJet I/O space
* -> 0x01 of the AMD at hw.njet.base + 0C4 */
#define TJ_AMD_PORT 0xC0
/* *************************** I/O-Interface functions ************************************* */
/* cs->readisac, macro rByteAMD */
static unsigned char
ReadByteAmd7930(struct IsdnCardState *cs, unsigned char offset)
{
/* direct register */
if (offset < 8)
return (inb(cs->hw.njet.isac + 4 * offset));
/* indirect register */
else {
outb(offset, cs->hw.njet.isac + 4 * AMD_CR);
return (inb(cs->hw.njet.isac + 4 * AMD_DR));
}
}
/* cs->writeisac, macro wByteAMD */
static void
WriteByteAmd7930(struct IsdnCardState *cs, unsigned char offset, unsigned char value)
{
/* direct register */
if (offset < 8)
outb(value, cs->hw.njet.isac + 4 * offset);
/* indirect register */
else {
outb(offset, cs->hw.njet.isac + 4 * AMD_CR);
outb(value, cs->hw.njet.isac + 4 * AMD_DR);
}
}
static void
enpci_setIrqMask(struct IsdnCardState *cs, unsigned char val) {
if (!val)
outb(0x00, cs->hw.njet.base + NETJET_IRQMASK1);
else
outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
}
static unsigned char dummyrr(struct IsdnCardState *cs, int chan, unsigned char off)
{
return (5);
}
static void dummywr(struct IsdnCardState *cs, int chan, unsigned char off, unsigned char value)
{
}
/* ******************************************************************************** */
static void
reset_enpci(struct IsdnCardState *cs)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: reset");
/* Reset on, (also for AMD) */
cs->hw.njet.ctrl_reg = 0x07;
outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
mdelay(20);
/* Reset off */
cs->hw.njet.ctrl_reg = 0x30;
outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
/* 20ms delay */
mdelay(20);
cs->hw.njet.auxd = 0; // LED-status
cs->hw.njet.dmactrl = 0;
outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
outb(cs->hw.njet.auxd, cs->hw.njet.auxa); // LED off
}
static int
enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
unsigned char *chan;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_enpci(cs);
Amd7930_init(cs);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case CARD_RELEASE:
release_io_netjet(cs);
break;
case CARD_INIT:
reset_enpci(cs);
inittiger(cs);
/* irq must be on here */
Amd7930_init(cs);
break;
case CARD_TEST:
break;
case MDL_ASSIGN:
/* TEI assigned, LED1 on */
cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
break;
case MDL_REMOVE:
/* TEI removed, LEDs off */
cs->hw.njet.auxd = 0;
outb(0x00, cs->hw.njet.base + NETJET_AUXDATA);
break;
case MDL_BC_ASSIGN:
/* activate B-channel */
chan = (unsigned char *)arg;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan);
cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN");
/* at least one b-channel in use, LED 2 on */
cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
break;
case MDL_BC_RELEASE:
/* deactivate B-channel */
chan = (unsigned char *)arg;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan);
cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE");
/* no b-channel active -> LED2 off */
if (!(cs->dc.amd7930.lmr1 & 3)) {
cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
}
break;
default:
break;
}
return (0);
}
static irqreturn_t
enpci_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
unsigned char s0val, s1val, ir;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
s1val = inb(cs->hw.njet.base + NETJET_IRQSTAT1);
/* AMD threw an interrupt */
if (!(s1val & TJ_AMD_IRQ)) {
/* read and clear interrupt-register */
ir = ReadByteAmd7930(cs, 0x00);
Amd7930_interrupt(cs, ir);
s1val = 1;
} else
s1val = 0;
s0val = inb(cs->hw.njet.base + NETJET_IRQSTAT0);
if ((s0val | s1val) == 0) { // shared IRQ
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
if (s0val)
outb(s0val, cs->hw.njet.base + NETJET_IRQSTAT0);
/* DMA-Interrupt: B-channel-stuff */
/* set bits in sval to indicate which page is free */
if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
/* the 2nd write page is free */
s0val = 0x08;
else /* the 1st write page is free */
s0val = 0x04;
if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
/* the 2nd read page is free */
s0val = s0val | 0x02;
else /* the 1st read page is free */
s0val = s0val | 0x01;
if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */
{
if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
cs->hw.njet.irqstat0 = s0val;
if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
/* we have a read dma int */
read_tiger(cs);
if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
(cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
/* we have a write dma int */
write_tiger(cs);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
}
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static int en_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs)
{
if (pci_enable_device(dev_netjet))
return (0);
cs->irq = dev_netjet->irq;
if (!cs->irq) {
printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
return (0);
}
cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
if (!cs->hw.njet.base) {
printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
return (0);
}
/* checks Sub-Vendor ID because system crashes with Traverse-Card */
if ((dev_netjet->subsystem_vendor != 0x55) ||
(dev_netjet->subsystem_device != 0x02)) {
printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
return (0);
}
return (1);
}
static void en_cs_init(struct IsdnCard *card, struct IsdnCardState *cs)
{
cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
/* Reset an */
cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff
outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
/* 20 ms Pause */
mdelay(20);
cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */
outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
mdelay(10);
cs->hw.njet.auxd = 0x00; // war 0xc0
cs->hw.njet.dmactrl = 0;
outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
outb(cs->hw.njet.auxd, cs->hw.njet.auxa);
}
static int en_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs)
{
const int bytecnt = 256;
printk(KERN_INFO
"enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
cs->hw.njet.base, cs->irq);
if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) {
printk(KERN_WARNING
"HiSax: enter:now config port %lx-%lx already in use\n",
cs->hw.njet.base,
cs->hw.njet.base + bytecnt);
return (0);
}
setup_Amd7930(cs);
cs->hw.njet.last_is0 = 0;
/* macro rByteAMD */
cs->readisac = &ReadByteAmd7930;
/* macro wByteAMD */
cs->writeisac = &WriteByteAmd7930;
cs->dc.amd7930.setIrqMask = &enpci_setIrqMask;
cs->BC_Read_Reg = &dummyrr;
cs->BC_Write_Reg = &dummywr;
cs->BC_Send_Data = &netjet_fill_dma;
cs->cardmsg = &enpci_card_msg;
cs->irq_func = &enpci_interrupt;
cs->irq_flags |= IRQF_SHARED;
return (1);
}
static struct pci_dev *dev_netjet = NULL;
/* called by config.c */
int setup_enternow_pci(struct IsdnCard *card)
{
int ret;
struct IsdnCardState *cs = card->cs;
char tmp[64];
#ifdef __BIG_ENDIAN
#error "not running on big endian machines now"
#endif
strcpy(tmp, enternow_pci_rev);
printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_ENTERNOW)
return (0);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
for (;;)
{
if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
ret = en_pci_probe(dev_netjet, cs);
if (!ret)
return (0);
} else {
printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
return (0);
}
en_cs_init(card, cs);
break;
}
return en_cs_init_rest(card, cs);
}

View file

@ -1,161 +0,0 @@
/* $Id: fsm.c,v 1.14.6.4 2001/09/23 22:24:47 kai Exp $
*
* Finite state machine
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
* by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include "hisax.h"
#define FSM_TIMER_DEBUG 0
int
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)
return -ENOMEM;
for (i = 0; i < fncount; i++)
if ((fnlist[i].state >= fsm->state_count) || (fnlist[i].event >= fsm->event_count)) {
printk(KERN_ERR "FsmNew Error line %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;
}
void
FsmFree(struct Fsm *fsm)
{
kfree((void *) fsm->jumpmatrix);
}
int
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 "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 routine",
fi->fsm->strState[fi->state],
fi->fsm->strEvent[event]);
return (!0);
}
}
void
FsmChangeState(struct FsmInst *fi, int newstate)
{
fi->state = newstate;
if (fi->debug)
fi->printdebug(fi, "ChangeState %s",
fi->fsm->strState[newstate]);
}
static void
FsmExpireTimer(struct timer_list *t)
{
struct FsmTimer *ft = from_timer(ft, t, tl);
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
#endif
FsmEvent(ft->fi, ft->event, ft->arg);
}
void
FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
{
ft->fi = fi;
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
#endif
timer_setup(&ft->tl, FsmExpireTimer, 0);
}
void
FsmDelTimer(struct FsmTimer *ft, int where)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
#endif
del_timer(&ft->tl);
}
int
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, "FsmAddTimer %lx %d %d",
(long) ft, millisec, where);
#endif
if (timer_pending(&ft->tl)) {
printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
return -1;
}
ft->event = event;
ft->arg = arg;
ft->tl.expires = jiffies + (millisec * HZ) / 1000;
add_timer(&ft->tl);
return 0;
}
void
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, "FsmRestartTimer %lx %d %d",
(long) ft, millisec, where);
#endif
if (timer_pending(&ft->tl))
del_timer(&ft->tl);
ft->event = event;
ft->arg = arg;
ft->tl.expires = jiffies + (millisec * HZ) / 1000;
add_timer(&ft->tl);
}

View file

@ -1,61 +0,0 @@
/* $Id: fsm.h,v 1.3.2.2 2001/09/23 22:24:47 kai Exp $
*
* Finite state machine
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
* by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef __FSM_H__
#define __FSM_H__
#include <linux/timer.h>
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;
};
int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
void FsmFree(struct Fsm *fsm);
int FsmEvent(struct FsmInst *fi, int event, void *arg);
void FsmChangeState(struct FsmInst *fi, int newstate);
void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
int FsmAddTimer(struct FsmTimer *ft, int millisec, int event,
void *arg, int where);
void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event,
void *arg, int where);
void FsmDelTimer(struct FsmTimer *ft, int where);
#endif

View file

@ -1,691 +0,0 @@
/* $Id: gazel.c,v 2.19.2.4 2004/01/14 16:04:48 keil Exp $
*
* low level stuff for Gazel isdn cards
*
* Author BeWan Systems
* based on source code from Karsten Keil
* Copyright by BeWan Systems
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
#include "ipac.h"
#include <linux/pci.h>
static const char *gazel_revision = "$Revision: 2.19.2.4 $";
#define R647 1
#define R685 2
#define R753 3
#define R742 4
#define PLX_CNTRL 0x50 /* registre de controle PLX */
#define RESET_GAZEL 0x4
#define RESET_9050 0x40000000
#define PLX_INCSR 0x4C /* registre d'IT du 9050 */
#define INT_ISAC_EN 0x8 /* 1 = enable IT isac */
#define INT_ISAC 0x20 /* 1 = IT isac en cours */
#define INT_HSCX_EN 0x1 /* 1 = enable IT hscx */
#define INT_HSCX 0x4 /* 1 = IT hscx en cours */
#define INT_PCI_EN 0x40 /* 1 = enable IT PCI */
#define INT_IPAC_EN 0x3 /* enable IT ipac */
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
static inline u_char
readreg(unsigned int adr, u_short off)
{
return bytein(adr + off);
}
static inline void
writereg(unsigned int adr, u_short off, u_char data)
{
byteout(adr + off, data);
}
static inline void
read_fifo(unsigned int adr, u_char *data, int size)
{
insb(adr, data, size);
}
static void
write_fifo(unsigned int adr, u_char *data, int size)
{
outsb(adr, data, size);
}
static inline u_char
readreg_ipac(unsigned int adr, u_short off)
{
register u_char ret;
byteout(adr, off);
ret = bytein(adr + 4);
return ret;
}
static inline void
writereg_ipac(unsigned int adr, u_short off, u_char data)
{
byteout(adr, off);
byteout(adr + 4, data);
}
static inline void
read_fifo_ipac(unsigned int adr, u_short off, u_char *data, int size)
{
byteout(adr, off);
insb(adr + 4, data, size);
}
static void
write_fifo_ipac(unsigned int adr, u_short off, u_char *data, int size)
{
byteout(adr, off);
outsb(adr + 4, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
u_short off2 = offset;
switch (cs->subtyp) {
case R647:
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
/* fall through */
case R685:
return (readreg(cs->hw.gazel.isac, off2));
case R753:
case R742:
return (readreg_ipac(cs->hw.gazel.ipac, 0x80 + off2));
}
return 0;
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
u_short off2 = offset;
switch (cs->subtyp) {
case R647:
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
/* fall through */
case R685:
writereg(cs->hw.gazel.isac, off2, value);
break;
case R753:
case R742:
writereg_ipac(cs->hw.gazel.ipac, 0x80 + off2, value);
break;
}
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
switch (cs->subtyp) {
case R647:
case R685:
read_fifo(cs->hw.gazel.isacfifo, data, size);
break;
case R753:
case R742:
read_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
break;
}
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
switch (cs->subtyp) {
case R647:
case R685:
write_fifo(cs->hw.gazel.isacfifo, data, size);
break;
case R753:
case R742:
write_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
break;
}
}
static void
ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
{
switch (cs->subtyp) {
case R647:
case R685:
read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
break;
case R753:
case R742:
read_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
break;
}
}
static void
WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
{
switch (cs->subtyp) {
case R647:
case R685:
write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
break;
case R753:
case R742:
write_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
break;
}
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
u_short off2 = offset;
switch (cs->subtyp) {
case R647:
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
/* fall through */
case R685:
return (readreg(cs->hw.gazel.hscx[hscx], off2));
case R753:
case R742:
return (readreg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2));
}
return 0;
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
u_short off2 = offset;
switch (cs->subtyp) {
case R647:
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
/* fall through */
case R685:
writereg(cs->hw.gazel.hscx[hscx], off2, value);
break;
case R753:
case R742:
writereg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2, value);
break;
}
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
gazel_interrupt(int intno, void *dev_id)
{
#define MAXCOUNT 5
struct IsdnCardState *cs = dev_id;
u_char valisac, valhscx;
int count = 0;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
do {
valhscx = ReadHSCX(cs, 1, HSCX_ISTA);
if (valhscx)
hscx_int_main(cs, valhscx);
valisac = ReadISAC(cs, ISAC_ISTA);
if (valisac)
isac_interrupt(cs, valisac);
count++;
} while ((valhscx || valisac) && (count < MAXCOUNT));
WriteHSCX(cs, 0, HSCX_MASK, 0xFF);
WriteHSCX(cs, 1, HSCX_MASK, 0xFF);
WriteISAC(cs, ISAC_MASK, 0xFF);
WriteISAC(cs, ISAC_MASK, 0x0);
WriteHSCX(cs, 0, HSCX_MASK, 0x0);
WriteHSCX(cs, 1, HSCX_MASK, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static irqreturn_t
gazel_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val;
int count = 0;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
ista = ReadISAC(cs, IPAC_ISTA - 0x80);
do {
if (ista & 0x0f) {
val = ReadHSCX(cs, 1, HSCX_ISTA);
if (ista & 0x01)
val |= 0x01;
if (ista & 0x04)
val |= 0x02;
if (ista & 0x08)
val |= 0x04;
if (val) {
hscx_int_main(cs, val);
}
}
if (ista & 0x20) {
val = 0xfe & ReadISAC(cs, ISAC_ISTA);
if (val) {
isac_interrupt(cs, val);
}
}
if (ista & 0x10) {
val = 0x01;
isac_interrupt(cs, val);
}
ista = ReadISAC(cs, IPAC_ISTA - 0x80);
count++;
}
while ((ista & 0x3f) && (count < MAXCOUNT));
WriteISAC(cs, IPAC_MASK - 0x80, 0xFF);
WriteISAC(cs, IPAC_MASK - 0x80, 0xC0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_gazel(struct IsdnCardState *cs)
{
unsigned int i;
switch (cs->subtyp) {
case R647:
for (i = 0x0000; i < 0xC000; i += 0x1000)
release_region(i + cs->hw.gazel.hscx[0], 16);
release_region(0xC000 + cs->hw.gazel.hscx[0], 1);
break;
case R685:
release_region(cs->hw.gazel.hscx[0], 0x100);
release_region(cs->hw.gazel.cfg_reg, 0x80);
break;
case R753:
release_region(cs->hw.gazel.ipac, 0x8);
release_region(cs->hw.gazel.cfg_reg, 0x80);
break;
case R742:
release_region(cs->hw.gazel.ipac, 8);
break;
}
}
static int
reset_gazel(struct IsdnCardState *cs)
{
unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg;
switch (cs->subtyp) {
case R647:
writereg(addr, 0, 0);
HZDELAY(10);
writereg(addr, 0, 1);
HZDELAY(2);
break;
case R685:
plxcntrl = inl(addr + PLX_CNTRL);
plxcntrl |= (RESET_9050 + RESET_GAZEL);
outl(plxcntrl, addr + PLX_CNTRL);
plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
HZDELAY(4);
outl(plxcntrl, addr + PLX_CNTRL);
HZDELAY(10);
outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR);
break;
case R753:
plxcntrl = inl(addr + PLX_CNTRL);
plxcntrl |= (RESET_9050 + RESET_GAZEL);
outl(plxcntrl, addr + PLX_CNTRL);
plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
HZDELAY(4);
outl(plxcntrl, addr + PLX_CNTRL);
HZDELAY(10);
WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR);
WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
break;
case R742:
WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
HZDELAY(4);
WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
break;
}
return (0);
}
static int
Gazel_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_gazel(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_gazel(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
inithscxisac(cs, 1);
if ((cs->subtyp == R647) || (cs->subtyp == R685)) {
int i;
for (i = 0; i < (2 + MAX_WAITING_CALLS); i++) {
cs->bcs[i].hw.hscx.tsaxr0 = 0x1f;
cs->bcs[i].hw.hscx.tsaxr1 = 0x23;
}
}
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int
reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs)
{
unsigned int i, j, base = 0, adr = 0, len = 0;
switch (cs->subtyp) {
case R647:
base = cs->hw.gazel.hscx[0];
if (!request_region(adr = (0xC000 + base), len = 1, "gazel"))
goto error;
for (i = 0x0000; i < 0xC000; i += 0x1000) {
if (!request_region(adr = (i + base), len = 16, "gazel"))
goto error;
}
if (i != 0xC000) {
for (j = 0; j < i; j += 0x1000)
release_region(j + base, 16);
release_region(0xC000 + base, 1);
goto error;
}
break;
case R685:
if (!request_region(adr = cs->hw.gazel.hscx[0], len = 0x100, "gazel"))
goto error;
if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) {
release_region(cs->hw.gazel.hscx[0], 0x100);
goto error;
}
break;
case R753:
if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel"))
goto error;
if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) {
release_region(cs->hw.gazel.ipac, 8);
goto error;
}
break;
case R742:
if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel"))
goto error;
break;
}
return 0;
error:
printk(KERN_WARNING "Gazel: io ports 0x%x-0x%x already in use\n",
adr, adr + len);
return 1;
}
static int setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
{
printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n");
// we got an irq parameter, assume it is an ISA card
// R742 decodes address even in not started...
// R647 returns FF if not present or not started
// eventually needs improvment
if (readreg_ipac(card->para[1], IPAC_ID) == 1)
cs->subtyp = R742;
else
cs->subtyp = R647;
setup_isac(cs);
cs->hw.gazel.cfg_reg = card->para[1] + 0xC000;
cs->hw.gazel.ipac = card->para[1];
cs->hw.gazel.isac = card->para[1] + 0x8000;
cs->hw.gazel.hscx[0] = card->para[1];
cs->hw.gazel.hscx[1] = card->para[1] + 0x4000;
cs->irq = card->para[0];
cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
switch (cs->subtyp) {
case R647:
printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n");
cs->dc.isac.adf2 = 0x87;
printk(KERN_INFO
"Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
printk(KERN_INFO
"Gazel: hscx A:0x%X hscx B:0x%X\n",
cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
break;
case R742:
printk(KERN_INFO "Gazel: Card ISA R742 found\n");
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
printk(KERN_INFO
"Gazel: config irq:%d ipac:0x%X\n",
cs->irq, cs->hw.gazel.ipac);
break;
}
return (0);
}
#ifdef CONFIG_PCI
static struct pci_dev *dev_tel = NULL;
static int setup_gazelpci(struct IsdnCardState *cs)
{
u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0;
u_char pci_irq = 0, found;
u_int nbseek, seekcard;
printk(KERN_WARNING "Gazel: PCI card automatic recognition\n");
found = 0;
seekcard = PCI_DEVICE_ID_PLX_R685;
for (nbseek = 0; nbseek < 4; nbseek++) {
if ((dev_tel = hisax_find_pci_device(PCI_VENDOR_ID_PLX,
seekcard, dev_tel))) {
if (pci_enable_device(dev_tel))
return 1;
pci_irq = dev_tel->irq;
pci_ioaddr0 = pci_resource_start(dev_tel, 1);
pci_ioaddr1 = pci_resource_start(dev_tel, 2);
found = 1;
}
if (found)
break;
else {
switch (seekcard) {
case PCI_DEVICE_ID_PLX_R685:
seekcard = PCI_DEVICE_ID_PLX_R753;
break;
case PCI_DEVICE_ID_PLX_R753:
seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO;
break;
case PCI_DEVICE_ID_PLX_DJINN_ITOO:
seekcard = PCI_DEVICE_ID_PLX_OLITEC;
break;
}
}
}
if (!found) {
printk(KERN_WARNING "Gazel: No PCI card found\n");
return (1);
}
if (!pci_irq) {
printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n");
return 1;
}
cs->hw.gazel.pciaddr[0] = pci_ioaddr0;
cs->hw.gazel.pciaddr[1] = pci_ioaddr1;
setup_isac(cs);
pci_ioaddr1 &= 0xfffe;
cs->hw.gazel.cfg_reg = pci_ioaddr0 & 0xfffe;
cs->hw.gazel.ipac = pci_ioaddr1;
cs->hw.gazel.isac = pci_ioaddr1 + 0x80;
cs->hw.gazel.hscx[0] = pci_ioaddr1;
cs->hw.gazel.hscx[1] = pci_ioaddr1 + 0x40;
cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
cs->irq = pci_irq;
cs->irq_flags |= IRQF_SHARED;
switch (seekcard) {
case PCI_DEVICE_ID_PLX_R685:
printk(KERN_INFO "Gazel: Card PCI R685 found\n");
cs->subtyp = R685;
cs->dc.isac.adf2 = 0x87;
printk(KERN_INFO
"Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
printk(KERN_INFO
"Gazel: hscx A:0x%X hscx B:0x%X\n",
cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
break;
case PCI_DEVICE_ID_PLX_R753:
case PCI_DEVICE_ID_PLX_DJINN_ITOO:
case PCI_DEVICE_ID_PLX_OLITEC:
printk(KERN_INFO "Gazel: Card PCI R753 found\n");
cs->subtyp = R753;
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
printk(KERN_INFO
"Gazel: config irq:%d ipac:0x%X cfg:0x%X\n",
cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg);
break;
}
return (0);
}
#endif /* CONFIG_PCI */
int setup_gazel(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
u_char val;
strcpy(tmp, gazel_revision);
printk(KERN_INFO "Gazel: Driver Revision %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_GAZEL)
return (0);
if (card->para[0]) {
if (setup_gazelisa(card, cs))
return (0);
} else {
#ifdef CONFIG_PCI
if (setup_gazelpci(cs))
return (0);
#else
printk(KERN_WARNING "Gazel: Card PCI requested and NO_PCI_BIOS, unable to config\n");
return (0);
#endif /* CONFIG_PCI */
}
if (reserve_regions(card, cs)) {
return (0);
}
if (reset_gazel(cs)) {
printk(KERN_WARNING "Gazel: wrong IRQ\n");
release_io_gazel(cs);
return (0);
}
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Gazel_card_msg;
switch (cs->subtyp) {
case R647:
case R685:
cs->irq_func = &gazel_interrupt;
ISACVersion(cs, "Gazel:");
if (HscxVersion(cs, "Gazel:")) {
printk(KERN_WARNING
"Gazel: wrong HSCX versions check IO address\n");
release_io_gazel(cs);
return (0);
}
break;
case R742:
case R753:
cs->irq_func = &gazel_interrupt_ipac;
val = ReadISAC(cs, IPAC_ID - 0x80);
printk(KERN_INFO "Gazel: IPAC version %x\n", val);
break;
}
return (1);
}

File diff suppressed because it is too large Load diff

View file

@ -1,89 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************/
/* $Id: hfc4s8s_l1.h,v 1.1 2005/02/02 17:28:55 martinb1 Exp $ */
/* */
/* This file is a minimal required extraction of hfc48scu.h */
/* (Genero 3.2, HFC XML 1.7a for HFC-E1, HFC-4S and HFC-8S) */
/* */
/* To get this complete register description contact */
/* Cologne Chip AG : */
/* Internet: http://www.colognechip.com/ */
/* E-Mail: [email protected] */
/***************************************************************/
#ifndef _HFC4S8S_L1_H_
#define _HFC4S8S_L1_H_
/*
* include Genero generated HFC-4S/8S header file hfc48scu.h
* for complete register description. This will define _HFC48SCU_H_
* to prevent redefinitions
*/
// #include "hfc48scu.h"
#ifndef _HFC48SCU_H_
#define _HFC48SCU_H_
#ifndef PCI_VENDOR_ID_CCD
#define PCI_VENDOR_ID_CCD 0x1397
#endif
#define CHIP_ID_4S 0x0C
#define CHIP_ID_8S 0x08
#define PCI_DEVICE_ID_4S 0x08B4
#define PCI_DEVICE_ID_8S 0x16B8
#define R_IRQ_MISC 0x11
#define M_TI_IRQ 0x02
#define A_ST_RD_STA 0x30
#define A_ST_WR_STA 0x30
#define M_SET_G2_G3 0x80
#define A_ST_CTRL0 0x31
#define A_ST_CTRL2 0x33
#define A_ST_CLK_DLY 0x37
#define A_Z1 0x04
#define A_Z2 0x06
#define R_CIRM 0x00
#define M_SRES 0x08
#define R_CTRL 0x01
#define R_BRG_PCM_CFG 0x02
#define M_PCM_CLK 0x20
#define R_RAM_MISC 0x0C
#define M_FZ_MD 0x80
#define R_FIFO_MD 0x0D
#define A_INC_RES_FIFO 0x0E
#define R_FIFO 0x0F
#define A_F1 0x0C
#define A_F2 0x0D
#define R_IRQ_OVIEW 0x10
#define R_CHIP_ID 0x16
#define R_STATUS 0x1C
#define M_BUSY 0x01
#define M_MISC_IRQSTA 0x40
#define M_FR_IRQSTA 0x80
#define R_CHIP_RV 0x1F
#define R_IRQ_CTRL 0x13
#define M_FIFO_IRQ 0x01
#define M_GLOB_IRQ_EN 0x08
#define R_PCM_MD0 0x14
#define M_PCM_MD 0x01
#define A_FIFO_DATA0 0x80
#define R_TI_WD 0x1A
#define R_PWM1 0x39
#define R_PWM_MD 0x46
#define R_IRQ_FIFO_BL0 0xC8
#define A_CON_HDLC 0xFA
#define A_SUBCH_CFG 0xFB
#define A_IRQ_MSK 0xFF
#define R_SCI_MSK 0x12
#define R_ST_SEL 0x16
#define R_ST_SYNC 0x17
#define M_AUTO_SYNC 0x08
#define R_SCI 0x12
#define R_IRQMSK_MISC 0x11
#define M_TI_IRQMSK 0x02
#endif /* _HFC4S8S_L1_H_ */
#endif /* _HFC48SCU_H_ */

File diff suppressed because it is too large Load diff

View file

@ -1,128 +0,0 @@
/* $Id: hfc_2bds0.h,v 1.6.2.2 2004/01/12 22:52:26 keil Exp $
*
* specific defines for CCD's HFC 2BDS0
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define HFCD_CIRM 0x18
#define HFCD_CTMT 0x19
#define HFCD_INT_M1 0x1A
#define HFCD_INT_M2 0x1B
#define HFCD_INT_S1 0x1E
#define HFCD_STAT 0x1C
#define HFCD_STAT_DISB 0x1D
#define HFCD_STATES 0x30
#define HFCD_SCTRL 0x31
#define HFCD_TEST 0x32
#define HFCD_SQ 0x34
#define HFCD_CLKDEL 0x37
#define HFCD_MST_MODE 0x2E
#define HFCD_CONN 0x2F
#define HFCD_FIFO 0x80
#define HFCD_Z1 0x10
#define HFCD_Z2 0x18
#define HFCD_Z_LOW 0x00
#define HFCD_Z_HIGH 0x04
#define HFCD_F1_INC 0x12
#define HFCD_FIFO_IN 0x16
#define HFCD_F1 0x1a
#define HFCD_F2 0x1e
#define HFCD_F2_INC 0x22
#define HFCD_FIFO_OUT 0x26
#define HFCD_REC 0x01
#define HFCD_SEND 0x00
#define HFCB_FIFO 0x80
#define HFCB_Z1 0x00
#define HFCB_Z2 0x08
#define HFCB_Z_LOW 0x00
#define HFCB_Z_HIGH 0x04
#define HFCB_F1_INC 0x28
#define HFCB_FIFO_IN 0x2c
#define HFCB_F1 0x30
#define HFCB_F2 0x34
#define HFCB_F2_INC 0x38
#define HFCB_FIFO_OUT 0x3c
#define HFCB_REC 0x01
#define HFCB_SEND 0x00
#define HFCB_B1 0x00
#define HFCB_B2 0x02
#define HFCB_CHANNEL(ch) (ch ? HFCB_B2 : HFCB_B1)
#define HFCD_STATUS 0
#define HFCD_DATA 1
#define HFCD_DATA_NODEB 2
/* Status (READ) */
#define HFCD_BUSY 0x01
#define HFCD_BUSY_NBUSY 0x04
#define HFCD_TIMER_ELAP 0x10
#define HFCD_STATINT 0x20
#define HFCD_FRAMEINT 0x40
#define HFCD_ANYINT 0x80
/* CTMT (Write) */
#define HFCD_CLTIMER 0x80
#define HFCD_TIM25 0x00
#define HFCD_TIM50 0x08
#define HFCD_TIM400 0x10
#define HFCD_TIM800 0x18
#define HFCD_AUTO_TIMER 0x20
#define HFCD_TRANSB2 0x02
#define HFCD_TRANSB1 0x01
/* CIRM (Write) */
#define HFCD_RESET 0x08
#define HFCD_MEM8K 0x10
#define HFCD_INTA 0x01
#define HFCD_INTB 0x02
#define HFCD_INTC 0x03
#define HFCD_INTD 0x04
#define HFCD_INTE 0x05
#define HFCD_INTF 0x06
/* INT_M1;INT_S1 */
#define HFCD_INTS_B1TRANS 0x01
#define HFCD_INTS_B2TRANS 0x02
#define HFCD_INTS_DTRANS 0x04
#define HFCD_INTS_B1REC 0x08
#define HFCD_INTS_B2REC 0x10
#define HFCD_INTS_DREC 0x20
#define HFCD_INTS_L1STATE 0x40
#define HFCD_INTS_TIMER 0x80
/* INT_M2 */
#define HFCD_IRQ_ENABLE 0x08
/* STATES */
#define HFCD_LOAD_STATE 0x10
#define HFCD_ACTIVATE 0x20
#define HFCD_DO_ACTION 0x40
/* HFCD_MST_MODE */
#define HFCD_MASTER 0x01
/* HFCD_SCTRL */
#define SCTRL_B1_ENA 0x01
#define SCTRL_B2_ENA 0x02
#define SCTRL_LOW_PRIO 0x08
#define SCTRL_SQ_ENA 0x10
#define SCTRL_TEST 0x20
#define SCTRL_NONE_CAP 0x40
#define SCTRL_PWR_DOWN 0x80
/* HFCD_TEST */
#define HFCD_AUTO_AWAKE 0x01
extern void main_irq_2bds0(struct BCState *bcs);
extern void init2bds0(struct IsdnCardState *cs);
extern void release2bds0(struct IsdnCardState *cs);
extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val);
extern void set_cs_func(struct IsdnCardState *cs);

View file

@ -1,591 +0,0 @@
/* $Id: hfc_2bs0.c,v 1.20.2.6 2004/02/11 13:21:33 keil Exp $
*
* specific routines for CCD's HFC 2BS0
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "hfc_2bs0.h"
#include "isac.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
static inline int
WaitForBusy(struct IsdnCardState *cs)
{
int to = 130;
u_char val;
while (!(cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
val = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2 |
(cs->hw.hfc.cip & 3));
udelay(1);
to--;
}
if (!to) {
printk(KERN_WARNING "HiSax: %s timeout\n", __func__);
return (0);
} else
return (to);
}
static inline int
WaitNoBusy(struct IsdnCardState *cs)
{
int to = 125;
while ((cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
udelay(1);
to--;
}
if (!to) {
printk(KERN_WARNING "HiSax: waitforBusy timeout\n");
return (0);
} else
return (to);
}
static int
GetFreeFifoBytes(struct BCState *bcs)
{
int s;
if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2)
return (bcs->cs->hw.hfc.fifosize);
s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2];
if (s <= 0)
s += bcs->cs->hw.hfc.fifosize;
s = bcs->cs->hw.hfc.fifosize - s;
return (s);
}
static int
ReadZReg(struct BCState *bcs, u_char reg)
{
int val;
WaitNoBusy(bcs->cs);
val = 256 * bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH);
WaitNoBusy(bcs->cs);
val += bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW);
return (val);
}
static void
hfc_clear_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int idx, cnt;
int rcnt, z1, z2;
u_char cip, f1, f2;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hfc_clear_fifo");
cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
WaitForBusy(cs);
}
WaitNoBusy(cs);
f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
WaitNoBusy(cs);
f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
cnt = 32;
while (((f1 != f2) || (z1 != z2)) && cnt--) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc clear %d f1(%d) f2(%d)",
bcs->channel, f1, f2);
rcnt = z1 - z2;
if (rcnt < 0)
rcnt += cs->hw.hfc.fifosize;
if (rcnt)
rcnt++;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc clear %d z1(%x) z2(%x) cnt(%d)",
bcs->channel, z1, z2, rcnt);
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
idx = 0;
while ((idx < rcnt) && WaitNoBusy(cs)) {
cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
idx++;
}
if (f1 != f2) {
WaitNoBusy(cs);
cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
HFC_CHANNEL(bcs->channel));
WaitForBusy(cs);
}
cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
WaitNoBusy(cs);
f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
WaitNoBusy(cs);
f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
}
return;
}
static struct sk_buff
*
hfc_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr;
struct sk_buff *skb;
struct IsdnCardState *cs = bcs->cs;
int idx;
int chksum;
u_char stat, cip;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hfc_empty_fifo");
idx = 0;
if (count > HSCX_BUFMAX + 3) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "hfc_empty_fifo: incoming packet too large");
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
while ((idx++ < count) && WaitNoBusy(cs))
cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
HFC_CHANNEL(bcs->channel));
WaitForBusy(cs);
return (NULL);
}
if ((count < 4) && (bcs->mode != L1_MODE_TRANS)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "hfc_empty_fifo: incoming packet too small");
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
while ((idx++ < count) && WaitNoBusy(cs))
cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
HFC_CHANNEL(bcs->channel));
WaitForBusy(cs);
#ifdef ERROR_STATISTIC
bcs->err_inv++;
#endif
return (NULL);
}
if (bcs->mode == L1_MODE_TRANS)
count -= 1;
else
count -= 3;
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "HFC: receive out of memory\n");
else {
ptr = skb_put(skb, count);
idx = 0;
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
while ((idx < count) && WaitNoBusy(cs)) {
*ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
idx++;
}
if (idx != count) {
debugl1(cs, "RFIFO BUSY error");
printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
dev_kfree_skb_any(skb);
if (bcs->mode != L1_MODE_TRANS) {
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
HFC_CHANNEL(bcs->channel));
WaitForBusy(cs);
}
return (NULL);
}
if (bcs->mode != L1_MODE_TRANS) {
WaitNoBusy(cs);
chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8);
WaitNoBusy(cs);
chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip);
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, cip);
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",
bcs->channel, chksum, stat);
if (stat) {
debugl1(cs, "FIFO CRC error");
dev_kfree_skb_any(skb);
skb = NULL;
#ifdef ERROR_STATISTIC
bcs->err_crc++;
#endif
}
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
HFC_CHANNEL(bcs->channel));
WaitForBusy(cs);
}
}
return (skb);
}
static void
hfc_fill_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int idx, fcnt;
int count;
int z1, z2;
u_char cip;
if (!bcs->tx_skb)
return;
if (bcs->tx_skb->len <= 0)
return;
cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel);
if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
WaitForBusy(cs);
}
WaitNoBusy(cs);
if (bcs->mode != L1_MODE_TRANS) {
bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel);
WaitNoBusy(cs);
bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel));
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
bcs->hw.hfc.send[bcs->hw.hfc.f1]);
fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
if (fcnt < 0)
fcnt += 32;
if (fcnt > 30) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_fill_fifo more as 30 frames");
return;
}
count = GetFreeFifoBytes(bcs);
}
else {
WaitForBusy(cs);
z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
count = z1 - z2;
if (count < 0)
count += cs->hw.hfc.fifosize;
} /* L1_MODE_TRANS */
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_fill_fifo %d count(%u/%d)",
bcs->channel, bcs->tx_skb->len,
count);
if (count < bcs->tx_skb->len) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_fill_fifo no fifo mem");
return;
}
cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel);
idx = 0;
while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs))
cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]);
if (idx != bcs->tx_skb->len) {
debugl1(cs, "FIFO Send BUSY error");
printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
} else {
count = bcs->tx_skb->len;
bcs->tx_cnt -= count;
if (PACKET_NOACK == bcs->tx_skb->pkt_type)
count = -1;
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
if (bcs->mode != L1_MODE_TRANS) {
WaitForBusy(cs);
WaitNoBusy(cs);
cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
}
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(count >= 0)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += count;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
return;
}
void
main_irq_hfc(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int z1, z2, rcnt;
u_char f1, f2, cip;
int receive, transmit, count = 5;
struct sk_buff *skb;
Begin:
count--;
cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
WaitForBusy(cs);
}
WaitNoBusy(cs);
receive = 0;
if (bcs->mode == L1_MODE_HDLC) {
f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
WaitNoBusy(cs);
f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
if (f1 != f2) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc rec %d f1(%d) f2(%d)",
bcs->channel, f1, f2);
receive = 1;
}
}
if (receive || (bcs->mode == L1_MODE_TRANS)) {
WaitForBusy(cs);
z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
rcnt = z1 - z2;
if (rcnt < 0)
rcnt += cs->hw.hfc.fifosize;
if ((bcs->mode == L1_MODE_HDLC) || (rcnt)) {
rcnt++;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
bcs->channel, z1, z2, rcnt);
/* sti(); */
if ((skb = hfc_empty_fifo(bcs, rcnt))) {
skb_queue_tail(&bcs->rqueue, skb);
schedule_event(bcs, B_RCVBUFREADY);
}
}
receive = 1;
}
if (bcs->tx_skb) {
transmit = 1;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
hfc_fill_fifo(bcs);
if (test_bit(BC_FLG_BUSY, &bcs->Flag))
transmit = 0;
} else {
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
transmit = 1;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
hfc_fill_fifo(bcs);
if (test_bit(BC_FLG_BUSY, &bcs->Flag))
transmit = 0;
} else {
transmit = 0;
schedule_event(bcs, B_XMTBUFREADY);
}
}
if ((receive || transmit) && count)
goto Begin;
return;
}
static void
mode_hfc(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HFC 2BS0 mode %d bchan %d/%d",
mode, bc, bcs->channel);
bcs->mode = mode;
bcs->channel = bc;
switch (mode) {
case (L1_MODE_NULL):
if (bc) {
cs->hw.hfc.ctmt &= ~1;
cs->hw.hfc.isac_spcr &= ~0x03;
}
else {
cs->hw.hfc.ctmt &= ~2;
cs->hw.hfc.isac_spcr &= ~0x0c;
}
break;
case (L1_MODE_TRANS):
cs->hw.hfc.ctmt &= ~(1 << bc); /* set HDLC mode */
cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
hfc_clear_fifo(bcs); /* complete fifo clear */
if (bc) {
cs->hw.hfc.ctmt |= 1;
cs->hw.hfc.isac_spcr &= ~0x03;
cs->hw.hfc.isac_spcr |= 0x02;
} else {
cs->hw.hfc.ctmt |= 2;
cs->hw.hfc.isac_spcr &= ~0x0c;
cs->hw.hfc.isac_spcr |= 0x08;
}
break;
case (L1_MODE_HDLC):
if (bc) {
cs->hw.hfc.ctmt &= ~1;
cs->hw.hfc.isac_spcr &= ~0x03;
cs->hw.hfc.isac_spcr |= 0x02;
} else {
cs->hw.hfc.ctmt &= ~2;
cs->hw.hfc.isac_spcr &= ~0x0c;
cs->hw.hfc.isac_spcr |= 0x08;
}
break;
}
cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr);
if (mode == L1_MODE_HDLC)
hfc_clear_fifo(bcs);
}
static void
hfc_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
struct sk_buff *skb = arg;
u_long flags;
switch (pr) {
case (PH_DATA | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
} else {
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->tx_skb = skb;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | REQUEST):
if (!bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (PH_ACTIVATE | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
mode_hfc(bcs, st->l1.mode, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
mode_hfc(bcs, 0, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
static void
close_hfcstate(struct BCState *bcs)
{
mode_hfc(bcs, 0, bcs->channel);
if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
}
static int
open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->tx_cnt = 0;
return (0);
}
static int
setstack_hfc(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
if (open_hfcstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
st->l2.l2l1 = hfc_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
static void
init_send(struct BCState *bcs)
{
int i;
bcs->hw.hfc.send = kmalloc_array(32, sizeof(unsigned int), GFP_ATOMIC);
if (!bcs->hw.hfc.send) {
printk(KERN_WARNING
"HiSax: No memory for hfc.send\n");
return;
}
for (i = 0; i < 32; i++)
bcs->hw.hfc.send[i] = 0x1fff;
}
void
inithfc(struct IsdnCardState *cs)
{
init_send(&cs->bcs[0]);
init_send(&cs->bcs[1]);
cs->BC_Send_Data = &hfc_fill_fifo;
cs->bcs[0].BC_SetStack = setstack_hfc;
cs->bcs[1].BC_SetStack = setstack_hfc;
cs->bcs[0].BC_Close = close_hfcstate;
cs->bcs[1].BC_Close = close_hfcstate;
mode_hfc(cs->bcs, 0, 0);
mode_hfc(cs->bcs + 1, 0, 0);
}
void
releasehfc(struct IsdnCardState *cs)
{
kfree(cs->bcs[0].hw.hfc.send);
cs->bcs[0].hw.hfc.send = NULL;
kfree(cs->bcs[1].hw.hfc.send);
cs->bcs[1].hw.hfc.send = NULL;
}

View file

@ -1,60 +0,0 @@
/* $Id: hfc_2bs0.h,v 1.5.2.2 2004/01/12 22:52:26 keil Exp $
*
* specific defines for CCD's HFC 2BS0
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define HFC_CTMT 0xe0
#define HFC_CIRM 0xc0
#define HFC_CIP 0x80
#define HFC_Z1 0x00
#define HFC_Z2 0x08
#define HFC_Z_LOW 0x00
#define HFC_Z_HIGH 0x04
#define HFC_F1_INC 0x28
#define HFC_FIFO_IN 0x2c
#define HFC_F1 0x30
#define HFC_F2 0x34
#define HFC_F2_INC 0x38
#define HFC_FIFO_OUT 0x3c
#define HFC_B1 0x00
#define HFC_B2 0x02
#define HFC_REC 0x01
#define HFC_SEND 0x00
#define HFC_CHANNEL(ch) (ch ? HFC_B2 : HFC_B1)
#define HFC_STATUS 0
#define HFC_DATA 1
#define HFC_DATA_NODEB 2
/* Status (READ) */
#define HFC_BUSY 0x01
#define HFC_TIMINT 0x02
#define HFC_EXTINT 0x04
/* CTMT (Write) */
#define HFC_CLTIMER 0x10
#define HFC_TIM50MS 0x08
#define HFC_TIMIRQE 0x04
#define HFC_TRANSB2 0x02
#define HFC_TRANSB1 0x01
/* CIRM (Write) */
#define HFC_RESET 0x08
#define HFC_MEM8K 0x10
#define HFC_INTA 0x01
#define HFC_INTB 0x02
#define HFC_INTC 0x03
#define HFC_INTD 0x04
#define HFC_INTE 0x05
#define HFC_INTF 0x06
extern void main_irq_hfc(struct BCState *bcs);
extern void inithfc(struct IsdnCardState *cs);
extern void releasehfc(struct IsdnCardState *cs);

File diff suppressed because it is too large Load diff

View file

@ -1,235 +0,0 @@
/* $Id: hfc_pci.h,v 1.10.2.2 2004/01/12 22:52:26 keil Exp $
*
* specific defines for CCD's HFC 2BDS0 PCI chips
*
* Author Werner Cornelius
* Copyright by Werner Cornelius <werner@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/*********************************************/
/* thresholds for transparent B-channel mode */
/* change mask and threshold simultaneously */
/*********************************************/
#define HFCPCI_BTRANS_THRESHOLD 128
#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
/* 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
typedef struct {
unsigned short z1; /* Z1 pointer 16 Bit */
unsigned short z2; /* Z2 pointer 16 Bit */
} z_type;
typedef struct {
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 */
z_type za[MAX_D_FRAMES + 1]; /* mask index with D_FREG_MASK for access */
u_char fill3[0x4000 - 0x2100]; /* align 16K */
} dfifo_type;
typedef struct {
z_type za[MAX_B_FRAMES + 1]; /* only range 0x0..0x1F allowed */
u_char f1, f2; /* f pointers */
u_char fill[0x2100 - 0x2082]; /* alignment */
} bzfifo_type;
typedef union {
struct {
dfifo_type d_tx; /* D-send channel */
dfifo_type d_rx; /* D-receive channel */
} d_chan;
struct {
u_char fill1[0x200];
u_char txdat_b1[B_FIFO_SIZE];
bzfifo_type txbz_b1;
bzfifo_type txbz_b2;
u_char txdat_b2[B_FIFO_SIZE];
u_char fill2[D_FIFO_SIZE];
u_char rxdat_b1[B_FIFO_SIZE];
bzfifo_type rxbz_b1;
bzfifo_type rxbz_b2;
u_char rxdat_b2[B_FIFO_SIZE];
} b_chans;
u_char fill[32768];
} fifo_area;
#define Write_hfc(a, b, c) (writeb(c, (a->hw.hfcpci.pci_io) + b))
#define Read_hfc(a, b) (readb((a->hw.hfcpci.pci_io) + b))
extern void main_irq_hcpci(struct BCState *bcs);
extern void releasehfcpci(struct IsdnCardState *cs);

File diff suppressed because it is too large Load diff

View file

@ -1,196 +0,0 @@
/* $Id: hfc_sx.h,v 1.2.6.1 2001/09/23 22:24:48 kai Exp $
*
* specific defines for CCD's HFC 2BDS0 S+,SP chips
*
* Author Werner Cornelius
* based on existing driver for CCD HFC PCI cards
* Copyright by Werner Cornelius <werner@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/*********************************************/
/* thresholds for transparent B-channel mode */
/* change mask and threshold simultaneously */
/*********************************************/
#define HFCSX_BTRANS_THRESHOLD 128
#define HFCSX_BTRANS_THRESMASK 0x00
/* GCI/IOM bus monitor registers */
#define HFCSX_C_I 0x02
#define HFCSX_TRxR 0x03
#define HFCSX_MON1_D 0x0A
#define HFCSX_MON2_D 0x0B
/* GCI/IOM bus timeslot registers */
#define HFCSX_B1_SSL 0x20
#define HFCSX_B2_SSL 0x21
#define HFCSX_AUX1_SSL 0x22
#define HFCSX_AUX2_SSL 0x23
#define HFCSX_B1_RSL 0x24
#define HFCSX_B2_RSL 0x25
#define HFCSX_AUX1_RSL 0x26
#define HFCSX_AUX2_RSL 0x27
/* GCI/IOM bus data registers */
#define HFCSX_B1_D 0x28
#define HFCSX_B2_D 0x29
#define HFCSX_AUX1_D 0x2A
#define HFCSX_AUX2_D 0x2B
/* GCI/IOM bus configuration registers */
#define HFCSX_MST_EMOD 0x2D
#define HFCSX_MST_MODE 0x2E
#define HFCSX_CONNECT 0x2F
/* Interrupt and status registers */
#define HFCSX_TRM 0x12
#define HFCSX_B_MODE 0x13
#define HFCSX_CHIP_ID 0x16
#define HFCSX_CIRM 0x18
#define HFCSX_CTMT 0x19
#define HFCSX_INT_M1 0x1A
#define HFCSX_INT_M2 0x1B
#define HFCSX_INT_S1 0x1E
#define HFCSX_INT_S2 0x1F
#define HFCSX_STATUS 0x1C
/* S/T section registers */
#define HFCSX_STATES 0x30
#define HFCSX_SCTRL 0x31
#define HFCSX_SCTRL_E 0x32
#define HFCSX_SCTRL_R 0x33
#define HFCSX_SQ 0x34
#define HFCSX_CLKDEL 0x37
#define HFCSX_B1_REC 0x3C
#define HFCSX_B1_SEND 0x3C
#define HFCSX_B2_REC 0x3D
#define HFCSX_B2_SEND 0x3D
#define HFCSX_D_REC 0x3E
#define HFCSX_D_SEND 0x3E
#define HFCSX_E_REC 0x3F
/****************/
/* FIFO section */
/****************/
#define HFCSX_FIF_SEL 0x10
#define HFCSX_FIF_Z1L 0x80
#define HFCSX_FIF_Z1H 0x84
#define HFCSX_FIF_Z2L 0x88
#define HFCSX_FIF_Z2H 0x8C
#define HFCSX_FIF_INCF1 0xA8
#define HFCSX_FIF_DWR 0xAC
#define HFCSX_FIF_F1 0xB0
#define HFCSX_FIF_F2 0xB4
#define HFCSX_FIF_INCF2 0xB8
#define HFCSX_FIF_DRD 0xBC
/* bits in status register (READ) */
#define HFCSX_SX_PROC 0x02
#define HFCSX_NBUSY 0x04
#define HFCSX_TIMER_ELAP 0x10
#define HFCSX_STATINT 0x20
#define HFCSX_FRAMEINT 0x40
#define HFCSX_ANYINT 0x80
/* bits in CTMT (Write) */
#define HFCSX_CLTIMER 0x80
#define HFCSX_TIM3_125 0x04
#define HFCSX_TIM25 0x10
#define HFCSX_TIM50 0x14
#define HFCSX_TIM400 0x18
#define HFCSX_TIM800 0x1C
#define HFCSX_AUTO_TIMER 0x20
#define HFCSX_TRANSB2 0x02
#define HFCSX_TRANSB1 0x01
/* bits in CIRM (Write) */
#define HFCSX_IRQ_SELMSK 0x07
#define HFCSX_IRQ_SELDIS 0x00
#define HFCSX_RESET 0x08
#define HFCSX_FIFO_RESET 0x80
/* bits in INT_M1 and INT_S1 */
#define HFCSX_INTS_B1TRANS 0x01
#define HFCSX_INTS_B2TRANS 0x02
#define HFCSX_INTS_DTRANS 0x04
#define HFCSX_INTS_B1REC 0x08
#define HFCSX_INTS_B2REC 0x10
#define HFCSX_INTS_DREC 0x20
#define HFCSX_INTS_L1STATE 0x40
#define HFCSX_INTS_TIMER 0x80
/* bits in INT_M2 */
#define HFCSX_PROC_TRANS 0x01
#define HFCSX_GCI_I_CHG 0x02
#define HFCSX_GCI_MON_REC 0x04
#define HFCSX_IRQ_ENABLE 0x08
/* bits in STATES */
#define HFCSX_STATE_MSK 0x0F
#define HFCSX_LOAD_STATE 0x10
#define HFCSX_ACTIVATE 0x20
#define HFCSX_DO_ACTION 0x40
#define HFCSX_NT_G2_G3 0x80
/* bits in HFCD_MST_MODE */
#define HFCSX_MASTER 0x01
#define HFCSX_SLAVE 0x00
/* 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 HFCSX_AUTO_AWAKE 0x01
#define HFCSX_DBIT_1 0x04
#define HFCSX_IGNORE_COL 0x08
#define HFCSX_CHG_B1_B2 0x80
/**********************************/
/* definitions for FIFO selection */
/**********************************/
#define HFCSX_SEL_D_RX 5
#define HFCSX_SEL_D_TX 4
#define HFCSX_SEL_B1_RX 1
#define HFCSX_SEL_B1_TX 0
#define HFCSX_SEL_B2_RX 3
#define HFCSX_SEL_B2_TX 2
#define MAX_D_FRAMES 15
#define MAX_B_FRAMES 31
#define B_SUB_VAL_32K 0x0200
#define B_FIFO_SIZE_32K (0x2000 - B_SUB_VAL_32K)
#define B_SUB_VAL_8K 0x1A00
#define B_FIFO_SIZE_8K (0x2000 - B_SUB_VAL_8K)
#define D_FIFO_SIZE 512
#define D_FREG_MASK 0xF
/************************************************************/
/* structure holding additional dynamic data -> send marker */
/************************************************************/
struct hfcsx_extra {
unsigned short marker[2 * (MAX_B_FRAMES + 1) + (MAX_D_FRAMES + 1)];
};
extern void main_irq_hfcsx(struct BCState *bcs);
extern void releasehfcsx(struct IsdnCardState *cs);

File diff suppressed because it is too large Load diff

View file

@ -1,208 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* hfc_usb.h
*
* $Id: hfc_usb.h,v 1.1.2.5 2007/08/20 14:36:03 mbachem Exp $
*/
#ifndef __HFC_USB_H__
#define __HFC_USB_H__
#define DRIVER_AUTHOR "Peter Sprenger ([email protected])"
#define DRIVER_DESC "HFC-S USB based HiSAX ISDN driver"
#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */
#define HFC_TIMER_T3 8000 /* timeout for l1 activation timer */
#define HFC_TIMER_T4 500 /* time for state change interval */
#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */
#define HFCUSB_L1_DRX 1 /* D-frame received */
#define HFCUSB_L1_ERX 2 /* E-frame received */
#define HFCUSB_L1_DTX 4 /* D-frames completed */
#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 64 /* 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_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
/*
* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
*/
#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
/* 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 (-64 * 8)
/* HFC-S USB register access by Control-URSs */
#define write_usb(a, b, c) usb_control_msg((a)->dev, (a)->ctrl_out_pipe, 0, 0x40, (c), (b), NULL, 0, HFC_CTRL_TIMEOUT)
#define read_usb(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 32
/* entry and size of output/input control buffer */
typedef struct {
__u8 hfc_reg; /* register number */
__u8 reg_val; /* value to be written (or read) */
int action; /* data for action handler */
} ctrl_buft;
/* Debugging Flags */
#define HFCUSB_DBG_INIT 0x0001
#define HFCUSB_DBG_STATES 0x0002
#define HFCUSB_DBG_DCHANNEL 0x0080
#define HFCUSB_DBG_FIFO_ERR 0x4000
#define HFCUSB_DBG_VERBOSE_USB 0x8000
/*
* 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}
};
/*
* device dependent information to support different
* ISDN Ta's using the HFC-S USB chip
*/
/* 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
/*
* List of all supported endpoint configuration sets, used to find the
* best matching endpoint configuration within a devices' 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_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_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
};
#ifdef CONFIG_HISAX_DEBUG
// 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"
};
#endif
typedef struct {
int vendor; // vendor id
int prod_id; // product id
char *vend_name; // vendor string
__u8 led_scheme; // led display scheme
signed short led_bits[8]; // array of 8 possible LED bitmask settings
} vendor_data;
#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
#endif // __HFC_USB_H__

View file

@ -1,261 +0,0 @@
/* $Id: hfcscard.c,v 1.10.2.4 2004/01/14 16:04:48 keil Exp $
*
* low level stuff for hfcs based cards (Teles3c, ACER P10)
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include <linux/isapnp.h>
#include "hisax.h"
#include "hfc_2bds0.h"
#include "isdnl1.h"
static const char *hfcs_revision = "$Revision: 1.10.2.4 $";
static irqreturn_t
hfcs_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, stat;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) &
(stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) {
val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val);
hfc2bds0_interrupt(cs, val);
} else {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat);
}
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
hfcs_Timer(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, hw.hfcD.timer);
cs->hw.hfcD.timer.expires = jiffies + 75;
/* WD RESET */
/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80);
add_timer(&cs->hw.hfcD.timer);
*/
}
static void
release_io_hfcs(struct IsdnCardState *cs)
{
release2bds0(cs);
del_timer(&cs->hw.hfcD.timer);
if (cs->hw.hfcD.addr)
release_region(cs->hw.hfcD.addr, 2);
}
static void
reset_hfcs(struct IsdnCardState *cs)
{
printk(KERN_INFO "HFCS: resetting card\n");
cs->hw.hfcD.cirm = HFCD_RESET;
if (cs->typ == ISDN_CTYPE_TELES3C)
cs->hw.hfcD.cirm |= HFCD_MEM8K;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */
mdelay(10);
cs->hw.hfcD.cirm = 0;
if (cs->typ == ISDN_CTYPE_TELES3C)
cs->hw.hfcD.cirm |= HFCD_MEM8K;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */
mdelay(10);
if (cs->typ == ISDN_CTYPE_TELES3C)
cs->hw.hfcD.cirm |= HFCD_INTB;
else if (cs->typ == ISDN_CTYPE_ACERP10)
cs->hw.hfcD.cirm |= HFCD_INTA;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */
cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE;
cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS |
HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC |
HFCD_INTS_DREC | HFCD_INTS_L1STATE;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */
udelay(10);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */
cs->hw.hfcD.mst_m = HFCD_MASTER;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */
cs->hw.hfcD.sctrl = 0;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
}
static int
hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
int delay;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "HFCS: card_msg %x", mt);
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_hfcs(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_hfcs(cs);
return (0);
case CARD_INIT:
delay = (75 * HZ) / 100 + 1;
mod_timer(&cs->hw.hfcD.timer, jiffies + delay);
spin_lock_irqsave(&cs->lock, flags);
reset_hfcs(cs);
init2bds0(cs);
spin_unlock_irqrestore(&cs->lock, flags);
delay = (80 * HZ) / 1000 + 1;
msleep(80);
spin_lock_irqsave(&cs->lock, flags);
cs->hw.hfcD.ctmt |= HFCD_TIM800;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
#ifdef __ISAPNP__
static struct isapnp_device_id hfc_ids[] = {
{ ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
(unsigned long) "Acer P10" },
{ ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
(unsigned long) "Billion 2" },
{ ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
(unsigned long) "Billion 1" },
{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
(unsigned long) "IStar PnP" },
{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
(unsigned long) "Teles 16.3c" },
{ ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
(unsigned long) "Tornado Tipa C" },
{ ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
(unsigned long) "Genius Speed Surfer" },
{ 0, }
};
static struct isapnp_device_id *ipid = &hfc_ids[0];
static struct pnp_card *pnp_c = NULL;
#endif
int setup_hfcs(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, hfcs_revision);
printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp));
#ifdef __ISAPNP__
if (!card->para[1] && isapnp_present()) {
struct pnp_dev *pnp_d;
while (ipid->card_vendor) {
if ((pnp_c = pnp_find_card(ipid->card_vendor,
ipid->card_device, pnp_c))) {
pnp_d = NULL;
if ((pnp_d = pnp_find_dev(pnp_c,
ipid->vendor, ipid->function, pnp_d))) {
int err;
printk(KERN_INFO "HiSax: %s detected\n",
(char *)ipid->driver_data);
pnp_disable_dev(pnp_d);
err = pnp_activate_dev(pnp_d);
if (err < 0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
__func__, err);
return (0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
card->para[0] = pnp_irq(pnp_d, 0);
if (card->para[0] == -1 || !card->para[1]) {
printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
card->para[0], card->para[1]);
pnp_disable_dev(pnp_d);
return (0);
}
break;
} else {
printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
}
}
ipid++;
pnp_c = NULL;
}
if (!ipid->card_vendor) {
printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
return (0);
}
}
#endif
cs->hw.hfcD.addr = card->para[1] & 0xfffe;
cs->irq = card->para[0];
cs->hw.hfcD.cip = 0;
cs->hw.hfcD.int_s1 = 0;
cs->hw.hfcD.send = NULL;
cs->bcs[0].hw.hfc.send = NULL;
cs->bcs[1].hw.hfc.send = NULL;
cs->hw.hfcD.dfifosize = 512;
cs->dc.hfcd.ph_state = 0;
cs->hw.hfcD.fifo = 255;
if (cs->typ == ISDN_CTYPE_TELES3C) {
cs->hw.hfcD.bfifosize = 1024 + 512;
} else if (cs->typ == ISDN_CTYPE_ACERP10) {
cs->hw.hfcD.bfifosize = 7 * 1024 + 512;
} else
return (0);
if (!request_region(cs->hw.hfcD.addr, 2, "HFCS isdn")) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
cs->hw.hfcD.addr,
cs->hw.hfcD.addr + 2);
return (0);
}
printk(KERN_INFO
"HFCS: defined at 0x%x IRQ %d HZ %d\n",
cs->hw.hfcD.addr,
cs->irq, HZ);
if (cs->typ == ISDN_CTYPE_TELES3C) {
/* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */
outb(0x00, cs->hw.hfcD.addr);
outb(0x56, cs->hw.hfcD.addr | 1);
} else if (cs->typ == ISDN_CTYPE_ACERP10) {
/* Acer P10 IO ADR is 0x300 */
outb(0x00, cs->hw.hfcD.addr);
outb(0x57, cs->hw.hfcD.addr | 1);
}
set_cs_func(cs);
timer_setup(&cs->hw.hfcD.timer, hfcs_Timer, 0);
cs->cardmsg = &hfcs_card_msg;
cs->irq_func = &hfcs_interrupt;
return (1);
}

File diff suppressed because it is too large Load diff

View file

@ -1,66 +0,0 @@
/* $Id: hisax_cfg.h,v 1.1.2.1 2004/01/24 20:47:23 keil Exp $
* define of the basic HiSax configuration structures
* and pcmcia interface
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define ISDN_CTYPE_16_0 1
#define ISDN_CTYPE_8_0 2
#define ISDN_CTYPE_16_3 3
#define ISDN_CTYPE_PNP 4
#define ISDN_CTYPE_A1 5
#define ISDN_CTYPE_ELSA 6
#define ISDN_CTYPE_ELSA_PNP 7
#define ISDN_CTYPE_TELESPCMCIA 8
#define ISDN_CTYPE_IX1MICROR2 9
#define ISDN_CTYPE_ELSA_PCMCIA 10
#define ISDN_CTYPE_DIEHLDIVA 11
#define ISDN_CTYPE_ASUSCOM 12
#define ISDN_CTYPE_TELEINT 13
#define ISDN_CTYPE_TELES3C 14
#define ISDN_CTYPE_SEDLBAUER 15
#define ISDN_CTYPE_SPORTSTER 16
#define ISDN_CTYPE_MIC 17
#define ISDN_CTYPE_ELSA_PCI 18
#define ISDN_CTYPE_COMPAQ_ISA 19
#define ISDN_CTYPE_NETJET_S 20
#define ISDN_CTYPE_TELESPCI 21
#define ISDN_CTYPE_SEDLBAUER_PCMCIA 22
#define ISDN_CTYPE_AMD7930 23
#define ISDN_CTYPE_NICCY 24
#define ISDN_CTYPE_S0BOX 25
#define ISDN_CTYPE_A1_PCMCIA 26
#define ISDN_CTYPE_FRITZPCI 27
#define ISDN_CTYPE_SEDLBAUER_FAX 28
#define ISDN_CTYPE_ISURF 29
#define ISDN_CTYPE_ACERP10 30
#define ISDN_CTYPE_HSTSAPHIR 31
#define ISDN_CTYPE_BKM_A4T 32
#define ISDN_CTYPE_SCT_QUADRO 33
#define ISDN_CTYPE_GAZEL 34
#define ISDN_CTYPE_HFC_PCI 35
#define ISDN_CTYPE_W6692 36
#define ISDN_CTYPE_HFC_SX 37
#define ISDN_CTYPE_NETJET_U 38
#define ISDN_CTYPE_HFC_SP_PCMCIA 39
#define ISDN_CTYPE_DYNAMIC 40
#define ISDN_CTYPE_ENTERNOW 41
#define ISDN_CTYPE_COUNT 41
typedef struct IsdnCardState IsdnCardState_t;
typedef struct IsdnCard IsdnCard_t;
struct IsdnCard {
int typ;
int protocol; /* EDSS1, 1TR6 or NI1 */
unsigned long para[4];
IsdnCardState_t *cs;
};
typedef int (*hisax_setup_func_t)(struct IsdnCard *card);
extern void HiSax_closecard(int);
extern int hisax_init_pcmcia(void *, int *, IsdnCard_t *);

View file

@ -1,80 +0,0 @@
/*
* Common debugging macros for use with the hisax driver
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* How to use:
*
* Before including this file, you need to
* #define __debug_variable my_debug
* where my_debug is a variable in your code which
* determines the debug bitmask.
*
* If CONFIG_HISAX_DEBUG is not set, all macros evaluate to nothing
*
*/
#ifndef __HISAX_DEBUG_H__
#define __HISAX_DEBUG_H__
#ifdef CONFIG_HISAX_DEBUG
#define DBG(level, format, arg...) do { \
if (level & __debug_variable) \
printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \
} while (0)
#define DBG_PACKET(level, data, count) \
if (level & __debug_variable) dump_packet(__func__, data, count)
#define DBG_SKB(level, skb) \
if ((level & __debug_variable) && skb) dump_packet(__func__, skb->data, skb->len)
static void __attribute__((unused))
dump_packet(const char *name, const u_char *data, int pkt_len)
{
#define DUMP_HDR_SIZE 20
#define DUMP_TLR_SIZE 8
if (pkt_len) {
int i, len1, len2;
printk(KERN_DEBUG "%s: length=%d,data=", name, pkt_len);
if (pkt_len > DUMP_HDR_SIZE + DUMP_TLR_SIZE) {
len1 = DUMP_HDR_SIZE;
len2 = DUMP_TLR_SIZE;
} else {
len1 = pkt_len > DUMP_HDR_SIZE ? DUMP_HDR_SIZE : pkt_len;
len2 = 0;
}
for (i = 0; i < len1; ++i) {
printk("%.2x", data[i]);
}
if (len2) {
printk("..");
for (i = pkt_len-DUMP_TLR_SIZE; i < pkt_len; ++i) {
printk("%.2x", data[i]);
}
}
printk("\n");
}
#undef DUMP_HDR_SIZE
#undef DUMP_TLR_SIZE
}
#else
#define DBG(level, format, arg...) do {} while (0)
#define DBG_PACKET(level, data, count) do {} while (0)
#define DBG_SKB(level, skb) do {} while (0)
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,58 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include "hisax_if.h"
#include "hisax_isac.h"
#include <linux/pci.h>
#define HSCX_BUFMAX 4096
enum {
AVM_FRITZ_PCI,
AVM_FRITZ_PNP,
AVM_FRITZ_PCIV2,
};
struct hdlc_stat_reg {
#ifdef __BIG_ENDIAN
u_char fill;
u_char mode;
u_char xml;
u_char cmd;
#else
u_char cmd;
u_char xml;
u_char mode;
u_char fill;
#endif
} __attribute__((packed));
struct fritz_bcs {
struct hisax_b_if b_if;
struct fritz_adapter *adapter;
int mode;
int channel;
union {
u_int ctrl;
struct hdlc_stat_reg sr;
} ctrl;
u_int stat;
int rcvidx;
int fifo_size;
u_char rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */
int tx_cnt; /* B-Channel transmit counter */
struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
};
struct fritz_adapter {
int type;
spinlock_t hw_lock;
unsigned int io;
unsigned int irq;
struct isac isac;
struct fritz_bcs bcs[2];
u32 (*read_hdlc_status) (struct fritz_adapter *adapter, int nr);
void (*write_ctrl) (struct fritz_bcs *bcs, int which);
};

View file

@ -1,66 +0,0 @@
/*
* Interface between low level (hardware) drivers and
* HiSax protocol stack
*
* Author Kai Germaschewski
* Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef __HISAX_IF_H__
#define __HISAX_IF_H__
#include <linux/skbuff.h>
#define REQUEST 0
#define CONFIRM 1
#define INDICATION 2
#define RESPONSE 3
#define PH_ACTIVATE 0x0100
#define PH_DEACTIVATE 0x0110
#define PH_DATA 0x0120
#define PH_PULL 0x0130
#define PH_DATA_E 0x0140
#define L1_MODE_NULL 0
#define L1_MODE_TRANS 1
#define L1_MODE_HDLC 2
#define L1_MODE_EXTRN 3
#define L1_MODE_HDLC_56K 4
#define L1_MODE_MODEM 7
#define L1_MODE_V32 8
#define L1_MODE_FAX 9
struct hisax_if {
void *priv; // private to driver
void (*l1l2)(struct hisax_if *, int pr, void *arg);
void (*l2l1)(struct hisax_if *, int pr, void *arg);
};
struct hisax_b_if {
struct hisax_if ifc;
// private to hisax
struct BCState *bcs;
};
struct hisax_d_if {
struct hisax_if ifc;
// private to hisax
struct module *owner;
struct IsdnCardState *cs;
struct hisax_b_if *b_if[2];
struct sk_buff_head erq;
unsigned long ph_state;
};
int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[],
char *name, int protocol);
void hisax_unregister(struct hisax_d_if *hisax_if);
#endif

View file

@ -1,895 +0,0 @@
/*
* Driver for ISAC-S and ISAC-SX
* ISDN Subscriber Access Controller for Terminals
*
* Author Kai Germaschewski
* Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
* 2001 by Karsten Keil <keil@isdn4linux.de>
*
* based upon Karsten Keil's original isac.c driver
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Wizard Computersysteme GmbH, Bremervoerde and
* SoHaNet Technology GmbH, Berlin
* for supporting the development of this driver
*/
/* TODO:
* specifically handle level vs edge triggered?
*/
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include "hisax_isac.h"
// debugging cruft
#define __debug_variable debug
#include "hisax_debug.h"
#ifdef CONFIG_HISAX_DEBUG
static int debug = 1;
module_param(debug, int, 0);
static char *ISACVer[] = {
"2086/2186 V1.1",
"2085 B1",
"2085 B2",
"2085 V2.3"
};
#endif
MODULE_AUTHOR("Kai Germaschewski <[email protected]>/Karsten Keil <[email protected]>");
MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
MODULE_LICENSE("GPL");
#define DBG_WARN 0x0001
#define DBG_IRQ 0x0002
#define DBG_L1M 0x0004
#define DBG_PR 0x0008
#define DBG_RFIFO 0x0100
#define DBG_RPACKET 0x0200
#define DBG_XFIFO 0x1000
#define DBG_XPACKET 0x2000
// we need to distinguish ISAC-S and ISAC-SX
#define TYPE_ISAC 0x00
#define TYPE_ISACSX 0x01
// registers etc.
#define ISAC_MASK 0x20
#define ISAC_ISTA 0x20
#define ISAC_ISTA_EXI 0x01
#define ISAC_ISTA_SIN 0x02
#define ISAC_ISTA_CISQ 0x04
#define ISAC_ISTA_XPR 0x10
#define ISAC_ISTA_RSC 0x20
#define ISAC_ISTA_RPF 0x40
#define ISAC_ISTA_RME 0x80
#define ISAC_STAR 0x21
#define ISAC_CMDR 0x21
#define ISAC_CMDR_XRES 0x01
#define ISAC_CMDR_XME 0x02
#define ISAC_CMDR_XTF 0x08
#define ISAC_CMDR_RRES 0x40
#define ISAC_CMDR_RMC 0x80
#define ISAC_EXIR 0x24
#define ISAC_EXIR_MOS 0x04
#define ISAC_EXIR_XDU 0x40
#define ISAC_EXIR_XMR 0x80
#define ISAC_ADF2 0x39
#define ISAC_SPCR 0x30
#define ISAC_ADF1 0x38
#define ISAC_CIR0 0x31
#define ISAC_CIX0 0x31
#define ISAC_CIR0_CIC0 0x02
#define ISAC_CIR0_CIC1 0x01
#define ISAC_CIR1 0x33
#define ISAC_CIX1 0x33
#define ISAC_STCR 0x37
#define ISAC_MODE 0x22
#define ISAC_RSTA 0x27
#define ISAC_RSTA_RDO 0x40
#define ISAC_RSTA_CRC 0x20
#define ISAC_RSTA_RAB 0x10
#define ISAC_RBCL 0x25
#define ISAC_RBCH 0x2A
#define ISAC_TIMR 0x23
#define ISAC_SQXR 0x3b
#define ISAC_MOSR 0x3a
#define ISAC_MOCR 0x3a
#define ISAC_MOR0 0x32
#define ISAC_MOX0 0x32
#define ISAC_MOR1 0x34
#define ISAC_MOX1 0x34
#define ISAC_RBCH_XAC 0x80
#define ISAC_CMD_TIM 0x0
#define ISAC_CMD_RES 0x1
#define ISAC_CMD_SSP 0x2
#define ISAC_CMD_SCP 0x3
#define ISAC_CMD_AR8 0x8
#define ISAC_CMD_AR10 0x9
#define ISAC_CMD_ARL 0xa
#define ISAC_CMD_DI 0xf
#define ISACSX_MASK 0x60
#define ISACSX_ISTA 0x60
#define ISACSX_ISTA_ICD 0x01
#define ISACSX_ISTA_CIC 0x10
#define ISACSX_MASKD 0x20
#define ISACSX_ISTAD 0x20
#define ISACSX_ISTAD_XDU 0x04
#define ISACSX_ISTAD_XMR 0x08
#define ISACSX_ISTAD_XPR 0x10
#define ISACSX_ISTAD_RFO 0x20
#define ISACSX_ISTAD_RPF 0x40
#define ISACSX_ISTAD_RME 0x80
#define ISACSX_CMDRD 0x21
#define ISACSX_CMDRD_XRES 0x01
#define ISACSX_CMDRD_XME 0x02
#define ISACSX_CMDRD_XTF 0x08
#define ISACSX_CMDRD_RRES 0x40
#define ISACSX_CMDRD_RMC 0x80
#define ISACSX_MODED 0x22
#define ISACSX_RBCLD 0x26
#define ISACSX_RSTAD 0x28
#define ISACSX_RSTAD_RAB 0x10
#define ISACSX_RSTAD_CRC 0x20
#define ISACSX_RSTAD_RDO 0x40
#define ISACSX_RSTAD_VFR 0x80
#define ISACSX_CIR0 0x2e
#define ISACSX_CIR0_CIC0 0x08
#define ISACSX_CIX0 0x2e
#define ISACSX_TR_CONF0 0x30
#define ISACSX_TR_CONF2 0x32
static struct Fsm l1fsm;
enum {
ST_L1_RESET,
ST_L1_F3_PDOWN,
ST_L1_F3_PUP,
ST_L1_F3_PEND_DEACT,
ST_L1_F4,
ST_L1_F5,
ST_L1_F6,
ST_L1_F7,
ST_L1_F8,
};
#define L1_STATE_COUNT (ST_L1_F8 + 1)
static char *strL1State[] =
{
"ST_L1_RESET",
"ST_L1_F3_PDOWN",
"ST_L1_F3_PUP",
"ST_L1_F3_PEND_DEACT",
"ST_L1_F4",
"ST_L1_F5",
"ST_L1_F6",
"ST_L1_F7",
"ST_L1_F8",
};
enum {
EV_PH_DR, // 0000
EV_PH_RES, // 0001
EV_PH_TMA, // 0010
EV_PH_SLD, // 0011
EV_PH_RSY, // 0100
EV_PH_DR6, // 0101
EV_PH_EI, // 0110
EV_PH_PU, // 0111
EV_PH_AR, // 1000
EV_PH_9, // 1001
EV_PH_ARL, // 1010
EV_PH_CVR, // 1011
EV_PH_AI8, // 1100
EV_PH_AI10, // 1101
EV_PH_AIL, // 1110
EV_PH_DC, // 1111
EV_PH_ACTIVATE_REQ,
EV_PH_DEACTIVATE_REQ,
EV_TIMER3,
};
#define L1_EVENT_COUNT (EV_TIMER3 + 1)
static char *strL1Event[] =
{
"EV_PH_DR", // 0000
"EV_PH_RES", // 0001
"EV_PH_TMA", // 0010
"EV_PH_SLD", // 0011
"EV_PH_RSY", // 0100
"EV_PH_DR6", // 0101
"EV_PH_EI", // 0110
"EV_PH_PU", // 0111
"EV_PH_AR", // 1000
"EV_PH_9", // 1001
"EV_PH_ARL", // 1010
"EV_PH_CVR", // 1011
"EV_PH_AI8", // 1100
"EV_PH_AI10", // 1101
"EV_PH_AIL", // 1110
"EV_PH_DC", // 1111
"EV_PH_ACTIVATE_REQ",
"EV_PH_DEACTIVATE_REQ",
"EV_TIMER3",
};
static inline void D_L1L2(struct isac *isac, int pr, void *arg)
{
struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if;
DBG(DBG_PR, "pr %#x", pr);
ifc->l1l2(ifc, pr, arg);
}
static void ph_command(struct isac *isac, unsigned int command)
{
DBG(DBG_L1M, "ph_command %#x", command);
switch (isac->type) {
case TYPE_ISAC:
isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3);
break;
case TYPE_ISACSX:
isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1));
break;
}
}
// ----------------------------------------------------------------------
static void l1_di(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_RESET);
ph_command(isac, ISAC_CMD_DI);
}
static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_RESET);
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
ph_command(isac, ISAC_CMD_DI);
}
static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F3_PDOWN);
}
static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
ph_command(isac, ISAC_CMD_DI);
}
static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
ph_command(isac, ISAC_CMD_DI);
}
static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F4);
}
static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F5);
}
static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F6);
}
static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_F6);
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
}
static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmDelTimer(&isac->timer, 0);
FsmChangeState(fi, ST_L1_F7);
ph_command(isac, ISAC_CMD_AR8);
D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL);
}
static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F8);
}
static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_F8);
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
}
static void l1_ar8(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
ph_command(isac, ISAC_CMD_AR8);
}
static void l1_timer3(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
ph_command(isac, ISAC_CMD_DI);
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
}
// state machines according to data sheet PSB 2186 / 3186
static struct FsmNode L1FnList[] __initdata =
{
{ST_L1_RESET, EV_PH_RES, l1_di},
{ST_L1_RESET, EV_PH_EI, l1_di},
{ST_L1_RESET, EV_PH_DC, l1_go_f3pdown},
{ST_L1_RESET, EV_PH_AR, l1_go_f6},
{ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F3_PDOWN, EV_PH_RES, l1_di},
{ST_L1_F3_PDOWN, EV_PH_EI, l1_di},
{ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6},
{ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5},
{ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4},
{ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F3_PDOWN, EV_PH_ACTIVATE_REQ, l1_ar8},
{ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3},
{ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di},
{ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di},
{ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown},
{ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5},
{ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6},
{ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F4, EV_PH_RES, l1_di},
{ST_L1_F4, EV_PH_EI, l1_di},
{ST_L1_F4, EV_PH_RSY, l1_go_f5},
{ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F4, EV_TIMER3, l1_timer3},
{ST_L1_F4, EV_PH_DC, l1_go_f3pdown},
{ST_L1_F5, EV_PH_RES, l1_di},
{ST_L1_F5, EV_PH_EI, l1_di},
{ST_L1_F5, EV_PH_AR, l1_go_f6},
{ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F5, EV_TIMER3, l1_timer3},
{ST_L1_F5, EV_PH_DR, l1_go_f3pend},
{ST_L1_F5, EV_PH_DC, l1_go_f3pdown},
{ST_L1_F6, EV_PH_RES, l1_di},
{ST_L1_F6, EV_PH_EI, l1_di},
{ST_L1_F6, EV_PH_RSY, l1_go_f8},
{ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F6, EV_PH_DR6, l1_go_f3pend},
{ST_L1_F6, EV_TIMER3, l1_timer3},
{ST_L1_F6, EV_PH_DC, l1_go_f3pdown},
{ST_L1_F7, EV_PH_RES, l1_di_deact_ind},
{ST_L1_F7, EV_PH_EI, l1_di_deact_ind},
{ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind},
{ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind},
{ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind},
{ST_L1_F8, EV_PH_RES, l1_di},
{ST_L1_F8, EV_PH_EI, l1_di},
{ST_L1_F8, EV_PH_AR, l1_go_f6},
{ST_L1_F8, EV_PH_DR, l1_go_f3pend},
{ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F8, EV_TIMER3, l1_timer3},
{ST_L1_F8, EV_PH_DC, l1_go_f3pdown},
};
static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
char buf[256];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
DBG(DBG_L1M, "%s", buf);
va_end(args);
}
static void isac_version(struct isac *cs)
{
int val;
val = cs->read_isac(cs, ISAC_RBCH);
DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);
}
static void isac_empty_fifo(struct isac *isac, int count)
{
// this also works for isacsx, since
// CMDR(D) register works the same
u_char *ptr;
DBG(DBG_IRQ, "count %d", count);
if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
DBG(DBG_WARN, "overrun %d", isac->rcvidx + count);
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
isac->rcvidx = 0;
return;
}
ptr = isac->rcvbuf + isac->rcvidx;
isac->rcvidx += count;
isac->read_isac_fifo(isac, ptr, count);
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
DBG_PACKET(DBG_RFIFO, ptr, count);
}
static void isac_fill_fifo(struct isac *isac)
{
// this also works for isacsx, since
// CMDR(D) register works the same
int count;
unsigned char cmd;
u_char *ptr;
BUG_ON(!isac->tx_skb);
count = isac->tx_skb->len;
BUG_ON(count <= 0);
DBG(DBG_IRQ, "count %d", count);
if (count > 0x20) {
count = 0x20;
cmd = ISAC_CMDR_XTF;
} else {
cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
}
ptr = isac->tx_skb->data;
skb_pull(isac->tx_skb, count);
isac->tx_cnt += count;
DBG_PACKET(DBG_XFIFO, ptr, count);
isac->write_isac_fifo(isac, ptr, count);
isac->write_isac(isac, ISAC_CMDR, cmd);
}
static void isac_retransmit(struct isac *isac)
{
if (!isac->tx_skb) {
DBG(DBG_WARN, "no skb");
return;
}
skb_push(isac->tx_skb, isac->tx_cnt);
isac->tx_cnt = 0;
}
static inline void isac_cisq_interrupt(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISAC_CIR0);
DBG(DBG_IRQ, "CIR0 %#x", val);
if (val & ISAC_CIR0_CIC0) {
DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf);
FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
}
if (val & ISAC_CIR0_CIC1) {
val = isac->read_isac(isac, ISAC_CIR1);
DBG(DBG_WARN, "ISAC CIR1 %#x", val);
}
}
static inline void isac_rme_interrupt(struct isac *isac)
{
unsigned char val;
int count;
struct sk_buff *skb;
val = isac->read_isac(isac, ISAC_RSTA);
if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB))
!= ISAC_RSTA_CRC) {
DBG(DBG_WARN, "RSTA %#x, dropped", val);
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
goto out;
}
count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
DBG(DBG_IRQ, "RBCL %#x", count);
if (count == 0)
count = 0x20;
isac_empty_fifo(isac, count);
count = isac->rcvidx;
if (count < 1) {
DBG(DBG_WARN, "count %d < 1", count);
goto out;
}
skb = alloc_skb(count, GFP_ATOMIC);
if (!skb) {
DBG(DBG_WARN, "no memory, dropping\n");
goto out;
}
skb_put_data(skb, isac->rcvbuf, count);
DBG_SKB(DBG_RPACKET, skb);
D_L1L2(isac, PH_DATA | INDICATION, skb);
out:
isac->rcvidx = 0;
}
static inline void isac_xpr_interrupt(struct isac *isac)
{
if (!isac->tx_skb)
return;
if (isac->tx_skb->len > 0) {
isac_fill_fifo(isac);
return;
}
dev_kfree_skb_irq(isac->tx_skb);
isac->tx_cnt = 0;
isac->tx_skb = NULL;
D_L1L2(isac, PH_DATA | CONFIRM, NULL);
}
static inline void isac_exi_interrupt(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISAC_EXIR);
DBG(2, "EXIR %#x", val);
if (val & ISAC_EXIR_XMR) {
DBG(DBG_WARN, "ISAC XMR");
isac_retransmit(isac);
}
if (val & ISAC_EXIR_XDU) {
DBG(DBG_WARN, "ISAC XDU");
isac_retransmit(isac);
}
if (val & ISAC_EXIR_MOS) { /* MOS */
DBG(DBG_WARN, "MOS");
val = isac->read_isac(isac, ISAC_MOSR);
DBG(2, "ISAC MOSR %#x", val);
}
}
void isac_irq(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISAC_ISTA);
DBG(DBG_IRQ, "ISTA %#x", val);
if (val & ISAC_ISTA_EXI) {
DBG(DBG_IRQ, "EXI");
isac_exi_interrupt(isac);
}
if (val & ISAC_ISTA_XPR) {
DBG(DBG_IRQ, "XPR");
isac_xpr_interrupt(isac);
}
if (val & ISAC_ISTA_RME) {
DBG(DBG_IRQ, "RME");
isac_rme_interrupt(isac);
}
if (val & ISAC_ISTA_RPF) {
DBG(DBG_IRQ, "RPF");
isac_empty_fifo(isac, 0x20);
}
if (val & ISAC_ISTA_CISQ) {
DBG(DBG_IRQ, "CISQ");
isac_cisq_interrupt(isac);
}
if (val & ISAC_ISTA_RSC) {
DBG(DBG_WARN, "RSC");
}
if (val & ISAC_ISTA_SIN) {
DBG(DBG_WARN, "SIN");
}
isac->write_isac(isac, ISAC_MASK, 0xff);
isac->write_isac(isac, ISAC_MASK, 0x00);
}
// ======================================================================
static inline void isacsx_cic_interrupt(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISACSX_CIR0);
DBG(DBG_IRQ, "CIR0 %#x", val);
if (val & ISACSX_CIR0_CIC0) {
DBG(DBG_IRQ, "CODR0 %#x", val >> 4);
FsmEvent(&isac->l1m, val >> 4, NULL);
}
}
static inline void isacsx_rme_interrupt(struct isac *isac)
{
int count;
struct sk_buff *skb;
unsigned char val;
val = isac->read_isac(isac, ISACSX_RSTAD);
if ((val & (ISACSX_RSTAD_VFR |
ISACSX_RSTAD_RDO |
ISACSX_RSTAD_CRC |
ISACSX_RSTAD_RAB))
!= (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) {
DBG(DBG_WARN, "RSTAD %#x, dropped", val);
isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
goto out;
}
count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
DBG(DBG_IRQ, "RBCLD %#x", count);
if (count == 0)
count = 0x20;
isac_empty_fifo(isac, count);
// strip trailing status byte
count = isac->rcvidx - 1;
if (count < 1) {
DBG(DBG_WARN, "count %d < 1", count);
goto out;
}
skb = dev_alloc_skb(count);
if (!skb) {
DBG(DBG_WARN, "no memory, dropping");
goto out;
}
skb_put_data(skb, isac->rcvbuf, count);
DBG_SKB(DBG_RPACKET, skb);
D_L1L2(isac, PH_DATA | INDICATION, skb);
out:
isac->rcvidx = 0;
}
static inline void isacsx_xpr_interrupt(struct isac *isac)
{
if (!isac->tx_skb)
return;
if (isac->tx_skb->len > 0) {
isac_fill_fifo(isac);
return;
}
dev_kfree_skb_irq(isac->tx_skb);
isac->tx_skb = NULL;
isac->tx_cnt = 0;
D_L1L2(isac, PH_DATA | CONFIRM, NULL);
}
static inline void isacsx_icd_interrupt(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISACSX_ISTAD);
DBG(DBG_IRQ, "ISTAD %#x", val);
if (val & ISACSX_ISTAD_XDU) {
DBG(DBG_WARN, "ISTAD XDU");
isac_retransmit(isac);
}
if (val & ISACSX_ISTAD_XMR) {
DBG(DBG_WARN, "ISTAD XMR");
isac_retransmit(isac);
}
if (val & ISACSX_ISTAD_XPR) {
DBG(DBG_IRQ, "ISTAD XPR");
isacsx_xpr_interrupt(isac);
}
if (val & ISACSX_ISTAD_RFO) {
DBG(DBG_WARN, "ISTAD RFO");
isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
}
if (val & ISACSX_ISTAD_RME) {
DBG(DBG_IRQ, "ISTAD RME");
isacsx_rme_interrupt(isac);
}
if (val & ISACSX_ISTAD_RPF) {
DBG(DBG_IRQ, "ISTAD RPF");
isac_empty_fifo(isac, 0x20);
}
}
void isacsx_irq(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISACSX_ISTA);
DBG(DBG_IRQ, "ISTA %#x", val);
if (val & ISACSX_ISTA_ICD)
isacsx_icd_interrupt(isac);
if (val & ISACSX_ISTA_CIC)
isacsx_cic_interrupt(isac);
}
void isac_init(struct isac *isac)
{
isac->tx_skb = NULL;
isac->l1m.fsm = &l1fsm;
isac->l1m.state = ST_L1_RESET;
#ifdef CONFIG_HISAX_DEBUG
isac->l1m.debug = 1;
#else
isac->l1m.debug = 0;
#endif
isac->l1m.userdata = isac;
isac->l1m.printdebug = l1m_debug;
FsmInitTimer(&isac->l1m, &isac->timer);
}
void isac_setup(struct isac *isac)
{
int val, eval;
isac->type = TYPE_ISAC;
isac_version(isac);
ph_command(isac, ISAC_CMD_RES);
isac->write_isac(isac, ISAC_MASK, 0xff);
isac->mocr = 0xaa;
if (test_bit(ISAC_IOM1, &isac->flags)) {
/* IOM 1 Mode */
isac->write_isac(isac, ISAC_ADF2, 0x0);
isac->write_isac(isac, ISAC_SPCR, 0xa);
isac->write_isac(isac, ISAC_ADF1, 0x2);
isac->write_isac(isac, ISAC_STCR, 0x70);
isac->write_isac(isac, ISAC_MODE, 0xc9);
} else {
/* IOM 2 Mode */
if (!isac->adf2)
isac->adf2 = 0x80;
isac->write_isac(isac, ISAC_ADF2, isac->adf2);
isac->write_isac(isac, ISAC_SQXR, 0x2f);
isac->write_isac(isac, ISAC_SPCR, 0x00);
isac->write_isac(isac, ISAC_STCR, 0x70);
isac->write_isac(isac, ISAC_MODE, 0xc9);
isac->write_isac(isac, ISAC_TIMR, 0x00);
isac->write_isac(isac, ISAC_ADF1, 0x00);
}
val = isac->read_isac(isac, ISAC_STAR);
DBG(2, "ISAC STAR %x", val);
val = isac->read_isac(isac, ISAC_MODE);
DBG(2, "ISAC MODE %x", val);
val = isac->read_isac(isac, ISAC_ADF2);
DBG(2, "ISAC ADF2 %x", val);
val = isac->read_isac(isac, ISAC_ISTA);
DBG(2, "ISAC ISTA %x", val);
if (val & 0x01) {
eval = isac->read_isac(isac, ISAC_EXIR);
DBG(2, "ISAC EXIR %x", eval);
}
val = isac->read_isac(isac, ISAC_CIR0);
DBG(2, "ISAC CIR0 %x", val);
FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
isac->write_isac(isac, ISAC_MASK, 0x0);
// RESET Receiver and Transmitter
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES);
}
void isacsx_setup(struct isac *isac)
{
isac->type = TYPE_ISACSX;
// clear LDD
isac->write_isac(isac, ISACSX_TR_CONF0, 0x00);
// enable transmitter
isac->write_isac(isac, ISACSX_TR_CONF2, 0x00);
// transparent mode 0, RAC, stop/go
isac->write_isac(isac, ISACSX_MODED, 0xc9);
// all HDLC IRQ unmasked
isac->write_isac(isac, ISACSX_MASKD, 0x03);
// unmask ICD, CID IRQs
isac->write_isac(isac, ISACSX_MASK,
~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
}
void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
{
struct isac *isac = hisax_d_if->priv;
struct sk_buff *skb = arg;
DBG(DBG_PR, "pr %#x", pr);
switch (pr) {
case PH_ACTIVATE | REQUEST:
FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL);
break;
case PH_DEACTIVATE | REQUEST:
FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL);
break;
case PH_DATA | REQUEST:
DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
DBG_SKB(DBG_XPACKET, skb);
if (isac->l1m.state != ST_L1_F7) {
DBG(1, "L1 wrong state %d\n", isac->l1m.state);
dev_kfree_skb(skb);
break;
}
BUG_ON(isac->tx_skb);
isac->tx_skb = skb;
isac_fill_fifo(isac);
break;
}
}
static int __init hisax_isac_init(void)
{
printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
l1fsm.state_count = L1_STATE_COUNT;
l1fsm.event_count = L1_EVENT_COUNT;
l1fsm.strState = strL1State;
l1fsm.strEvent = strL1Event;
return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
}
static void __exit hisax_isac_exit(void)
{
FsmFree(&l1fsm);
}
EXPORT_SYMBOL(isac_init);
EXPORT_SYMBOL(isac_d_l2l1);
EXPORT_SYMBOL(isacsx_setup);
EXPORT_SYMBOL(isacsx_irq);
EXPORT_SYMBOL(isac_setup);
EXPORT_SYMBOL(isac_irq);
module_init(hisax_isac_init);
module_exit(hisax_isac_exit);

View file

@ -1,46 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __HISAX_ISAC_H__
#define __HISAX_ISAC_H__
#include <linux/kernel.h>
#include "fsm.h"
#include "hisax_if.h"
#define TIMER3_VALUE 7000
#define MAX_DFRAME_LEN_L1 300
#define ISAC_IOM1 0
struct isac {
void *priv;
u_long flags;
struct hisax_d_if hisax_d_if;
struct FsmInst l1m;
struct FsmTimer timer;
u_char mocr;
u_char adf2;
int type;
u_char rcvbuf[MAX_DFRAME_LEN_L1];
int rcvidx;
struct sk_buff *tx_skb;
int tx_cnt;
u_char (*read_isac) (struct isac *, u_char);
void (*write_isac) (struct isac *, u_char, u_char);
void (*read_isac_fifo) (struct isac *, u_char *, int);
void (*write_isac_fifo)(struct isac *, u_char *, int);
};
void isac_init(struct isac *isac);
void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
void isac_setup(struct isac *isac);
void isac_irq(struct isac *isac);
void isacsx_setup(struct isac *isac);
void isacsx_irq(struct isac *isac);
#endif

View file

@ -1,277 +0,0 @@
/* $Id: hscx.c,v 1.24.2.4 2004/01/24 20:47:23 keil Exp $
*
* HSCX specific routines
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "hscx.h"
#include "isac.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
static char *HSCXVer[] =
{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
"?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
int
HscxVersion(struct IsdnCardState *cs, char *s)
{
int verA, verB;
verA = cs->BC_Read_Reg(cs, 0, HSCX_VSTR) & 0xf;
verB = cs->BC_Read_Reg(cs, 1, HSCX_VSTR) & 0xf;
printk(KERN_INFO "%s HSCX version A: %s B: %s\n", s,
HSCXVer[verA], HSCXVer[verB]);
if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf))
return (1);
else
return (0);
}
void
modehscx(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
int hscx = bcs->hw.hscx.hscx;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hscx %c mode %d ichan %d",
'A' + hscx, mode, bc);
bcs->mode = mode;
bcs->channel = bc;
cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF);
cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF);
cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF);
cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0);
cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0);
cs->BC_Write_Reg(cs, hscx, HSCX_CCR1,
test_bit(HW_IPAC, &cs->HW_Flags) ? 0x82 : 0x85);
cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30);
cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7);
cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7);
/* Switch IOM 1 SSI */
if (test_bit(HW_IOM1, &cs->HW_Flags) && (hscx == 0))
bc = 1 - bc;
if (bc == 0) {
cs->BC_Write_Reg(cs, hscx, HSCX_TSAX,
test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
cs->BC_Write_Reg(cs, hscx, HSCX_TSAR,
test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
} else {
cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, bcs->hw.hscx.tsaxr1);
cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, bcs->hw.hscx.tsaxr1);
}
switch (mode) {
case (L1_MODE_NULL):
cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x1f);
cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x1f);
cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84);
break;
case (L1_MODE_TRANS):
cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4);
break;
case (L1_MODE_HDLC):
cs->BC_Write_Reg(cs, hscx, HSCX_CCR1,
test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d);
cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c);
break;
}
if (mode)
cs->BC_Write_Reg(cs, hscx, HSCX_CMDR, 0x41);
cs->BC_Write_Reg(cs, hscx, HSCX_ISTA, 0x00);
}
void
hscx_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
u_long flags;
struct sk_buff *skb = arg;
switch (pr) {
case (PH_DATA | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->hw.hscx.count = 0;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
} else {
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->tx_skb = skb;
bcs->hw.hscx.count = 0;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | REQUEST):
if (!bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (PH_ACTIVATE | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
modehscx(bcs, st->l1.mode, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
modehscx(bcs, 0, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
static void
close_hscxstate(struct BCState *bcs)
{
modehscx(bcs, 0, bcs->channel);
if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
kfree(bcs->blog);
bcs->blog = NULL;
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
}
int
open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for hscx.rcvbuf\n");
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
return (1);
}
if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for bcs->blog\n");
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
return (2);
}
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->hw.hscx.rcvidx = 0;
bcs->tx_cnt = 0;
return (0);
}
static int
setstack_hscx(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
if (open_hscxstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
st->l2.l2l1 = hscx_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
void
clear_pending_hscx_ints(struct IsdnCardState *cs)
{
int val, eval;
val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA);
debugl1(cs, "HSCX B ISTA %x", val);
if (val & 0x01) {
eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR);
debugl1(cs, "HSCX B EXIR %x", eval);
}
if (val & 0x02) {
eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR);
debugl1(cs, "HSCX A EXIR %x", eval);
}
val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA);
debugl1(cs, "HSCX A ISTA %x", val);
val = cs->BC_Read_Reg(cs, 1, HSCX_STAR);
debugl1(cs, "HSCX B STAR %x", val);
val = cs->BC_Read_Reg(cs, 0, HSCX_STAR);
debugl1(cs, "HSCX A STAR %x", val);
/* disable all IRQ */
cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF);
cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF);
}
void
inithscx(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_hscx;
cs->bcs[1].BC_SetStack = setstack_hscx;
cs->bcs[0].BC_Close = close_hscxstate;
cs->bcs[1].BC_Close = close_hscxstate;
cs->bcs[0].hw.hscx.hscx = 0;
cs->bcs[1].hw.hscx.hscx = 1;
cs->bcs[0].hw.hscx.tsaxr0 = 0x2f;
cs->bcs[0].hw.hscx.tsaxr1 = 3;
cs->bcs[1].hw.hscx.tsaxr0 = 0x2f;
cs->bcs[1].hw.hscx.tsaxr1 = 3;
modehscx(cs->bcs, 0, 0);
modehscx(cs->bcs + 1, 0, 0);
}
void
inithscxisac(struct IsdnCardState *cs, int part)
{
if (part & 1) {
clear_pending_isac_ints(cs);
clear_pending_hscx_ints(cs);
initisac(cs);
inithscx(cs);
}
if (part & 2) {
/* Reenable all IRQ */
cs->writeisac(cs, ISAC_MASK, 0);
cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0);
cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0);
/* RESET Receiver and Transmitter */
cs->writeisac(cs, ISAC_CMDR, 0x41);
}
}

View file

@ -1,41 +0,0 @@
/* $Id: hscx.h,v 1.8.2.2 2004/01/12 22:52:26 keil Exp $
*
* HSCX specific defines
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/* All Registers original Siemens Spec */
#define HSCX_ISTA 0x20
#define HSCX_CCR1 0x2f
#define HSCX_CCR2 0x2c
#define HSCX_TSAR 0x31
#define HSCX_TSAX 0x30
#define HSCX_XCCR 0x32
#define HSCX_RCCR 0x33
#define HSCX_MODE 0x22
#define HSCX_CMDR 0x21
#define HSCX_EXIR 0x24
#define HSCX_XAD1 0x24
#define HSCX_XAD2 0x25
#define HSCX_RAH2 0x27
#define HSCX_RSTA 0x27
#define HSCX_TIMR 0x23
#define HSCX_STAR 0x21
#define HSCX_RBCL 0x25
#define HSCX_XBCH 0x2d
#define HSCX_VSTR 0x2e
#define HSCX_RLCR 0x2e
#define HSCX_MASK 0x20
extern int HscxVersion(struct IsdnCardState *cs, char *s);
extern void modehscx(struct BCState *bcs, int mode, int bc);
extern void clear_pending_hscx_ints(struct IsdnCardState *cs);
extern void inithscx(struct IsdnCardState *cs);
extern void inithscxisac(struct IsdnCardState *cs, int part);

View file

@ -1,294 +0,0 @@
/* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $
*
* low level b-channel stuff for Siemens HSCX
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* This is an include file for fast inline IRQ stuff
*
*/
static inline void
waitforCEC(struct IsdnCardState *cs, int hscx)
{
int to = 50;
while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
}
static inline void
waitforXFW(struct IsdnCardState *cs, int hscx)
{
int to = 50;
while (((READHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
}
static inline void
WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
{
waitforCEC(cs, hscx);
WRITEHSCX(cs, hscx, HSCX_CMDR, data);
}
static void
hscx_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr;
struct IsdnCardState *cs = bcs->cs;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hscx_empty_fifo");
if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "hscx_empty_fifo: incoming packet too large");
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
bcs->hw.hscx.rcvidx = 0;
return;
}
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
bcs->hw.hscx.rcvidx += count;
READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "hscx_empty_fifo %c cnt %d",
bcs->hw.hscx.hscx ? 'B' : 'A', count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", bcs->blog);
}
}
static void
hscx_fill_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int more, count;
int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32;
u_char *ptr;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hscx_fill_fifo");
if (!bcs->tx_skb)
return;
if (bcs->tx_skb->len <= 0)
return;
more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
if (bcs->tx_skb->len > fifo_size) {
more = !0;
count = fifo_size;
} else
count = bcs->tx_skb->len;
waitforXFW(cs, bcs->hw.hscx.hscx);
ptr = bcs->tx_skb->data;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.hscx.count += count;
WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "hscx_fill_fifo %c cnt %d",
bcs->hw.hscx.hscx ? 'B' : 'A', count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", bcs->blog);
}
}
static void
hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
{
u_char r;
struct BCState *bcs = cs->bcs + hscx;
struct sk_buff *skb;
int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32;
int count;
if (!test_bit(BC_FLG_INIT, &bcs->Flag))
return;
if (val & 0x80) { /* RME */
r = READHSCX(cs, hscx, HSCX_RSTA);
if ((r & 0xf0) != 0xa0) {
if (!(r & 0x80)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX invalid frame");
#ifdef ERROR_STATISTIC
bcs->err_inv++;
#endif
}
if ((r & 0x40) && bcs->mode) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX RDO mode=%d",
bcs->mode);
#ifdef ERROR_STATISTIC
bcs->err_rdo++;
#endif
}
if (!(r & 0x20)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX CRC error");
#ifdef ERROR_STATISTIC
bcs->err_crc++;
#endif
}
WriteHSCXCMDR(cs, hscx, 0x80);
} else {
count = READHSCX(cs, hscx, HSCX_RBCL) & (
test_bit(HW_IPAC, &cs->HW_Flags) ? 0x3f : 0x1f);
if (count == 0)
count = fifo_size;
hscx_empty_fifo(bcs, count);
if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
if (cs->debug & L1_DEB_HSCX_FIFO)
debugl1(cs, "HX Frame %d", count);
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "HSCX: receive out of memory\n");
else {
skb_put_data(skb, bcs->hw.hscx.rcvbuf,
count);
skb_queue_tail(&bcs->rqueue, skb);
}
}
}
bcs->hw.hscx.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
}
if (val & 0x40) { /* RPF */
hscx_empty_fifo(bcs, fifo_size);
if (bcs->mode == L1_MODE_TRANS) {
/* receive audio data */
if (!(skb = dev_alloc_skb(fifo_size)))
printk(KERN_WARNING "HiSax: receive out of memory\n");
else {
skb_put_data(skb, bcs->hw.hscx.rcvbuf,
fifo_size);
skb_queue_tail(&bcs->rqueue, skb);
}
bcs->hw.hscx.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
}
}
if (val & 0x10) { /* XPR */
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
hscx_fill_fifo(bcs);
return;
} else {
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += bcs->hw.hscx.count;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL;
}
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
bcs->hw.hscx.count = 0;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
hscx_fill_fifo(bcs);
} else {
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
schedule_event(bcs, B_XMTBUFREADY);
}
}
}
static void
hscx_int_main(struct IsdnCardState *cs, u_char val)
{
u_char exval;
struct BCState *bcs;
if (val & 0x01) {
bcs = cs->bcs + 1;
exval = READHSCX(cs, 1, HSCX_EXIR);
if (exval & 0x40) {
if (bcs->mode == 1)
hscx_fill_fifo(bcs);
else {
#ifdef ERROR_STATISTIC
bcs->err_tx++;
#endif
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->hw.hscx.count);
bcs->tx_cnt += bcs->hw.hscx.count;
bcs->hw.hscx.count = 0;
}
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
}
} else if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX B EXIR %x", exval);
}
if (val & 0xf8) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX B interrupt %x", val);
hscx_interrupt(cs, val, 1);
}
if (val & 0x02) {
bcs = cs->bcs;
exval = READHSCX(cs, 0, HSCX_EXIR);
if (exval & 0x40) {
if (bcs->mode == L1_MODE_TRANS)
hscx_fill_fifo(bcs);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
#ifdef ERROR_STATISTIC
bcs->err_tx++;
#endif
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->hw.hscx.count);
bcs->tx_cnt += bcs->hw.hscx.count;
bcs->hw.hscx.count = 0;
}
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
}
} else if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX A EXIR %x", exval);
}
if (val & 0x04) {
exval = READHSCX(cs, 0, HSCX_ISTA);
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX A interrupt %x", exval);
hscx_interrupt(cs, exval, 0);
}
}

View file

@ -1,680 +0,0 @@
/* $Id: icc.c,v 1.8.2.3 2004/01/13 14:31:25 keil Exp $
*
* ICC specific routines
*
* Author Matt Henderson & Guy Ellis
* Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* 1999.6.25 Initial implementation of routines for Siemens ISDN
* Communication Controller PEB 2070 based on the ISAC routines
* written by Karsten Keil.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "icc.h"
// #include "arcofi.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
#define DBUSY_TIMER_VALUE 80
#define ARCOFI_USE 0
static char *ICCVer[] =
{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
void
ICCVersion(struct IsdnCardState *cs, char *s)
{
int val;
val = cs->readisac(cs, ICC_RBCH);
printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]);
}
static void
ph_command(struct IsdnCardState *cs, unsigned int command)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ph_command %x", command);
cs->writeisac(cs, ICC_CIX0, (command << 2) | 3);
}
static void
icc_new_ph(struct IsdnCardState *cs)
{
switch (cs->dc.icc.ph_state) {
case (ICC_IND_EI1):
ph_command(cs, ICC_CMD_DI);
l1_msg(cs, HW_RESET | INDICATION, NULL);
break;
case (ICC_IND_DC):
l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
break;
case (ICC_IND_DR):
l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
break;
case (ICC_IND_PU):
l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
break;
case (ICC_IND_FJ):
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
break;
case (ICC_IND_AR):
l1_msg(cs, HW_INFO2 | INDICATION, NULL);
break;
case (ICC_IND_AI):
l1_msg(cs, HW_INFO4 | INDICATION, NULL);
break;
default:
break;
}
}
static void
icc_bh(struct work_struct *work)
{
struct IsdnCardState *cs =
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "D-Channel Busy cleared");
stptr = cs->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
stptr = stptr->next;
}
}
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
icc_new_ph(cs);
if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
DChannel_proc_rcv(cs);
if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
DChannel_proc_xmt(cs);
#if ARCOFI_USE
if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
return;
if (test_and_clear_bit(D_RX_MON1, &cs->event))
arcofi_fsm(cs, ARCOFI_RX_END, NULL);
if (test_and_clear_bit(D_TX_MON1, &cs->event))
arcofi_fsm(cs, ARCOFI_TX_END, NULL);
#endif
}
static void
icc_empty_fifo(struct IsdnCardState *cs, int count)
{
u_char *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "icc_empty_fifo");
if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "icc_empty_fifo overrun %d",
cs->rcvidx + count);
cs->writeisac(cs, ICC_CMDR, 0x80);
cs->rcvidx = 0;
return;
}
ptr = cs->rcvbuf + cs->rcvidx;
cs->rcvidx += count;
cs->readisacfifo(cs, ptr, count);
cs->writeisac(cs, ICC_CMDR, 0x80);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "icc_empty_fifo cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
static void
icc_fill_fifo(struct IsdnCardState *cs)
{
int count, more;
u_char *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "icc_fill_fifo");
if (!cs->tx_skb)
return;
count = cs->tx_skb->len;
if (count <= 0)
return;
more = 0;
if (count > 32) {
more = !0;
count = 32;
}
ptr = cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
cs->tx_cnt += count;
cs->writeisacfifo(cs, ptr, count);
cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa);
if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
debugl1(cs, "icc_fill_fifo dbusytimer running");
del_timer(&cs->dbusytimer);
}
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
add_timer(&cs->dbusytimer);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "icc_fill_fifo cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
void
icc_interrupt(struct IsdnCardState *cs, u_char val)
{
u_char exval, v1;
struct sk_buff *skb;
unsigned int count;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ICC interrupt %x", val);
if (val & 0x80) { /* RME */
exval = cs->readisac(cs, ICC_RSTA);
if ((exval & 0x70) != 0x20) {
if (exval & 0x40) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC RDO");
#ifdef ERROR_STATISTIC
cs->err_rx++;
#endif
}
if (!(exval & 0x20)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC CRC error");
#ifdef ERROR_STATISTIC
cs->err_crc++;
#endif
}
cs->writeisac(cs, ICC_CMDR, 0x80);
} else {
count = cs->readisac(cs, ICC_RBCL) & 0x1f;
if (count == 0)
count = 32;
icc_empty_fifo(cs, count);
if ((count = cs->rcvidx) > 0) {
cs->rcvidx = 0;
if (!(skb = alloc_skb(count, GFP_ATOMIC)))
printk(KERN_WARNING "HiSax: D receive out of memory\n");
else {
skb_put_data(skb, cs->rcvbuf, count);
skb_queue_tail(&cs->rq, skb);
}
}
}
cs->rcvidx = 0;
schedule_event(cs, D_RCVBUFREADY);
}
if (val & 0x40) { /* RPF */
icc_empty_fifo(cs, 32);
}
if (val & 0x20) { /* RSC */
/* never */
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC RSC interrupt");
}
if (val & 0x10) { /* XPR */
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) {
if (cs->tx_skb->len) {
icc_fill_fifo(cs);
goto afterXPR;
} else {
dev_kfree_skb_irq(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
}
}
if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
cs->tx_cnt = 0;
icc_fill_fifo(cs);
} else
schedule_event(cs, D_XMTBUFREADY);
}
afterXPR:
if (val & 0x04) { /* CISQ */
exval = cs->readisac(cs, ICC_CIR0);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ICC CIR0 %02X", exval);
if (exval & 2) {
cs->dc.icc.ph_state = (exval >> 2) & 0xf;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state);
schedule_event(cs, D_L1STATECHANGE);
}
if (exval & 1) {
exval = cs->readisac(cs, ICC_CIR1);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ICC CIR1 %02X", exval);
}
}
if (val & 0x02) { /* SIN */
/* never */
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC SIN interrupt");
}
if (val & 0x01) { /* EXI */
exval = cs->readisac(cs, ICC_EXIR);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC EXIR %02x", exval);
if (exval & 0x80) { /* XMR */
debugl1(cs, "ICC XMR");
printk(KERN_WARNING "HiSax: ICC XMR\n");
}
if (exval & 0x40) { /* XDU */
debugl1(cs, "ICC XDU");
printk(KERN_WARNING "HiSax: ICC XDU\n");
#ifdef ERROR_STATISTIC
cs->err_tx++;
#endif
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) { /* Restart frame */
skb_push(cs->tx_skb, cs->tx_cnt);
cs->tx_cnt = 0;
icc_fill_fifo(cs);
} else {
printk(KERN_WARNING "HiSax: ICC XDU no skb\n");
debugl1(cs, "ICC XDU no skb");
}
}
if (exval & 0x04) { /* MOS */
v1 = cs->readisac(cs, ICC_MOSR);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ICC MOSR %02x", v1);
#if ARCOFI_USE
if (v1 & 0x08) {
if (!cs->dc.icc.mon_rx) {
if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC MON RX out of memory!");
cs->dc.icc.mocr &= 0xf0;
cs->dc.icc.mocr |= 0x0a;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
goto afterMONR0;
} else
cs->dc.icc.mon_rxp = 0;
}
if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
cs->dc.icc.mocr &= 0xf0;
cs->dc.icc.mocr |= 0x0a;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mon_rxp = 0;
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC MON RX overflow!");
goto afterMONR0;
}
cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]);
if (cs->dc.icc.mon_rxp == 1) {
cs->dc.icc.mocr |= 0x04;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
}
}
afterMONR0:
if (v1 & 0x80) {
if (!cs->dc.icc.mon_rx) {
if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC MON RX out of memory!");
cs->dc.icc.mocr &= 0x0f;
cs->dc.icc.mocr |= 0xa0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
goto afterMONR1;
} else
cs->dc.icc.mon_rxp = 0;
}
if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
cs->dc.icc.mocr &= 0x0f;
cs->dc.icc.mocr |= 0xa0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mon_rxp = 0;
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC MON RX overflow!");
goto afterMONR1;
}
cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]);
cs->dc.icc.mocr |= 0x40;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
}
afterMONR1:
if (v1 & 0x04) {
cs->dc.icc.mocr &= 0xf0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mocr |= 0x0a;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
schedule_event(cs, D_RX_MON0);
}
if (v1 & 0x40) {
cs->dc.icc.mocr &= 0x0f;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mocr |= 0xa0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
schedule_event(cs, D_RX_MON1);
}
if (v1 & 0x02) {
if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
!(v1 & 0x08))) {
cs->dc.icc.mocr &= 0xf0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mocr |= 0x0a;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
if (cs->dc.icc.mon_txc &&
(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
schedule_event(cs, D_TX_MON0);
goto AfterMOX0;
}
if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
schedule_event(cs, D_TX_MON0);
goto AfterMOX0;
}
cs->writeisac(cs, ICC_MOX0,
cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]);
}
AfterMOX0:
if (v1 & 0x20) {
if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
!(v1 & 0x80))) {
cs->dc.icc.mocr &= 0x0f;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mocr |= 0xa0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
if (cs->dc.icc.mon_txc &&
(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
schedule_event(cs, D_TX_MON1);
goto AfterMOX1;
}
if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
schedule_event(cs, D_TX_MON1);
goto AfterMOX1;
}
cs->writeisac(cs, ICC_MOX1,
cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]);
}
AfterMOX1: ;
#endif
}
}
}
static void
ICC_l1hw(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
struct sk_buff *skb = arg;
u_long flags;
int val;
switch (pr) {
case (PH_DATA | REQUEST):
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
skb_queue_tail(&cs->sq, skb);
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA Queued", 0);
#endif
} else {
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA", 0);
#endif
icc_fill_fifo(cs);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
skb_queue_tail(&cs->sq, skb);
spin_unlock_irqrestore(&cs->lock, flags);
break;
}
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
#endif
icc_fill_fifo(cs);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | REQUEST):
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
debugl1(cs, "-> PH_REQUEST_PULL");
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (HW_RESET | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
if ((cs->dc.icc.ph_state == ICC_IND_EI1) ||
(cs->dc.icc.ph_state == ICC_IND_DR))
ph_command(cs, ICC_CMD_DI);
else
ph_command(cs, ICC_CMD_RES);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_ENABLE | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
ph_command(cs, ICC_CMD_DI);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_INFO1 | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
ph_command(cs, ICC_CMD_AR);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_INFO3 | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
ph_command(cs, ICC_CMD_AI);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_TESTLOOP | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
val = 0;
if (1 & (long) arg)
val |= 0x0c;
if (2 & (long) arg)
val |= 0x3;
if (test_bit(HW_IOM1, &cs->HW_Flags)) {
/* IOM 1 Mode */
if (!val) {
cs->writeisac(cs, ICC_SPCR, 0xa);
cs->writeisac(cs, ICC_ADF1, 0x2);
} else {
cs->writeisac(cs, ICC_SPCR, val);
cs->writeisac(cs, ICC_ADF1, 0xa);
}
} else {
/* IOM 2 Mode */
cs->writeisac(cs, ICC_SPCR, val);
if (val)
cs->writeisac(cs, ICC_ADF1, 0x8);
else
cs->writeisac(cs, ICC_ADF1, 0x0);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_DEACTIVATE | RESPONSE):
skb_queue_purge(&cs->rq);
skb_queue_purge(&cs->sq);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
}
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
break;
default:
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "icc_l1hw unknown %04x", pr);
break;
}
}
static void
setstack_icc(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = ICC_l1hw;
}
static void
DC_Close_icc(struct IsdnCardState *cs) {
kfree(cs->dc.icc.mon_rx);
cs->dc.icc.mon_rx = NULL;
kfree(cs->dc.icc.mon_tx);
cs->dc.icc.mon_tx = NULL;
}
static void
dbusy_timer_handler(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
struct PStack *stptr;
int rbch, star;
if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
rbch = cs->readisac(cs, ICC_RBCH);
star = cs->readisac(cs, ICC_STAR);
if (cs->debug)
debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
rbch, star);
if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */
test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
stptr = cs->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
stptr = stptr->next;
}
} else {
/* discard frame; reset transceiver */
test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
} else {
printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n");
debugl1(cs, "D-Channel Busy no skb");
}
cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */
cs->irq_func(cs->irq, cs);
}
}
}
void
initicc(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_icc;
cs->DC_Close = DC_Close_icc;
cs->dc.icc.mon_tx = NULL;
cs->dc.icc.mon_rx = NULL;
cs->writeisac(cs, ICC_MASK, 0xff);
cs->dc.icc.mocr = 0xaa;
if (test_bit(HW_IOM1, &cs->HW_Flags)) {
/* IOM 1 Mode */
cs->writeisac(cs, ICC_ADF2, 0x0);
cs->writeisac(cs, ICC_SPCR, 0xa);
cs->writeisac(cs, ICC_ADF1, 0x2);
cs->writeisac(cs, ICC_STCR, 0x70);
cs->writeisac(cs, ICC_MODE, 0xc9);
} else {
/* IOM 2 Mode */
if (!cs->dc.icc.adf2)
cs->dc.icc.adf2 = 0x80;
cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2);
cs->writeisac(cs, ICC_SQXR, 0xa0);
cs->writeisac(cs, ICC_SPCR, 0x20);
cs->writeisac(cs, ICC_STCR, 0x70);
cs->writeisac(cs, ICC_MODE, 0xca);
cs->writeisac(cs, ICC_TIMR, 0x00);
cs->writeisac(cs, ICC_ADF1, 0x20);
}
ph_command(cs, ICC_CMD_RES);
cs->writeisac(cs, ICC_MASK, 0x0);
ph_command(cs, ICC_CMD_DI);
}
void
clear_pending_icc_ints(struct IsdnCardState *cs)
{
int val, eval;
val = cs->readisac(cs, ICC_STAR);
debugl1(cs, "ICC STAR %x", val);
val = cs->readisac(cs, ICC_MODE);
debugl1(cs, "ICC MODE %x", val);
val = cs->readisac(cs, ICC_ADF2);
debugl1(cs, "ICC ADF2 %x", val);
val = cs->readisac(cs, ICC_ISTA);
debugl1(cs, "ICC ISTA %x", val);
if (val & 0x01) {
eval = cs->readisac(cs, ICC_EXIR);
debugl1(cs, "ICC EXIR %x", eval);
}
val = cs->readisac(cs, ICC_CIR0);
debugl1(cs, "ICC CIR0 %x", val);
cs->dc.icc.ph_state = (val >> 2) & 0xf;
schedule_event(cs, D_L1STATECHANGE);
/* Disable all IRQ */
cs->writeisac(cs, ICC_MASK, 0xFF);
}
void setup_icc(struct IsdnCardState *cs)
{
INIT_WORK(&cs->tqueue, icc_bh);
timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
}

View file

@ -1,72 +0,0 @@
/* $Id: icc.h,v 1.4.2.2 2004/01/12 22:52:26 keil Exp $
*
* ICC specific routines
*
* Author Matt Henderson & Guy Ellis
* Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* 1999.7.14 Initial implementation of routines for Siemens ISDN
* Communication Controller PEB 2070 based on the ISAC routines
* written by Karsten Keil.
*/
/* All Registers original Siemens Spec */
#define ICC_MASK 0x20
#define ICC_ISTA 0x20
#define ICC_STAR 0x21
#define ICC_CMDR 0x21
#define ICC_EXIR 0x24
#define ICC_ADF2 0x39
#define ICC_SPCR 0x30
#define ICC_ADF1 0x38
#define ICC_CIR0 0x31
#define ICC_CIX0 0x31
#define ICC_CIR1 0x33
#define ICC_CIX1 0x33
#define ICC_STCR 0x37
#define ICC_MODE 0x22
#define ICC_RSTA 0x27
#define ICC_RBCL 0x25
#define ICC_RBCH 0x2A
#define ICC_TIMR 0x23
#define ICC_SQXR 0x3b
#define ICC_MOSR 0x3a
#define ICC_MOCR 0x3a
#define ICC_MOR0 0x32
#define ICC_MOX0 0x32
#define ICC_MOR1 0x34
#define ICC_MOX1 0x34
#define ICC_RBCH_XAC 0x80
#define ICC_CMD_TIM 0x0
#define ICC_CMD_RES 0x1
#define ICC_CMD_DU 0x3
#define ICC_CMD_EI1 0x4
#define ICC_CMD_SSP 0x5
#define ICC_CMD_DT 0x6
#define ICC_CMD_AR 0x8
#define ICC_CMD_ARL 0xA
#define ICC_CMD_AI 0xC
#define ICC_CMD_DI 0xF
#define ICC_IND_DR 0x0
#define ICC_IND_FJ 0x2
#define ICC_IND_EI1 0x4
#define ICC_IND_INT 0x6
#define ICC_IND_PU 0x7
#define ICC_IND_AR 0x8
#define ICC_IND_ARL 0xA
#define ICC_IND_AI 0xC
#define ICC_IND_AIL 0xE
#define ICC_IND_DC 0xF
extern void ICCVersion(struct IsdnCardState *cs, char *s);
extern void initicc(struct IsdnCardState *cs);
extern void icc_interrupt(struct IsdnCardState *cs, u_char val);
extern void clear_pending_icc_ints(struct IsdnCardState *cs);
extern void setup_icc(struct IsdnCardState *);

View file

@ -1,29 +0,0 @@
/* $Id: ipac.h,v 1.7.2.2 2004/01/12 22:52:26 keil Exp $
*
* IPAC specific defines
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/* All Registers original Siemens Spec */
#define IPAC_CONF 0xC0
#define IPAC_MASK 0xC1
#define IPAC_ISTA 0xC1
#define IPAC_ID 0xC2
#define IPAC_ACFG 0xC3
#define IPAC_AOE 0xC4
#define IPAC_ARX 0xC5
#define IPAC_ATX 0xC5
#define IPAC_PITA1 0xC6
#define IPAC_PITA2 0xC7
#define IPAC_POTA1 0xC8
#define IPAC_POTA2 0xC9
#define IPAC_PCFG 0xCA
#define IPAC_SCFG 0xCB
#define IPAC_TIMR2 0xCC

View file

@ -1,913 +0,0 @@
/*
*
* IPACX specific routines
*
* Author Joerg Petersohn
* Derived from hisax_isac.c, isac.c, hscx.c and others
*
* 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/slab.h>
#include <linux/init.h>
#include "hisax_if.h"
#include "hisax.h"
#include "isdnl1.h"
#include "ipacx.h"
#define DBUSY_TIMER_VALUE 80
#define TIMER3_VALUE 7000
#define MAX_DFRAME_LEN_L1 300
#define B_FIFO_SIZE 64
#define D_FIFO_SIZE 32
// ipacx interrupt mask values
#define _MASK_IMASK 0x2E // global mask
#define _MASKB_IMASK 0x0B
#define _MASKD_IMASK 0x03 // all on
//----------------------------------------------------------
// local function declarations
//----------------------------------------------------------
static void ph_command(struct IsdnCardState *cs, unsigned int command);
static inline void cic_int(struct IsdnCardState *cs);
static void dch_l2l1(struct PStack *st, int pr, void *arg);
static void dbusy_timer_handler(struct timer_list *t);
static void dch_empty_fifo(struct IsdnCardState *cs, int count);
static void dch_fill_fifo(struct IsdnCardState *cs);
static inline void dch_int(struct IsdnCardState *cs);
static void dch_setstack(struct PStack *st, struct IsdnCardState *cs);
static void dch_init(struct IsdnCardState *cs);
static void bch_l2l1(struct PStack *st, int pr, void *arg);
static void bch_empty_fifo(struct BCState *bcs, int count);
static void bch_fill_fifo(struct BCState *bcs);
static void bch_int(struct IsdnCardState *cs, u_char hscx);
static void bch_mode(struct BCState *bcs, int mode, int bc);
static void bch_close_state(struct BCState *bcs);
static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);
static int bch_setstack(struct PStack *st, struct BCState *bcs);
static void bch_init(struct IsdnCardState *cs, int hscx);
static void clear_pending_ints(struct IsdnCardState *cs);
//----------------------------------------------------------
// Issue Layer 1 command to chip
//----------------------------------------------------------
static void
ph_command(struct IsdnCardState *cs, unsigned int command)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ph_command (%#x) in (%#x)", command,
cs->dc.isac.ph_state);
//###################################
// printk(KERN_INFO "ph_command (%#x)\n", command);
//###################################
cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E);
}
//----------------------------------------------------------
// Transceiver interrupt handler
//----------------------------------------------------------
static inline void
cic_int(struct IsdnCardState *cs)
{
u_char event;
event = cs->readisac(cs, IPACX_CIR0) >> 4;
if (cs->debug & L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event);
//#########################################
// printk(KERN_INFO "cic_int(%x)\n", event);
//#########################################
cs->dc.isac.ph_state = event;
schedule_event(cs, D_L1STATECHANGE);
}
//==========================================================
// D channel functions
//==========================================================
//----------------------------------------------------------
// Command entry point
//----------------------------------------------------------
static void
dch_l2l1(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
struct sk_buff *skb = arg;
u_char cda1_cr;
switch (pr) {
case (PH_DATA | REQUEST):
if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
if (cs->tx_skb) {
skb_queue_tail(&cs->sq, skb);
#ifdef L2FRAME_DEBUG
if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0);
#endif
} else {
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG
if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0);
#endif
dch_fill_fifo(cs);
}
break;
case (PH_PULL | INDICATION):
if (cs->tx_skb) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
skb_queue_tail(&cs->sq, skb);
break;
}
if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG
if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
#endif
dch_fill_fifo(cs);
break;
case (PH_PULL | REQUEST):
#ifdef L2FRAME_DEBUG
if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL");
#endif
if (!cs->tx_skb) {
clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (HW_RESET | REQUEST):
case (HW_ENABLE | REQUEST):
if ((cs->dc.isac.ph_state == IPACX_IND_RES) ||
(cs->dc.isac.ph_state == IPACX_IND_DR) ||
(cs->dc.isac.ph_state == IPACX_IND_DC))
ph_command(cs, IPACX_CMD_TIM);
else
ph_command(cs, IPACX_CMD_RES);
break;
case (HW_INFO3 | REQUEST):
ph_command(cs, IPACX_CMD_AR8);
break;
case (HW_TESTLOOP | REQUEST):
cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1
cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1
cda1_cr = cs->readisac(cs, IPACX_CDA1_CR);
(void) cs->readisac(cs, IPACX_CDA2_CR);
if ((long)arg & 1) { // loop B1
cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x0a);
}
else { // B1 off
cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x0a);
}
if ((long)arg & 2) { // loop B2
cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x14);
}
else { // B2 off
cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x14);
}
break;
case (HW_DEACTIVATE | RESPONSE):
skb_queue_purge(&cs->rq);
skb_queue_purge(&cs->sq);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
}
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
break;
default:
if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr);
break;
}
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
dbusy_timer_handler(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
struct PStack *st;
int rbchd, stard;
if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
rbchd = cs->readisac(cs, IPACX_RBCHD);
stard = cs->readisac(cs, IPACX_STARD);
if (cs->debug)
debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard);
if (!(stard & 0x40)) { // D-Channel Busy
set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
for (st = cs->stlist; st; st = st->next) {
st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on
}
} else {
// seems we lost an interrupt; reset transceiver */
clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
} else {
printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
debugl1(cs, "D-Channel Busy no skb");
}
cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR
}
}
}
//----------------------------------------------------------
// Fill buffer from receive FIFO
//----------------------------------------------------------
static void
dch_empty_fifo(struct IsdnCardState *cs, int count)
{
u_char *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "dch_empty_fifo()");
// message too large, remove
if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "dch_empty_fifo() incoming message too large");
cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
cs->rcvidx = 0;
return;
}
ptr = cs->rcvbuf + cs->rcvidx;
cs->rcvidx += count;
cs->readisacfifo(cs, ptr, count);
cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "dch_empty_fifo() cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
//----------------------------------------------------------
// Fill transmit FIFO
//----------------------------------------------------------
static void
dch_fill_fifo(struct IsdnCardState *cs)
{
int count;
u_char cmd, *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "dch_fill_fifo()");
if (!cs->tx_skb) return;
count = cs->tx_skb->len;
if (count <= 0) return;
if (count > D_FIFO_SIZE) {
count = D_FIFO_SIZE;
cmd = 0x08; // XTF
} else {
cmd = 0x0A; // XTF | XME
}
ptr = cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
cs->tx_cnt += count;
cs->writeisacfifo(cs, ptr, count);
cs->writeisac(cs, IPACX_CMDRD, cmd);
// set timeout for transmission contol
if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
debugl1(cs, "dch_fill_fifo dbusytimer running");
del_timer(&cs->dbusytimer);
}
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
add_timer(&cs->dbusytimer);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "dch_fill_fifo() cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
//----------------------------------------------------------
// D channel interrupt handler
//----------------------------------------------------------
static inline void
dch_int(struct IsdnCardState *cs)
{
struct sk_buff *skb;
u_char istad, rstad;
int count;
istad = cs->readisac(cs, IPACX_ISTAD);
//##############################################
// printk(KERN_WARNING "dch_int(istad=%02x)\n", istad);
//##############################################
if (istad & 0x80) { // RME
rstad = cs->readisac(cs, IPACX_RSTAD);
if ((rstad & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
if (!(rstad & 0x80))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "dch_int(): invalid frame");
if ((rstad & 0x40))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "dch_int(): RDO");
if (!(rstad & 0x20))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "dch_int(): CRC error");
cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
} else { // received frame ok
count = cs->readisac(cs, IPACX_RBCLD);
if (count) count--; // RSTAB is last byte
count &= D_FIFO_SIZE - 1;
if (count == 0) count = D_FIFO_SIZE;
dch_empty_fifo(cs, count);
if ((count = cs->rcvidx) > 0) {
cs->rcvidx = 0;
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n");
else {
skb_put_data(skb, cs->rcvbuf, count);
skb_queue_tail(&cs->rq, skb);
}
}
}
cs->rcvidx = 0;
schedule_event(cs, D_RCVBUFREADY);
}
if (istad & 0x40) { // RPF
dch_empty_fifo(cs, D_FIFO_SIZE);
}
if (istad & 0x20) { // RFO
if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): RFO");
cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES
}
if (istad & 0x10) { // XPR
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) {
if (cs->tx_skb->len) {
dch_fill_fifo(cs);
goto afterXPR;
}
else {
dev_kfree_skb_irq(cs->tx_skb);
cs->tx_skb = NULL;
cs->tx_cnt = 0;
}
}
if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
cs->tx_cnt = 0;
dch_fill_fifo(cs);
}
else {
schedule_event(cs, D_XMTBUFREADY);
}
}
afterXPR:
if (istad & 0x0C) { // XDU or XMR
if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): XDU");
if (cs->tx_skb) {
skb_push(cs->tx_skb, cs->tx_cnt); // retransmit
cs->tx_cnt = 0;
dch_fill_fifo(cs);
} else {
printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
debugl1(cs, "ISAC XDU no skb");
}
}
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
dch_setstack(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = dch_l2l1;
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
dch_init(struct IsdnCardState *cs)
{
printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
cs->setstack_d = dch_setstack;
timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
cs->writeisac(cs, IPACX_TR_CONF0, 0x00); // clear LDD
cs->writeisac(cs, IPACX_TR_CONF2, 0x00); // enable transmitter
cs->writeisac(cs, IPACX_MODED, 0xC9); // transparent mode 0, RAC, stop/go
cs->writeisac(cs, IPACX_MON_CR, 0x00); // disable monitor channel
}
//==========================================================
// B channel functions
//==========================================================
//----------------------------------------------------------
// Entry point for commands
//----------------------------------------------------------
static void
bch_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
struct sk_buff *skb = arg;
u_long flags;
switch (pr) {
case (PH_DATA | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->hw.hscx.count = 0;
bch_fill_fifo(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n");
} else {
set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->tx_skb = skb;
bcs->hw.hscx.count = 0;
bch_fill_fifo(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | REQUEST):
if (!bcs->tx_skb) {
clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (PH_ACTIVATE | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
set_bit(BC_FLG_ACTIV, &bcs->Flag);
bch_mode(bcs, st->l1.mode, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
spin_lock_irqsave(&bcs->cs->lock, flags);
clear_bit(BC_FLG_ACTIV, &bcs->Flag);
clear_bit(BC_FLG_BUSY, &bcs->Flag);
bch_mode(bcs, 0, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
//----------------------------------------------------------
// Read B channel fifo to receive buffer
//----------------------------------------------------------
static void
bch_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr, hscx;
struct IsdnCardState *cs;
int cnt;
cs = bcs->cs;
hscx = bcs->hw.hscx.hscx;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "bch_empty_fifo()");
// message too large, remove
if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_empty_fifo() incoming packet too large");
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
bcs->hw.hscx.rcvidx = 0;
return;
}
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
cnt = count;
while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB);
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
bcs->hw.hscx.rcvidx += count;
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", bcs->blog);
}
}
//----------------------------------------------------------
// Fill buffer to transmit FIFO
//----------------------------------------------------------
static void
bch_fill_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs;
int more, count, cnt;
u_char *ptr, *p, hscx;
cs = bcs->cs;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "bch_fill_fifo()");
if (!bcs->tx_skb) return;
if (bcs->tx_skb->len <= 0) return;
hscx = bcs->hw.hscx.hscx;
more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
if (bcs->tx_skb->len > B_FIFO_SIZE) {
more = 1;
count = B_FIFO_SIZE;
} else {
count = bcs->tx_skb->len;
}
cnt = count;
p = ptr = bcs->tx_skb->data;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.hscx.count += count;
while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++);
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a));
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "%s() B-%d cnt %d", __func__, hscx, count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", bcs->blog);
}
}
//----------------------------------------------------------
// B channel interrupt handler
//----------------------------------------------------------
static void
bch_int(struct IsdnCardState *cs, u_char hscx)
{
u_char istab;
struct BCState *bcs;
struct sk_buff *skb;
int count;
u_char rstab;
bcs = cs->bcs + hscx;
istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB);
//##############################################
// printk(KERN_WARNING "bch_int(istab=%02x)\n", istab);
//##############################################
if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return;
if (istab & 0x80) { // RME
rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB);
if ((rstab & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
if (!(rstab & 0x80))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d: invalid frame", hscx);
if ((rstab & 0x40) && (bcs->mode != L1_MODE_NULL))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode);
if (!(rstab & 0x20))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d: CRC error", hscx);
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
}
else { // received frame ok
count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) & (B_FIFO_SIZE - 1);
if (count == 0) count = B_FIFO_SIZE;
bch_empty_fifo(bcs, count);
if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
if (cs->debug & L1_DEB_HSCX_FIFO)
debugl1(cs, "bch_int Frame %d", count);
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n");
else {
skb_put_data(skb, bcs->hw.hscx.rcvbuf,
count);
skb_queue_tail(&bcs->rqueue, skb);
}
}
}
bcs->hw.hscx.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
}
if (istab & 0x40) { // RPF
bch_empty_fifo(bcs, B_FIFO_SIZE);
if (bcs->mode == L1_MODE_TRANS) { // queue every chunk
// receive transparent audio data
if (!(skb = dev_alloc_skb(B_FIFO_SIZE)))
printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n");
else {
skb_put_data(skb, bcs->hw.hscx.rcvbuf,
B_FIFO_SIZE);
skb_queue_tail(&bcs->rqueue, skb);
}
bcs->hw.hscx.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
}
}
if (istab & 0x20) { // RFO
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d: RFO error", hscx);
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES
}
if (istab & 0x10) { // XPR
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
bch_fill_fifo(bcs);
goto afterXPR;
} else {
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += bcs->hw.hscx.count;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
}
dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL;
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
bcs->hw.hscx.count = 0;
set_bit(BC_FLG_BUSY, &bcs->Flag);
bch_fill_fifo(bcs);
} else {
clear_bit(BC_FLG_BUSY, &bcs->Flag);
schedule_event(bcs, B_XMTBUFREADY);
}
}
afterXPR:
if (istab & 0x04) { // XDU
if (bcs->mode == L1_MODE_TRANS) {
bch_fill_fifo(bcs);
}
else {
if (bcs->tx_skb) { // restart transmitting the whole frame
skb_push(bcs->tx_skb, bcs->hw.hscx.count);
bcs->tx_cnt += bcs->hw.hscx.count;
bcs->hw.hscx.count = 0;
}
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d XDU error", hscx);
}
}
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
bch_mode(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
int hscx = bcs->hw.hscx.hscx;
bc = bc ? 1 : 0; // in case bc is greater than 1
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "mode_bch() switch B-%d mode %d chan %d", hscx, mode, bc);
bcs->mode = mode;
bcs->channel = bc;
// map controller to according timeslot
if (!hscx)
{
cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc);
cs->writeisac(cs, IPACX_BCHA_CR, 0x88);
}
else
{
cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc);
cs->writeisac(cs, IPACX_BCHB_CR, 0x88);
}
switch (mode) {
case (L1_MODE_NULL):
cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0); // rec off
cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x30); // std adj.
cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF); // ints off
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
break;
case (L1_MODE_TRANS):
cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88); // ext transp mode
cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x00); // xxx00000
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
break;
case (L1_MODE_HDLC):
cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8); // transp mode 0
cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x01); // idle=hdlc flags crc enabled
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
break;
}
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
bch_close_state(struct BCState *bcs)
{
bch_mode(bcs, 0, bcs->channel);
if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
kfree(bcs->blog);
bcs->blog = NULL;
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
}
//----------------------------------------------------------
//----------------------------------------------------------
static int
bch_open_state(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax open_bchstate(): No memory for hscx.rcvbuf\n");
clear_bit(BC_FLG_INIT, &bcs->Flag);
return (1);
}
if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax open_bchstate: No memory for bcs->blog\n");
clear_bit(BC_FLG_INIT, &bcs->Flag);
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
return (2);
}
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->hw.hscx.rcvidx = 0;
bcs->tx_cnt = 0;
return (0);
}
//----------------------------------------------------------
//----------------------------------------------------------
static int
bch_setstack(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
if (bch_open_state(st->l1.hardware, bcs)) return (-1);
st->l1.bcs = bcs;
st->l2.l2l1 = bch_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
bch_init(struct IsdnCardState *cs, int hscx)
{
cs->bcs[hscx].BC_SetStack = bch_setstack;
cs->bcs[hscx].BC_Close = bch_close_state;
cs->bcs[hscx].hw.hscx.hscx = hscx;
cs->bcs[hscx].cs = cs;
bch_mode(cs->bcs + hscx, 0, hscx);
}
//==========================================================
// Shared functions
//==========================================================
//----------------------------------------------------------
// Main interrupt handler
//----------------------------------------------------------
void
interrupt_ipacx(struct IsdnCardState *cs)
{
u_char ista;
while ((ista = cs->readisac(cs, IPACX_ISTA))) {
//#################################################
// printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista);
//#################################################
if (ista & 0x80) bch_int(cs, 0); // B channel interrupts
if (ista & 0x40) bch_int(cs, 1);
if (ista & 0x01) dch_int(cs); // D channel
if (ista & 0x10) cic_int(cs); // Layer 1 state
}
}
//----------------------------------------------------------
// Clears chip interrupt status
//----------------------------------------------------------
static void
clear_pending_ints(struct IsdnCardState *cs)
{
int ista;
// all interrupts off
cs->writeisac(cs, IPACX_MASK, 0xff);
cs->writeisac(cs, IPACX_MASKD, 0xff);
cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff);
cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff);
ista = cs->readisac(cs, IPACX_ISTA);
if (ista & 0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB);
if (ista & 0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB);
if (ista & 0x10) cs->readisac(cs, IPACX_CIR0);
if (ista & 0x01) cs->readisac(cs, IPACX_ISTAD);
}
//----------------------------------------------------------
// Does chip configuration work
// Work to do depends on bit mask in part
//----------------------------------------------------------
void
init_ipacx(struct IsdnCardState *cs, int part)
{
if (part & 1) { // initialise chip
//##################################################
// printk(KERN_INFO "init_ipacx(%x)\n", part);
//##################################################
clear_pending_ints(cs);
bch_init(cs, 0);
bch_init(cs, 1);
dch_init(cs);
}
if (part & 2) { // reenable all interrupts and start chip
cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK);
cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK);
cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK);
cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register
// reset HDLC Transmitters/receivers
cs->writeisac(cs, IPACX_CMDRD, 0x41);
cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41);
cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41);
ph_command(cs, IPACX_CMD_RES);
}
}
//----------------- end of file -----------------------

View file

@ -1,162 +0,0 @@
/*
*
* IPACX specific defines
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/* All Registers original Siemens Spec */
#ifndef INCLUDE_IPACX_H
#define INCLUDE_IPACX_H
/* D-channel registers */
#define IPACX_RFIFOD 0x00 /* RD */
#define IPACX_XFIFOD 0x00 /* WR */
#define IPACX_ISTAD 0x20 /* RD */
#define IPACX_MASKD 0x20 /* WR */
#define IPACX_STARD 0x21 /* RD */
#define IPACX_CMDRD 0x21 /* WR */
#define IPACX_MODED 0x22 /* RD/WR */
#define IPACX_EXMD1 0x23 /* RD/WR */
#define IPACX_TIMR1 0x24 /* RD/WR */
#define IPACX_SAP1 0x25 /* WR */
#define IPACX_SAP2 0x26 /* WR */
#define IPACX_RBCLD 0x26 /* RD */
#define IPACX_RBCHD 0x27 /* RD */
#define IPACX_TEI1 0x27 /* WR */
#define IPACX_TEI2 0x28 /* WR */
#define IPACX_RSTAD 0x28 /* RD */
#define IPACX_TMD 0x29 /* RD/WR */
#define IPACX_CIR0 0x2E /* RD */
#define IPACX_CIX0 0x2E /* WR */
#define IPACX_CIR1 0x2F /* RD */
#define IPACX_CIX1 0x2F /* WR */
/* Transceiver registers */
#define IPACX_TR_CONF0 0x30 /* RD/WR */
#define IPACX_TR_CONF1 0x31 /* RD/WR */
#define IPACX_TR_CONF2 0x32 /* RD/WR */
#define IPACX_TR_STA 0x33 /* RD */
#define IPACX_TR_CMD 0x34 /* RD/WR */
#define IPACX_SQRR1 0x35 /* RD */
#define IPACX_SQXR1 0x35 /* WR */
#define IPACX_SQRR2 0x36 /* RD */
#define IPACX_SQXR2 0x36 /* WR */
#define IPACX_SQRR3 0x37 /* RD */
#define IPACX_SQXR3 0x37 /* WR */
#define IPACX_ISTATR 0x38 /* RD */
#define IPACX_MASKTR 0x39 /* RD/WR */
#define IPACX_TR_MODE 0x3A /* RD/WR */
#define IPACX_ACFG1 0x3C /* RD/WR */
#define IPACX_ACFG2 0x3D /* RD/WR */
#define IPACX_AOE 0x3E /* RD/WR */
#define IPACX_ARX 0x3F /* RD */
#define IPACX_ATX 0x3F /* WR */
/* IOM: Timeslot, DPS, CDA */
#define IPACX_CDA10 0x40 /* RD/WR */
#define IPACX_CDA11 0x41 /* RD/WR */
#define IPACX_CDA20 0x42 /* RD/WR */
#define IPACX_CDA21 0x43 /* RD/WR */
#define IPACX_CDA_TSDP10 0x44 /* RD/WR */
#define IPACX_CDA_TSDP11 0x45 /* RD/WR */
#define IPACX_CDA_TSDP20 0x46 /* RD/WR */
#define IPACX_CDA_TSDP21 0x47 /* RD/WR */
#define IPACX_BCHA_TSDP_BC1 0x48 /* RD/WR */
#define IPACX_BCHA_TSDP_BC2 0x49 /* RD/WR */
#define IPACX_BCHB_TSDP_BC1 0x4A /* RD/WR */
#define IPACX_BCHB_TSDP_BC2 0x4B /* RD/WR */
#define IPACX_TR_TSDP_BC1 0x4C /* RD/WR */
#define IPACX_TR_TSDP_BC2 0x4D /* RD/WR */
#define IPACX_CDA1_CR 0x4E /* RD/WR */
#define IPACX_CDA2_CR 0x4F /* RD/WR */
/* IOM: Contol, Sync transfer, Monitor */
#define IPACX_TR_CR 0x50 /* RD/WR */
#define IPACX_TRC_CR 0x50 /* RD/WR */
#define IPACX_BCHA_CR 0x51 /* RD/WR */
#define IPACX_BCHB_CR 0x52 /* RD/WR */
#define IPACX_DCI_CR 0x53 /* RD/WR */
#define IPACX_DCIC_CR 0x53 /* RD/WR */
#define IPACX_MON_CR 0x54 /* RD/WR */
#define IPACX_SDS1_CR 0x55 /* RD/WR */
#define IPACX_SDS2_CR 0x56 /* RD/WR */
#define IPACX_IOM_CR 0x57 /* RD/WR */
#define IPACX_STI 0x58 /* RD */
#define IPACX_ASTI 0x58 /* WR */
#define IPACX_MSTI 0x59 /* RD/WR */
#define IPACX_SDS_CONF 0x5A /* RD/WR */
#define IPACX_MCDA 0x5B /* RD */
#define IPACX_MOR 0x5C /* RD */
#define IPACX_MOX 0x5C /* WR */
#define IPACX_MOSR 0x5D /* RD */
#define IPACX_MOCR 0x5E /* RD/WR */
#define IPACX_MSTA 0x5F /* RD */
#define IPACX_MCONF 0x5F /* WR */
/* Interrupt and general registers */
#define IPACX_ISTA 0x60 /* RD */
#define IPACX_MASK 0x60 /* WR */
#define IPACX_AUXI 0x61 /* RD */
#define IPACX_AUXM 0x61 /* WR */
#define IPACX_MODE1 0x62 /* RD/WR */
#define IPACX_MODE2 0x63 /* RD/WR */
#define IPACX_ID 0x64 /* RD */
#define IPACX_SRES 0x64 /* WR */
#define IPACX_TIMR2 0x65 /* RD/WR */
/* B-channel registers */
#define IPACX_OFF_B1 0x70
#define IPACX_OFF_B2 0x80
#define IPACX_ISTAB 0x00 /* RD */
#define IPACX_MASKB 0x00 /* WR */
#define IPACX_STARB 0x01 /* RD */
#define IPACX_CMDRB 0x01 /* WR */
#define IPACX_MODEB 0x02 /* RD/WR */
#define IPACX_EXMB 0x03 /* RD/WR */
#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 /* RD/WR */
#define IPACX_RFIFOB 0x0A /*- RD */
#define IPACX_XFIFOB 0x0A /*- WR */
/* Layer 1 Commands */
#define IPACX_CMD_TIM 0x0
#define IPACX_CMD_RES 0x1
#define IPACX_CMD_SSP 0x2
#define IPACX_CMD_SCP 0x3
#define IPACX_CMD_AR8 0x8
#define IPACX_CMD_AR10 0x9
#define IPACX_CMD_ARL 0xa
#define IPACX_CMD_DI 0xf
/* Layer 1 Indications */
#define IPACX_IND_DR 0x0
#define IPACX_IND_RES 0x1
#define IPACX_IND_TMA 0x2
#define IPACX_IND_SLD 0x3
#define IPACX_IND_RSY 0x4
#define IPACX_IND_DR6 0x5
#define IPACX_IND_PU 0x7
#define IPACX_IND_AR 0x8
#define IPACX_IND_ARL 0xa
#define IPACX_IND_CVR 0xb
#define IPACX_IND_AI8 0xc
#define IPACX_IND_AI10 0xd
#define IPACX_IND_AIL 0xe
#define IPACX_IND_DC 0xf
extern void init_ipacx(struct IsdnCardState *, int);
extern void interrupt_ipacx(struct IsdnCardState *);
extern void setup_isac(struct IsdnCardState *);
#endif

View file

@ -1,681 +0,0 @@
/* $Id: isac.c,v 1.31.2.3 2004/01/13 14:31:25 keil Exp $
*
* ISAC specific routines
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* For changes and modifications please read
* Documentation/isdn/HiSax.cert
*
*/
#include "hisax.h"
#include "isac.h"
#include "arcofi.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/init.h>
#define DBUSY_TIMER_VALUE 80
#define ARCOFI_USE 1
static char *ISACVer[] =
{"2086/2186 V1.1", "2085 B1", "2085 B2",
"2085 V2.3"};
void ISACVersion(struct IsdnCardState *cs, char *s)
{
int val;
val = cs->readisac(cs, ISAC_RBCH);
printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]);
}
static void
ph_command(struct IsdnCardState *cs, unsigned int command)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ph_command %x", command);
cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3);
}
static void
isac_new_ph(struct IsdnCardState *cs)
{
switch (cs->dc.isac.ph_state) {
case (ISAC_IND_RS):
case (ISAC_IND_EI):
ph_command(cs, ISAC_CMD_DUI);
l1_msg(cs, HW_RESET | INDICATION, NULL);
break;
case (ISAC_IND_DID):
l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
break;
case (ISAC_IND_DR):
l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
break;
case (ISAC_IND_PU):
l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
break;
case (ISAC_IND_RSY):
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
break;
case (ISAC_IND_ARD):
l1_msg(cs, HW_INFO2 | INDICATION, NULL);
break;
case (ISAC_IND_AI8):
l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
break;
case (ISAC_IND_AI10):
l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
break;
default:
break;
}
}
static void
isac_bh(struct work_struct *work)
{
struct IsdnCardState *cs =
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "D-Channel Busy cleared");
stptr = cs->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
stptr = stptr->next;
}
}
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
isac_new_ph(cs);
if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
DChannel_proc_rcv(cs);
if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
DChannel_proc_xmt(cs);
#if ARCOFI_USE
if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
return;
if (test_and_clear_bit(D_RX_MON1, &cs->event))
arcofi_fsm(cs, ARCOFI_RX_END, NULL);
if (test_and_clear_bit(D_TX_MON1, &cs->event))
arcofi_fsm(cs, ARCOFI_TX_END, NULL);
#endif
}
static void
isac_empty_fifo(struct IsdnCardState *cs, int count)
{
u_char *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "isac_empty_fifo");
if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "isac_empty_fifo overrun %d",
cs->rcvidx + count);
cs->writeisac(cs, ISAC_CMDR, 0x80);
cs->rcvidx = 0;
return;
}
ptr = cs->rcvbuf + cs->rcvidx;
cs->rcvidx += count;
cs->readisacfifo(cs, ptr, count);
cs->writeisac(cs, ISAC_CMDR, 0x80);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "isac_empty_fifo cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
static void
isac_fill_fifo(struct IsdnCardState *cs)
{
int count, more;
u_char *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "isac_fill_fifo");
if (!cs->tx_skb)
return;
count = cs->tx_skb->len;
if (count <= 0)
return;
more = 0;
if (count > 32) {
more = !0;
count = 32;
}
ptr = cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
cs->tx_cnt += count;
cs->writeisacfifo(cs, ptr, count);
cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa);
if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
debugl1(cs, "isac_fill_fifo dbusytimer running");
del_timer(&cs->dbusytimer);
}
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
add_timer(&cs->dbusytimer);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "isac_fill_fifo cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
void
isac_interrupt(struct IsdnCardState *cs, u_char val)
{
u_char exval, v1;
struct sk_buff *skb;
unsigned int count;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC interrupt %x", val);
if (val & 0x80) { /* RME */
exval = cs->readisac(cs, ISAC_RSTA);
if ((exval & 0x70) != 0x20) {
if (exval & 0x40) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC RDO");
#ifdef ERROR_STATISTIC
cs->err_rx++;
#endif
}
if (!(exval & 0x20)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC CRC error");
#ifdef ERROR_STATISTIC
cs->err_crc++;
#endif
}
cs->writeisac(cs, ISAC_CMDR, 0x80);
} else {
count = cs->readisac(cs, ISAC_RBCL) & 0x1f;
if (count == 0)
count = 32;
isac_empty_fifo(cs, count);
count = cs->rcvidx;
if (count > 0) {
cs->rcvidx = 0;
skb = alloc_skb(count, GFP_ATOMIC);
if (!skb)
printk(KERN_WARNING "HiSax: D receive out of memory\n");
else {
skb_put_data(skb, cs->rcvbuf, count);
skb_queue_tail(&cs->rq, skb);
}
}
}
cs->rcvidx = 0;
schedule_event(cs, D_RCVBUFREADY);
}
if (val & 0x40) { /* RPF */
isac_empty_fifo(cs, 32);
}
if (val & 0x20) { /* RSC */
/* never */
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC RSC interrupt");
}
if (val & 0x10) { /* XPR */
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) {
if (cs->tx_skb->len) {
isac_fill_fifo(cs);
goto afterXPR;
} else {
dev_kfree_skb_irq(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
}
}
cs->tx_skb = skb_dequeue(&cs->sq);
if (cs->tx_skb) {
cs->tx_cnt = 0;
isac_fill_fifo(cs);
} else
schedule_event(cs, D_XMTBUFREADY);
}
afterXPR:
if (val & 0x04) { /* CISQ */
exval = cs->readisac(cs, ISAC_CIR0);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC CIR0 %02X", exval);
if (exval & 2) {
cs->dc.isac.ph_state = (exval >> 2) & 0xf;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state);
schedule_event(cs, D_L1STATECHANGE);
}
if (exval & 1) {
exval = cs->readisac(cs, ISAC_CIR1);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC CIR1 %02X", exval);
}
}
if (val & 0x02) { /* SIN */
/* never */
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC SIN interrupt");
}
if (val & 0x01) { /* EXI */
exval = cs->readisac(cs, ISAC_EXIR);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC EXIR %02x", exval);
if (exval & 0x80) { /* XMR */
debugl1(cs, "ISAC XMR");
printk(KERN_WARNING "HiSax: ISAC XMR\n");
}
if (exval & 0x40) { /* XDU */
debugl1(cs, "ISAC XDU");
printk(KERN_WARNING "HiSax: ISAC XDU\n");
#ifdef ERROR_STATISTIC
cs->err_tx++;
#endif
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) { /* Restart frame */
skb_push(cs->tx_skb, cs->tx_cnt);
cs->tx_cnt = 0;
isac_fill_fifo(cs);
} else {
printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
debugl1(cs, "ISAC XDU no skb");
}
}
if (exval & 0x04) { /* MOS */
v1 = cs->readisac(cs, ISAC_MOSR);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ISAC MOSR %02x", v1);
#if ARCOFI_USE
if (v1 & 0x08) {
if (!cs->dc.isac.mon_rx) {
cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
if (!cs->dc.isac.mon_rx) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC MON RX out of memory!");
cs->dc.isac.mocr &= 0xf0;
cs->dc.isac.mocr |= 0x0a;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
goto afterMONR0;
} else
cs->dc.isac.mon_rxp = 0;
}
if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
cs->dc.isac.mocr &= 0xf0;
cs->dc.isac.mocr |= 0x0a;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mon_rxp = 0;
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC MON RX overflow!");
goto afterMONR0;
}
cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]);
if (cs->dc.isac.mon_rxp == 1) {
cs->dc.isac.mocr |= 0x04;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
}
}
afterMONR0:
if (v1 & 0x80) {
if (!cs->dc.isac.mon_rx) {
cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
if (!cs->dc.isac.mon_rx) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC MON RX out of memory!");
cs->dc.isac.mocr &= 0x0f;
cs->dc.isac.mocr |= 0xa0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
goto afterMONR1;
} else
cs->dc.isac.mon_rxp = 0;
}
if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
cs->dc.isac.mocr &= 0x0f;
cs->dc.isac.mocr |= 0xa0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mon_rxp = 0;
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC MON RX overflow!");
goto afterMONR1;
}
cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]);
cs->dc.isac.mocr |= 0x40;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
}
afterMONR1:
if (v1 & 0x04) {
cs->dc.isac.mocr &= 0xf0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mocr |= 0x0a;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
schedule_event(cs, D_RX_MON0);
}
if (v1 & 0x40) {
cs->dc.isac.mocr &= 0x0f;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mocr |= 0xa0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
schedule_event(cs, D_RX_MON1);
}
if (v1 & 0x02) {
if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
!(v1 & 0x08))) {
cs->dc.isac.mocr &= 0xf0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mocr |= 0x0a;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
if (cs->dc.isac.mon_txc &&
(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
schedule_event(cs, D_TX_MON0);
goto AfterMOX0;
}
if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
schedule_event(cs, D_TX_MON0);
goto AfterMOX0;
}
cs->writeisac(cs, ISAC_MOX0,
cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]);
}
AfterMOX0:
if (v1 & 0x20) {
if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
!(v1 & 0x80))) {
cs->dc.isac.mocr &= 0x0f;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mocr |= 0xa0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
if (cs->dc.isac.mon_txc &&
(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
schedule_event(cs, D_TX_MON1);
goto AfterMOX1;
}
if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
schedule_event(cs, D_TX_MON1);
goto AfterMOX1;
}
cs->writeisac(cs, ISAC_MOX1,
cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]);
}
AfterMOX1:;
#endif
}
}
}
static void
ISAC_l1hw(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
struct sk_buff *skb = arg;
u_long flags;
int val;
switch (pr) {
case (PH_DATA | REQUEST):
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
skb_queue_tail(&cs->sq, skb);
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA Queued", 0);
#endif
} else {
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA", 0);
#endif
isac_fill_fifo(cs);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
skb_queue_tail(&cs->sq, skb);
} else {
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
#endif
isac_fill_fifo(cs);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | REQUEST):
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
debugl1(cs, "-> PH_REQUEST_PULL");
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (HW_RESET | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
if ((cs->dc.isac.ph_state == ISAC_IND_EI) ||
(cs->dc.isac.ph_state == ISAC_IND_DR) ||
(cs->dc.isac.ph_state == ISAC_IND_RS))
ph_command(cs, ISAC_CMD_TIM);
else
ph_command(cs, ISAC_CMD_RS);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_ENABLE | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
ph_command(cs, ISAC_CMD_TIM);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_INFO3 | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
ph_command(cs, ISAC_CMD_AR8);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_TESTLOOP | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
val = 0;
if (1 & (long) arg)
val |= 0x0c;
if (2 & (long) arg)
val |= 0x3;
if (test_bit(HW_IOM1, &cs->HW_Flags)) {
/* IOM 1 Mode */
if (!val) {
cs->writeisac(cs, ISAC_SPCR, 0xa);
cs->writeisac(cs, ISAC_ADF1, 0x2);
} else {
cs->writeisac(cs, ISAC_SPCR, val);
cs->writeisac(cs, ISAC_ADF1, 0xa);
}
} else {
/* IOM 2 Mode */
cs->writeisac(cs, ISAC_SPCR, val);
if (val)
cs->writeisac(cs, ISAC_ADF1, 0x8);
else
cs->writeisac(cs, ISAC_ADF1, 0x0);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_DEACTIVATE | RESPONSE):
skb_queue_purge(&cs->rq);
skb_queue_purge(&cs->sq);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
}
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
break;
default:
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "isac_l1hw unknown %04x", pr);
break;
}
}
static void
setstack_isac(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = ISAC_l1hw;
}
static void
DC_Close_isac(struct IsdnCardState *cs)
{
kfree(cs->dc.isac.mon_rx);
cs->dc.isac.mon_rx = NULL;
kfree(cs->dc.isac.mon_tx);
cs->dc.isac.mon_tx = NULL;
}
static void
dbusy_timer_handler(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
struct PStack *stptr;
int rbch, star;
if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
rbch = cs->readisac(cs, ISAC_RBCH);
star = cs->readisac(cs, ISAC_STAR);
if (cs->debug)
debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
rbch, star);
if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */
test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
stptr = cs->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
stptr = stptr->next;
}
} else {
/* discard frame; reset transceiver */
test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
} else {
printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
debugl1(cs, "D-Channel Busy no skb");
}
cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
cs->irq_func(cs->irq, cs);
}
}
}
void initisac(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_isac;
cs->DC_Close = DC_Close_isac;
cs->dc.isac.mon_tx = NULL;
cs->dc.isac.mon_rx = NULL;
cs->writeisac(cs, ISAC_MASK, 0xff);
cs->dc.isac.mocr = 0xaa;
if (test_bit(HW_IOM1, &cs->HW_Flags)) {
/* IOM 1 Mode */
cs->writeisac(cs, ISAC_ADF2, 0x0);
cs->writeisac(cs, ISAC_SPCR, 0xa);
cs->writeisac(cs, ISAC_ADF1, 0x2);
cs->writeisac(cs, ISAC_STCR, 0x70);
cs->writeisac(cs, ISAC_MODE, 0xc9);
} else {
/* IOM 2 Mode */
if (!cs->dc.isac.adf2)
cs->dc.isac.adf2 = 0x80;
cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2);
cs->writeisac(cs, ISAC_SQXR, 0x2f);
cs->writeisac(cs, ISAC_SPCR, 0x00);
cs->writeisac(cs, ISAC_STCR, 0x70);
cs->writeisac(cs, ISAC_MODE, 0xc9);
cs->writeisac(cs, ISAC_TIMR, 0x00);
cs->writeisac(cs, ISAC_ADF1, 0x00);
}
ph_command(cs, ISAC_CMD_RS);
cs->writeisac(cs, ISAC_MASK, 0x0);
}
void clear_pending_isac_ints(struct IsdnCardState *cs)
{
int val, eval;
val = cs->readisac(cs, ISAC_STAR);
debugl1(cs, "ISAC STAR %x", val);
val = cs->readisac(cs, ISAC_MODE);
debugl1(cs, "ISAC MODE %x", val);
val = cs->readisac(cs, ISAC_ADF2);
debugl1(cs, "ISAC ADF2 %x", val);
val = cs->readisac(cs, ISAC_ISTA);
debugl1(cs, "ISAC ISTA %x", val);
if (val & 0x01) {
eval = cs->readisac(cs, ISAC_EXIR);
debugl1(cs, "ISAC EXIR %x", eval);
}
val = cs->readisac(cs, ISAC_CIR0);
debugl1(cs, "ISAC CIR0 %x", val);
cs->dc.isac.ph_state = (val >> 2) & 0xf;
schedule_event(cs, D_L1STATECHANGE);
/* Disable all IRQ */
cs->writeisac(cs, ISAC_MASK, 0xFF);
}
void setup_isac(struct IsdnCardState *cs)
{
INIT_WORK(&cs->tqueue, isac_bh);
timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
}

View file

@ -1,70 +0,0 @@
/* $Id: isac.h,v 1.9.2.2 2004/01/12 22:52:27 keil Exp $
*
* ISAC specific defines
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/* All Registers original Siemens Spec */
#define ISAC_MASK 0x20
#define ISAC_ISTA 0x20
#define ISAC_STAR 0x21
#define ISAC_CMDR 0x21
#define ISAC_EXIR 0x24
#define ISAC_ADF2 0x39
#define ISAC_SPCR 0x30
#define ISAC_ADF1 0x38
#define ISAC_CIR0 0x31
#define ISAC_CIX0 0x31
#define ISAC_CIR1 0x33
#define ISAC_CIX1 0x33
#define ISAC_STCR 0x37
#define ISAC_MODE 0x22
#define ISAC_RSTA 0x27
#define ISAC_RBCL 0x25
#define ISAC_RBCH 0x2A
#define ISAC_TIMR 0x23
#define ISAC_SQXR 0x3b
#define ISAC_MOSR 0x3a
#define ISAC_MOCR 0x3a
#define ISAC_MOR0 0x32
#define ISAC_MOX0 0x32
#define ISAC_MOR1 0x34
#define ISAC_MOX1 0x34
#define ISAC_RBCH_XAC 0x80
#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
#define ISAC_IND_RS 0x1
#define ISAC_IND_PU 0x7
#define ISAC_IND_DR 0x0
#define ISAC_IND_SD 0x2
#define ISAC_IND_DIS 0x3
#define ISAC_IND_EI 0x6
#define ISAC_IND_RSY 0x4
#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
extern void ISACVersion(struct IsdnCardState *, char *);
extern void setup_isac(struct IsdnCardState *);
extern void initisac(struct IsdnCardState *);
extern void isac_interrupt(struct IsdnCardState *, u_char);
extern void clear_pending_isac_ints(struct IsdnCardState *);

Some files were not shown because too many files have changed in this diff Show more