mISDN: Add support for Speedfax+ cards
Add support for the Siemens ISAR DSP chip and cards based on it, including analog modem protocols. Signed-off-by: Karsten Keil <keil@b1-systems.de>
This commit is contained in:
parent
6115d2f3fc
commit
da2272c91a
|
@ -47,6 +47,15 @@ config MISDN_AVMFRITZ
|
|||
help
|
||||
Enable support for AVMs FRITZ!CARD PCI cards
|
||||
|
||||
config MISDN_SPEEDFAX
|
||||
tristate "Support for Sedlbauer Speedfax+"
|
||||
depends on MISDN
|
||||
depends on PCI
|
||||
select MISDN_IPAC
|
||||
select MISDN_ISAR
|
||||
help
|
||||
Enable support for Sedlbauer Speedfax+.
|
||||
|
||||
config MISDN_INFINEON
|
||||
tristate "Support for cards with Infineon chipset"
|
||||
depends on MISDN
|
||||
|
@ -61,3 +70,7 @@ config MISDN_IPAC
|
|||
tristate
|
||||
depends on MISDN
|
||||
|
||||
config MISDN_ISAR
|
||||
tristate
|
||||
depends on MISDN
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o
|
|||
obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o
|
||||
obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o
|
||||
obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o
|
||||
obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o
|
||||
obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o
|
||||
# chip modules
|
||||
obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o
|
||||
obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o
|
||||
|
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
*
|
||||
* isar.h ISAR (Siemens PSB 7110) specific defines
|
||||
*
|
||||
* Author Karsten Keil (keil@isdn4linux.de)
|
||||
*
|
||||
* Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "iohelper.h"
|
||||
|
||||
struct isar_hw;
|
||||
|
||||
struct isar_ch {
|
||||
struct bchannel bch;
|
||||
struct isar_hw *is;
|
||||
struct timer_list ftimer;
|
||||
u8 nr;
|
||||
u8 dpath;
|
||||
u8 mml;
|
||||
u8 state;
|
||||
u8 cmd;
|
||||
u8 mod;
|
||||
u8 newcmd;
|
||||
u8 newmod;
|
||||
u8 try_mod;
|
||||
u8 conmsg[16];
|
||||
};
|
||||
|
||||
struct isar_hw {
|
||||
struct isar_ch ch[2];
|
||||
void *hw;
|
||||
spinlock_t *hwlock; /* lock HW acccess */
|
||||
char *name;
|
||||
struct module *owner;
|
||||
read_reg_t *read_reg;
|
||||
write_reg_t *write_reg;
|
||||
fifo_func_t *read_fifo;
|
||||
fifo_func_t *write_fifo;
|
||||
int (*ctrl)(void *, u32, u_long);
|
||||
void (*release)(struct isar_hw *);
|
||||
int (*init)(struct isar_hw *);
|
||||
int (*open)(struct isar_hw *, struct channel_req *);
|
||||
int (*firmware)(struct isar_hw *, const u8 *, int);
|
||||
unsigned long Flags;
|
||||
int version;
|
||||
u8 bstat;
|
||||
u8 iis;
|
||||
u8 cmsb;
|
||||
u8 clsb;
|
||||
u8 buf[256];
|
||||
u8 log[256];
|
||||
};
|
||||
|
||||
#define ISAR_IRQMSK 0x04
|
||||
#define ISAR_IRQSTA 0x04
|
||||
#define ISAR_IRQBIT 0x75
|
||||
#define ISAR_CTRL_H 0x61
|
||||
#define ISAR_CTRL_L 0x60
|
||||
#define ISAR_IIS 0x58
|
||||
#define ISAR_IIA 0x58
|
||||
#define ISAR_HIS 0x50
|
||||
#define ISAR_HIA 0x50
|
||||
#define ISAR_MBOX 0x4c
|
||||
#define ISAR_WADR 0x4a
|
||||
#define ISAR_RADR 0x48
|
||||
|
||||
#define ISAR_HIS_VNR 0x14
|
||||
#define ISAR_HIS_DKEY 0x02
|
||||
#define ISAR_HIS_FIRM 0x1e
|
||||
#define ISAR_HIS_STDSP 0x08
|
||||
#define ISAR_HIS_DIAG 0x05
|
||||
#define ISAR_HIS_P0CFG 0x3c
|
||||
#define ISAR_HIS_P12CFG 0x24
|
||||
#define ISAR_HIS_SARTCFG 0x25
|
||||
#define ISAR_HIS_PUMPCFG 0x26
|
||||
#define ISAR_HIS_PUMPCTRL 0x2a
|
||||
#define ISAR_HIS_IOM2CFG 0x27
|
||||
#define ISAR_HIS_IOM2REQ 0x07
|
||||
#define ISAR_HIS_IOM2CTRL 0x2b
|
||||
#define ISAR_HIS_BSTREQ 0x0c
|
||||
#define ISAR_HIS_PSTREQ 0x0e
|
||||
#define ISAR_HIS_SDATA 0x20
|
||||
#define ISAR_HIS_DPS1 0x40
|
||||
#define ISAR_HIS_DPS2 0x80
|
||||
#define SET_DPS(x) ((x<<6) & 0xc0)
|
||||
|
||||
#define ISAR_IIS_MSCMSD 0x3f
|
||||
#define ISAR_IIS_VNR 0x15
|
||||
#define ISAR_IIS_DKEY 0x03
|
||||
#define ISAR_IIS_FIRM 0x1f
|
||||
#define ISAR_IIS_STDSP 0x09
|
||||
#define ISAR_IIS_DIAG 0x25
|
||||
#define ISAR_IIS_GSTEV 0x00
|
||||
#define ISAR_IIS_BSTEV 0x28
|
||||
#define ISAR_IIS_BSTRSP 0x2c
|
||||
#define ISAR_IIS_PSTRSP 0x2e
|
||||
#define ISAR_IIS_PSTEV 0x2a
|
||||
#define ISAR_IIS_IOM2RSP 0x27
|
||||
#define ISAR_IIS_RDATA 0x20
|
||||
#define ISAR_IIS_INVMSG 0x3f
|
||||
|
||||
#define ISAR_CTRL_SWVER 0x10
|
||||
#define ISAR_CTRL_STST 0x40
|
||||
|
||||
#define ISAR_MSG_HWVER 0x20
|
||||
|
||||
#define ISAR_DP1_USE 1
|
||||
#define ISAR_DP2_USE 2
|
||||
#define ISAR_RATE_REQ 3
|
||||
|
||||
#define PMOD_DISABLE 0
|
||||
#define PMOD_FAX 1
|
||||
#define PMOD_DATAMODEM 2
|
||||
#define PMOD_HALFDUPLEX 3
|
||||
#define PMOD_V110 4
|
||||
#define PMOD_DTMF 5
|
||||
#define PMOD_DTMF_TRANS 6
|
||||
#define PMOD_BYPASS 7
|
||||
|
||||
#define PCTRL_ORIG 0x80
|
||||
#define PV32P2_V23R 0x40
|
||||
#define PV32P2_V22A 0x20
|
||||
#define PV32P2_V22B 0x10
|
||||
#define PV32P2_V22C 0x08
|
||||
#define PV32P2_V21 0x02
|
||||
#define PV32P2_BEL 0x01
|
||||
|
||||
/* LSB MSB in ISAR doc wrong !!! Arghhh */
|
||||
#define PV32P3_AMOD 0x80
|
||||
#define PV32P3_V32B 0x02
|
||||
#define PV32P3_V23B 0x01
|
||||
#define PV32P4_48 0x11
|
||||
#define PV32P5_48 0x05
|
||||
#define PV32P4_UT48 0x11
|
||||
#define PV32P5_UT48 0x0d
|
||||
#define PV32P4_96 0x11
|
||||
#define PV32P5_96 0x03
|
||||
#define PV32P4_UT96 0x11
|
||||
#define PV32P5_UT96 0x0f
|
||||
#define PV32P4_B96 0x91
|
||||
#define PV32P5_B96 0x0b
|
||||
#define PV32P4_UTB96 0xd1
|
||||
#define PV32P5_UTB96 0x0f
|
||||
#define PV32P4_120 0xb1
|
||||
#define PV32P5_120 0x09
|
||||
#define PV32P4_UT120 0xf1
|
||||
#define PV32P5_UT120 0x0f
|
||||
#define PV32P4_144 0x99
|
||||
#define PV32P5_144 0x09
|
||||
#define PV32P4_UT144 0xf9
|
||||
#define PV32P5_UT144 0x0f
|
||||
#define PV32P6_CTN 0x01
|
||||
#define PV32P6_ATN 0x02
|
||||
|
||||
#define PFAXP2_CTN 0x01
|
||||
#define PFAXP2_ATN 0x04
|
||||
|
||||
#define PSEV_10MS_TIMER 0x02
|
||||
#define PSEV_CON_ON 0x18
|
||||
#define PSEV_CON_OFF 0x19
|
||||
#define PSEV_V24_OFF 0x20
|
||||
#define PSEV_CTS_ON 0x21
|
||||
#define PSEV_CTS_OFF 0x22
|
||||
#define PSEV_DCD_ON 0x23
|
||||
#define PSEV_DCD_OFF 0x24
|
||||
#define PSEV_DSR_ON 0x25
|
||||
#define PSEV_DSR_OFF 0x26
|
||||
#define PSEV_REM_RET 0xcc
|
||||
#define PSEV_REM_REN 0xcd
|
||||
#define PSEV_GSTN_CLR 0xd4
|
||||
|
||||
#define PSEV_RSP_READY 0xbc
|
||||
#define PSEV_LINE_TX_H 0xb3
|
||||
#define PSEV_LINE_TX_B 0xb2
|
||||
#define PSEV_LINE_RX_H 0xb1
|
||||
#define PSEV_LINE_RX_B 0xb0
|
||||
#define PSEV_RSP_CONN 0xb5
|
||||
#define PSEV_RSP_DISC 0xb7
|
||||
#define PSEV_RSP_FCERR 0xb9
|
||||
#define PSEV_RSP_SILDET 0xbe
|
||||
#define PSEV_RSP_SILOFF 0xab
|
||||
#define PSEV_FLAGS_DET 0xba
|
||||
|
||||
#define PCTRL_CMD_TDTMF 0x5a
|
||||
|
||||
#define PCTRL_CMD_FTH 0xa7
|
||||
#define PCTRL_CMD_FRH 0xa5
|
||||
#define PCTRL_CMD_FTM 0xa8
|
||||
#define PCTRL_CMD_FRM 0xa6
|
||||
#define PCTRL_CMD_SILON 0xac
|
||||
#define PCTRL_CMD_CONT 0xa2
|
||||
#define PCTRL_CMD_ESC 0xa4
|
||||
#define PCTRL_CMD_SILOFF 0xab
|
||||
#define PCTRL_CMD_HALT 0xa9
|
||||
|
||||
#define PCTRL_LOC_RET 0xcf
|
||||
#define PCTRL_LOC_REN 0xce
|
||||
|
||||
#define SMODE_DISABLE 0
|
||||
#define SMODE_V14 2
|
||||
#define SMODE_HDLC 3
|
||||
#define SMODE_BINARY 4
|
||||
#define SMODE_FSK_V14 5
|
||||
|
||||
#define SCTRL_HDMC_BOTH 0x00
|
||||
#define SCTRL_HDMC_DTX 0x80
|
||||
#define SCTRL_HDMC_DRX 0x40
|
||||
#define S_P1_OVSP 0x40
|
||||
#define S_P1_SNP 0x20
|
||||
#define S_P1_EOP 0x10
|
||||
#define S_P1_EDP 0x08
|
||||
#define S_P1_NSB 0x04
|
||||
#define S_P1_CHS_8 0x03
|
||||
#define S_P1_CHS_7 0x02
|
||||
#define S_P1_CHS_6 0x01
|
||||
#define S_P1_CHS_5 0x00
|
||||
|
||||
#define S_P2_BFT_DEF 0x10
|
||||
|
||||
#define IOM_CTRL_ENA 0x80
|
||||
#define IOM_CTRL_NOPCM 0x00
|
||||
#define IOM_CTRL_ALAW 0x02
|
||||
#define IOM_CTRL_ULAW 0x04
|
||||
#define IOM_CTRL_RCV 0x01
|
||||
|
||||
#define IOM_P1_TXD 0x10
|
||||
|
||||
#define HDLC_FED 0x40
|
||||
#define HDLC_FSD 0x20
|
||||
#define HDLC_FST 0x20
|
||||
#define HDLC_ERROR 0x1c
|
||||
#define HDLC_ERR_FAD 0x10
|
||||
#define HDLC_ERR_RER 0x08
|
||||
#define HDLC_ERR_CER 0x04
|
||||
#define SART_NMD 0x01
|
||||
|
||||
#define BSTAT_RDM0 0x1
|
||||
#define BSTAT_RDM1 0x2
|
||||
#define BSTAT_RDM2 0x4
|
||||
#define BSTAT_RDM3 0x8
|
||||
#define BSTEV_TBO 0x1f
|
||||
#define BSTEV_RBO 0x2f
|
||||
|
||||
/* FAX State Machine */
|
||||
#define STFAX_NULL 0
|
||||
#define STFAX_READY 1
|
||||
#define STFAX_LINE 2
|
||||
#define STFAX_CONT 3
|
||||
#define STFAX_ACTIV 4
|
||||
#define STFAX_ESCAPE 5
|
||||
#define STFAX_SILDET 6
|
||||
|
||||
extern u32 mISDNisar_init(struct isar_hw *, void *);
|
||||
extern void mISDNisar_irq(struct isar_hw *);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,526 @@
|
|||
/*
|
||||
* speedfax.c low level stuff for Sedlbauer Speedfax+ cards
|
||||
* based on the ISAR DSP
|
||||
* Thanks to Sedlbauer AG for informations and HW
|
||||
*
|
||||
* Author Karsten Keil <keil@isdn4linux.de>
|
||||
*
|
||||
* Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mISDNhw.h>
|
||||
#include <linux/firmware.h>
|
||||
#include "ipac.h"
|
||||
#include "isar.h"
|
||||
|
||||
#define SPEEDFAX_REV "2.0"
|
||||
|
||||
#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51
|
||||
#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54
|
||||
#define PCI_SUB_ID_SEDLBAUER 0x01
|
||||
|
||||
#define SFAX_PCI_ADDR 0xc8
|
||||
#define SFAX_PCI_ISAC 0xd0
|
||||
#define SFAX_PCI_ISAR 0xe0
|
||||
|
||||
/* TIGER 100 Registers */
|
||||
|
||||
#define TIGER_RESET_ADDR 0x00
|
||||
#define TIGER_EXTERN_RESET_ON 0x01
|
||||
#define TIGER_EXTERN_RESET_OFF 0x00
|
||||
#define TIGER_AUX_CTRL 0x02
|
||||
#define TIGER_AUX_DATA 0x03
|
||||
#define TIGER_AUX_IRQMASK 0x05
|
||||
#define TIGER_AUX_STATUS 0x07
|
||||
|
||||
/* Tiger AUX BITs */
|
||||
#define SFAX_AUX_IOMASK 0xdd /* 1 and 5 are inputs */
|
||||
#define SFAX_ISAR_RESET_BIT_OFF 0x00
|
||||
#define SFAX_ISAR_RESET_BIT_ON 0x01
|
||||
#define SFAX_TIGER_IRQ_BIT 0x02
|
||||
#define SFAX_LED1_BIT 0x08
|
||||
#define SFAX_LED2_BIT 0x10
|
||||
|
||||
#define SFAX_PCI_RESET_ON (SFAX_ISAR_RESET_BIT_ON)
|
||||
#define SFAX_PCI_RESET_OFF (SFAX_LED1_BIT | SFAX_LED2_BIT)
|
||||
|
||||
static int sfax_cnt;
|
||||
static u32 debug;
|
||||
static u32 irqloops = 4;
|
||||
|
||||
struct sfax_hw {
|
||||
struct list_head list;
|
||||
struct pci_dev *pdev;
|
||||
char name[MISDN_MAX_IDLEN];
|
||||
u32 irq;
|
||||
u32 irqcnt;
|
||||
u32 cfg;
|
||||
struct _ioport p_isac;
|
||||
struct _ioport p_isar;
|
||||
u8 aux_data;
|
||||
spinlock_t lock; /* HW access lock */
|
||||
struct isac_hw isac;
|
||||
struct isar_hw isar;
|
||||
};
|
||||
|
||||
static LIST_HEAD(Cards);
|
||||
static DEFINE_RWLOCK(card_lock); /* protect Cards */
|
||||
|
||||
static void
|
||||
_set_debug(struct sfax_hw *card)
|
||||
{
|
||||
card->isac.dch.debug = debug;
|
||||
card->isar.ch[0].bch.debug = debug;
|
||||
card->isar.ch[1].bch.debug = debug;
|
||||
}
|
||||
|
||||
static int
|
||||
set_debug(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
int ret;
|
||||
struct sfax_hw *card;
|
||||
|
||||
ret = param_set_uint(val, kp);
|
||||
if (!ret) {
|
||||
read_lock(&card_lock);
|
||||
list_for_each_entry(card, &Cards, list)
|
||||
_set_debug(card);
|
||||
read_unlock(&card_lock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Karsten Keil");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_VERSION(SPEEDFAX_REV);
|
||||
module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(debug, "Speedfax debug mask");
|
||||
module_param(irqloops, uint, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)");
|
||||
|
||||
IOFUNC_IND(ISAC, sfax_hw, p_isac)
|
||||
IOFUNC_IND(ISAR, sfax_hw, p_isar)
|
||||
|
||||
static irqreturn_t
|
||||
speedfax_irq(int intno, void *dev_id)
|
||||
{
|
||||
struct sfax_hw *sf = dev_id;
|
||||
u8 val;
|
||||
int cnt = irqloops;
|
||||
|
||||
spin_lock(&sf->lock);
|
||||
val = inb(sf->cfg + TIGER_AUX_STATUS);
|
||||
if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */
|
||||
spin_unlock(&sf->lock);
|
||||
return IRQ_NONE; /* shared */
|
||||
}
|
||||
sf->irqcnt++;
|
||||
val = ReadISAR_IND(sf, ISAR_IRQBIT);
|
||||
Start_ISAR:
|
||||
if (val & ISAR_IRQSTA)
|
||||
mISDNisar_irq(&sf->isar);
|
||||
val = ReadISAC_IND(sf, ISAC_ISTA);
|
||||
if (val)
|
||||
mISDNisac_irq(&sf->isac, val);
|
||||
val = ReadISAR_IND(sf, ISAR_IRQBIT);
|
||||
if ((val & ISAR_IRQSTA) && cnt--)
|
||||
goto Start_ISAR;
|
||||
if (cnt < irqloops)
|
||||
pr_debug("%s: %d irqloops cpu%d\n", sf->name,
|
||||
irqloops - cnt, smp_processor_id());
|
||||
if (irqloops && !cnt)
|
||||
pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name,
|
||||
irqloops, smp_processor_id());
|
||||
spin_unlock(&sf->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void
|
||||
enable_hwirq(struct sfax_hw *sf)
|
||||
{
|
||||
WriteISAC_IND(sf, ISAC_MASK, 0);
|
||||
WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK);
|
||||
outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK);
|
||||
}
|
||||
|
||||
static void
|
||||
disable_hwirq(struct sfax_hw *sf)
|
||||
{
|
||||
WriteISAC_IND(sf, ISAC_MASK, 0xFF);
|
||||
WriteISAR_IND(sf, ISAR_IRQBIT, 0);
|
||||
outb(0, sf->cfg + TIGER_AUX_IRQMASK);
|
||||
}
|
||||
|
||||
static void
|
||||
reset_speedfax(struct sfax_hw *sf)
|
||||
{
|
||||
|
||||
pr_debug("%s: resetting card\n", sf->name);
|
||||
outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR);
|
||||
outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA);
|
||||
mdelay(1);
|
||||
outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR);
|
||||
sf->aux_data = SFAX_PCI_RESET_OFF;
|
||||
outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
static int
|
||||
sfax_ctrl(struct sfax_hw *sf, u32 cmd, u_long arg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case HW_RESET_REQ:
|
||||
reset_speedfax(sf);
|
||||
break;
|
||||
case HW_ACTIVATE_IND:
|
||||
if (arg & 1)
|
||||
sf->aux_data &= ~SFAX_LED1_BIT;
|
||||
if (arg & 2)
|
||||
sf->aux_data &= ~SFAX_LED2_BIT;
|
||||
outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
|
||||
break;
|
||||
case HW_DEACT_IND:
|
||||
if (arg & 1)
|
||||
sf->aux_data |= SFAX_LED1_BIT;
|
||||
if (arg & 2)
|
||||
sf->aux_data |= SFAX_LED2_BIT;
|
||||
outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
|
||||
break;
|
||||
default:
|
||||
pr_info("%s: %s unknown command %x %lx\n",
|
||||
sf->name, __func__, cmd, arg);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (cq->op) {
|
||||
case MISDN_CTRL_GETOP:
|
||||
cq->op = MISDN_CTRL_LOOP;
|
||||
break;
|
||||
case MISDN_CTRL_LOOP:
|
||||
/* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
|
||||
if (cq->channel < 0 || cq->channel > 3) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel);
|
||||
break;
|
||||
default:
|
||||
pr_info("%s: unknown Op %x\n", sf->name, cq->op);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
|
||||
{
|
||||
struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
|
||||
struct dchannel *dch = container_of(dev, struct dchannel, dev);
|
||||
struct sfax_hw *sf = dch->hw;
|
||||
struct channel_req *rq;
|
||||
int err = 0;
|
||||
|
||||
pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg);
|
||||
switch (cmd) {
|
||||
case OPEN_CHANNEL:
|
||||
rq = arg;
|
||||
if (rq->protocol == ISDN_P_TE_S0)
|
||||
err = sf->isac.open(&sf->isac, rq);
|
||||
else
|
||||
err = sf->isar.open(&sf->isar, rq);
|
||||
if (err)
|
||||
break;
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
pr_info("%s: cannot get module\n", sf->name);
|
||||
break;
|
||||
case CLOSE_CHANNEL:
|
||||
pr_debug("%s: dev(%d) close from %p\n", sf->name,
|
||||
dch->dev.id, __builtin_return_address(0));
|
||||
module_put(THIS_MODULE);
|
||||
break;
|
||||
case CONTROL_CHANNEL:
|
||||
err = channel_ctrl(sf, arg);
|
||||
break;
|
||||
default:
|
||||
pr_debug("%s: unknown command %x\n", sf->name, cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
init_card(struct sfax_hw *sf)
|
||||
{
|
||||
int ret, cnt = 3;
|
||||
u_long flags;
|
||||
|
||||
ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf);
|
||||
if (ret) {
|
||||
pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq);
|
||||
return ret;
|
||||
}
|
||||
while (cnt--) {
|
||||
spin_lock_irqsave(&sf->lock, flags);
|
||||
ret = sf->isac.init(&sf->isac);
|
||||
if (ret) {
|
||||
spin_unlock_irqrestore(&sf->lock, flags);
|
||||
pr_info("%s: ISAC init failed with %d\n",
|
||||
sf->name, ret);
|
||||
break;
|
||||
}
|
||||
enable_hwirq(sf);
|
||||
/* RESET Receiver and Transmitter */
|
||||
WriteISAC_IND(sf, ISAC_CMDR, 0x41);
|
||||
spin_unlock_irqrestore(&sf->lock, flags);
|
||||
msleep_interruptible(10);
|
||||
if (debug & DEBUG_HW)
|
||||
pr_notice("%s: IRQ %d count %d\n", sf->name,
|
||||
sf->irq, sf->irqcnt);
|
||||
if (!sf->irqcnt) {
|
||||
pr_info("%s: IRQ(%d) got no requests during init %d\n",
|
||||
sf->name, sf->irq, 3 - cnt);
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
free_irq(sf->irq, sf);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
static int __devinit
|
||||
setup_speedfax(struct sfax_hw *sf)
|
||||
{
|
||||
u_long flags;
|
||||
|
||||
if (!request_region(sf->cfg, 256, sf->name)) {
|
||||
pr_info("mISDN: %s config port %x-%x already in use\n",
|
||||
sf->name, sf->cfg, sf->cfg + 255);
|
||||
return -EIO;
|
||||
}
|
||||
outb(0xff, sf->cfg);
|
||||
outb(0, sf->cfg);
|
||||
outb(0xdd, sf->cfg + TIGER_AUX_CTRL);
|
||||
outb(0, sf->cfg + TIGER_AUX_IRQMASK);
|
||||
|
||||
sf->isac.type = IPAC_TYPE_ISAC;
|
||||
sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR;
|
||||
sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC;
|
||||
sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR;
|
||||
sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR;
|
||||
ASSIGN_FUNC(IND, ISAC, sf->isac);
|
||||
ASSIGN_FUNC(IND, ISAR, sf->isar);
|
||||
spin_lock_irqsave(&sf->lock, flags);
|
||||
reset_speedfax(sf);
|
||||
disable_hwirq(sf);
|
||||
spin_unlock_irqrestore(&sf->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
release_card(struct sfax_hw *card) {
|
||||
u_long flags;
|
||||
|
||||
spin_lock_irqsave(&card->lock, flags);
|
||||
disable_hwirq(card);
|
||||
spin_unlock_irqrestore(&card->lock, flags);
|
||||
card->isac.release(&card->isac);
|
||||
free_irq(card->irq, card);
|
||||
card->isar.release(&card->isar);
|
||||
mISDN_unregister_device(&card->isac.dch.dev);
|
||||
release_region(card->cfg, 256);
|
||||
pci_disable_device(card->pdev);
|
||||
pci_set_drvdata(card->pdev, NULL);
|
||||
write_lock_irqsave(&card_lock, flags);
|
||||
list_del(&card->list);
|
||||
write_unlock_irqrestore(&card_lock, flags);
|
||||
kfree(card);
|
||||
sfax_cnt--;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
setup_instance(struct sfax_hw *card)
|
||||
{
|
||||
const struct firmware *firmware;
|
||||
int i, err;
|
||||
u_long flags;
|
||||
|
||||
snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1);
|
||||
write_lock_irqsave(&card_lock, flags);
|
||||
list_add_tail(&card->list, &Cards);
|
||||
write_unlock_irqrestore(&card_lock, flags);
|
||||
_set_debug(card);
|
||||
spin_lock_init(&card->lock);
|
||||
card->isac.hwlock = &card->lock;
|
||||
card->isar.hwlock = &card->lock;
|
||||
card->isar.ctrl = (void *)&sfax_ctrl;
|
||||
card->isac.name = card->name;
|
||||
card->isar.name = card->name;
|
||||
card->isar.owner = THIS_MODULE;
|
||||
|
||||
err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev);
|
||||
if (err < 0) {
|
||||
pr_info("%s: firmware request failed %d\n",
|
||||
card->name, err);
|
||||
goto error_fw;
|
||||
}
|
||||
if (debug & DEBUG_HW)
|
||||
pr_notice("%s: got firmware %zu bytes\n",
|
||||
card->name, firmware->size);
|
||||
|
||||
mISDNisac_init(&card->isac, card);
|
||||
|
||||
card->isac.dch.dev.D.ctrl = sfax_dctrl;
|
||||
card->isac.dch.dev.Bprotocols =
|
||||
mISDNisar_init(&card->isar, card);
|
||||
for (i = 0; i < 2; i++) {
|
||||
set_channelmap(i + 1, card->isac.dch.dev.channelmap);
|
||||
list_add(&card->isar.ch[i].bch.ch.list,
|
||||
&card->isac.dch.dev.bchannels);
|
||||
}
|
||||
|
||||
err = setup_speedfax(card);
|
||||
if (err)
|
||||
goto error_setup;
|
||||
err = card->isar.init(&card->isar);
|
||||
if (err)
|
||||
goto error;
|
||||
err = mISDN_register_device(&card->isac.dch.dev,
|
||||
&card->pdev->dev, card->name);
|
||||
if (err)
|
||||
goto error;
|
||||
err = init_card(card);
|
||||
if (err)
|
||||
goto error_init;
|
||||
err = card->isar.firmware(&card->isar, firmware->data, firmware->size);
|
||||
if (!err) {
|
||||
release_firmware(firmware);
|
||||
sfax_cnt++;
|
||||
pr_notice("SpeedFax %d cards installed\n", sfax_cnt);
|
||||
return 0;
|
||||
}
|
||||
disable_hwirq(card);
|
||||
free_irq(card->irq, card);
|
||||
error_init:
|
||||
mISDN_unregister_device(&card->isac.dch.dev);
|
||||
error:
|
||||
release_region(card->cfg, 256);
|
||||
error_setup:
|
||||
card->isac.release(&card->isac);
|
||||
card->isar.release(&card->isar);
|
||||
release_firmware(firmware);
|
||||
error_fw:
|
||||
pci_disable_device(card->pdev);
|
||||
write_lock_irqsave(&card_lock, flags);
|
||||
list_del(&card->list);
|
||||
write_unlock_irqrestore(&card_lock, flags);
|
||||
kfree(card);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
struct sfax_hw *card = kzalloc(sizeof(struct sfax_hw), GFP_KERNEL);
|
||||
|
||||
if (!card) {
|
||||
pr_info("No memory for Speedfax+ PCI\n");
|
||||
return err;
|
||||
}
|
||||
card->pdev = pdev;
|
||||
err = pci_enable_device(pdev);
|
||||
if (err) {
|
||||
kfree(card);
|
||||
return err;
|
||||
}
|
||||
|
||||
pr_notice("mISDN: Speedfax found adapter %s at %s\n",
|
||||
(char *)ent->driver_data, pci_name(pdev));
|
||||
|
||||
card->cfg = pci_resource_start(pdev, 0);
|
||||
card->irq = pdev->irq;
|
||||
pci_set_drvdata(pdev, card);
|
||||
err = setup_instance(card);
|
||||
if (err)
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __devexit
|
||||
sfax_remove_pci(struct pci_dev *pdev)
|
||||
{
|
||||
struct sfax_hw *card = pci_get_drvdata(pdev);
|
||||
|
||||
if (card)
|
||||
release_card(card);
|
||||
else
|
||||
pr_debug("%s: drvdata allready removed\n", __func__);
|
||||
}
|
||||
|
||||
static struct pci_device_id sfaxpci_ids[] __devinitdata = {
|
||||
{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
|
||||
PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER,
|
||||
0, 0, (unsigned long) "Pyramid Speedfax + PCI"
|
||||
},
|
||||
{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
|
||||
PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER,
|
||||
0, 0, (unsigned long) "Sedlbauer Speedfax + PCI"
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, sfaxpci_ids);
|
||||
|
||||
static struct pci_driver sfaxpci_driver = {
|
||||
.name = "speedfax+ pci",
|
||||
.probe = sfaxpci_probe,
|
||||
.remove = __devexit_p(sfax_remove_pci),
|
||||
.id_table = sfaxpci_ids,
|
||||
};
|
||||
|
||||
static int __init
|
||||
Speedfax_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n",
|
||||
SPEEDFAX_REV);
|
||||
err = pci_register_driver(&sfaxpci_driver);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
Speedfax_cleanup(void)
|
||||
{
|
||||
pci_unregister_driver(&sfaxpci_driver);
|
||||
}
|
||||
|
||||
module_init(Speedfax_init);
|
||||
module_exit(Speedfax_cleanup);
|
|
@ -37,7 +37,7 @@
|
|||
*/
|
||||
#define MISDN_MAJOR_VERSION 1
|
||||
#define MISDN_MINOR_VERSION 1
|
||||
#define MISDN_RELEASE 20
|
||||
#define MISDN_RELEASE 21
|
||||
|
||||
/* primitives for information exchange
|
||||
* generell format
|
||||
|
@ -153,6 +153,18 @@
|
|||
#define HFC_VOL_CHANGE_RX 0x2602
|
||||
#define HFC_SPL_LOOP_ON 0x2603
|
||||
#define HFC_SPL_LOOP_OFF 0x2604
|
||||
/* for T30 FAX and analog modem */
|
||||
#define HW_MOD_FRM 0x4000
|
||||
#define HW_MOD_FRH 0x4001
|
||||
#define HW_MOD_FTM 0x4002
|
||||
#define HW_MOD_FTH 0x4003
|
||||
#define HW_MOD_FTS 0x4004
|
||||
#define HW_MOD_CONNECT 0x4010
|
||||
#define HW_MOD_OK 0x4011
|
||||
#define HW_MOD_NOCARR 0x4012
|
||||
#define HW_MOD_FCERROR 0x4013
|
||||
#define HW_MOD_READY 0x4014
|
||||
#define HW_MOD_LASTDATA 0x4015
|
||||
|
||||
/* DSP_TONE_PATT_ON parameter */
|
||||
#define TONE_OFF 0x0000
|
||||
|
@ -224,6 +236,8 @@
|
|||
#define ISDN_P_B_L2DTMF 0x24
|
||||
#define ISDN_P_B_L2DSP 0x25
|
||||
#define ISDN_P_B_L2DSPHDLC 0x26
|
||||
#define ISDN_P_B_T30_FAX 0x27
|
||||
#define ISDN_P_B_MODEM_ASYNC 0x28
|
||||
|
||||
#define OPTION_L2_PMX 1
|
||||
#define OPTION_L2_PTP 2
|
||||
|
|
Loading…
Reference in New Issue