mISDN/drivers/isdn/hardware/mISDN/sedl_fax.c

966 lines
24 KiB
C

/* $Id$
*
* sedl_fax.c low level stuff for Sedlbauer Speedfax + cards
*
* Copyright (C) 2000,2001 Karsten Keil (kkeil@suse.de)
*
* Author Karsten Keil (kkeil@suse.de)
*
*
* Thanks to Sedlbauer AG for informations
* Marcus Niemann
* Edgar Toernig
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
/* Supported cards:
* Card: Chip: Configuration: Comment:
* ---------------------------------------------------------------------
* Speed Fax+ ISAC_ISAR ISAPNP Full analog support
* Speed Fax+ ISAC_ISAR PCI PNP Full analog support
*
* Important:
* For the sedlbauer speed fax+ to work properly you have to download
* the firmware onto the card.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <asm/semaphore.h>
#ifdef NEW_ISAPNP
#include <linux/pnp.h>
#else
#include <linux/isapnp.h>
#endif
#include "channel.h"
#include "isac.h"
#include "isar.h"
#include "layer1.h"
#include "helper.h"
#include "debug.h"
extern const char *CardType[];
const char *Sedlfax_revision = "$Revision$";
const char *Sedlbauer_Types[] =
{"None", "speed fax+", "speed fax+ pyramid", "speed fax+ pci"};
#ifndef PCI_VENDOR_ID_TIGERJET
#define PCI_VENDOR_ID_TIGERJET 0xe159
#endif
#ifndef PCI_DEVICE_ID_TIGERJET_100
#define PCI_DEVICE_ID_TIGERJET_100 0x0002
#endif
#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51
#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54
#define PCI_SUB_ID_SEDLBAUER 0x01
#define SEDL_SPEEDFAX_ISA 1
#define SEDL_SPEEDFAX_PYRAMID 2
#define SEDL_SPEEDFAX_PCI 3
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
#define SEDL_ISA_ISAC 4
#define SEDL_ISA_ISAR 6
#define SEDL_ISA_ADR 8
#define SEDL_ISA_RESET_ON 10
#define SEDL_ISA_RESET_OFF 12
#define SEDL_PCI_ADR 0xc8
#define SEDL_PCI_ISAC 0xd0
#define SEDL_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 SEDL_AUX_IOMASK 0xdd /* 1 and 5 are inputs */
#define SEDL_ISAR_RESET_BIT_OFF 0x00
#define SEDL_ISAR_RESET_BIT_ON 0x01
#define SEDL_TIGER_IRQ_BIT 0x02
#define SEDL_ISAR_PCI_LED1_BIT 0x08
#define SEDL_ISAR_PCI_LED2_BIT 0x10
#define SEDL_PCI_RESET_ON (SEDL_ISAR_RESET_BIT_ON)
#define SEDL_PCI_RESET_OFF (SEDL_ISAR_PCI_LED1_BIT | SEDL_ISAR_PCI_LED2_BIT)
#define SEDL_RESET 0x3 /* same as DOS driver */
/* data struct */
typedef struct _sedl_fax {
struct list_head list;
union {
#if defined(CONFIG_PNP)
#ifdef NEW_ISAPNP
struct pnp_dev *pnp;
#else
struct pci_dev *pnp;
#endif
#endif
struct pci_dev *pci;
} dev;
u_int subtyp;
u_int irq;
u_int irqcnt;
u_int cfg;
u_int addr;
u_int isac;
u_int isar;
spinlock_t lock;
isar_reg_t ir;
isac_chip_t isac_hw;
isar_hw_t isar_hw[2];
channel_t dch;
channel_t bch[2];
} sedl_fax;
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
byteout(ale, off);
return (bytein(adr));
}
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(void *p, u_char offset)
{
return (readreg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isac, offset));
}
static void
WriteISAC(void *p, u_char offset, u_char value)
{
writereg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isac, offset, value);
}
static void
ReadISACfifo(void *p, u_char * data, int size)
{
readfifo(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isac, 0, data, size);
}
static void
WriteISACfifo(void *p, u_char * data, int size)
{
writefifo(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isac, 0, data, size);
}
/* ISAR access routines
* mode = 0 access with IRQ on
* mode = 1 access with IRQ off
* mode = 2 access with IRQ off and using last offset
*/
static u_char
ReadISAR(void *p, u_char offset)
{
return (readreg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, offset));
}
static void
WriteISAR(void *p, u_char offset, u_char value)
{
writereg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, offset, value);
}
static void
ReadISARfifo(void *p, u_char * data, int size)
{
readfifo(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, ISAR_MBOX, data, size);
}
static void
WriteISARfifo(void *p, u_char * data, int size)
{
writefifo(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, ISAR_MBOX, data, size);
}
inline void
do_sedl_interrupt(sedl_fax *sf)
{
u_char val;
int cnt = 8;
val = readreg(sf->addr, sf->isar, ISAR_IRQBIT);
Start_ISAR:
if (val & ISAR_IRQSTA)
isar_int_main(&sf->bch[0]);
val = readreg(sf->addr, sf->isac, ISAC_ISTA);
Start_ISAC:
if (val)
mISDN_isac_interrupt(&sf->dch, val);
val = readreg(sf->addr, sf->isar, ISAR_IRQBIT);
if ((val & ISAR_IRQSTA) && cnt) {
cnt--;
if (sf->dch.debug & L1_DEB_HSCX)
printk(KERN_DEBUG "ISAR IntStat after IntRoutine cpu%d\n",
smp_processor_id());
goto Start_ISAR;
}
val = readreg(sf->addr, sf->isac, ISAC_ISTA);
if (val && cnt) {
cnt--;
if (sf->dch.debug & L1_DEB_ISAC)
printk(KERN_DEBUG "ISAC IntStat after IntRoutine cpu%d\n",
smp_processor_id());
goto Start_ISAC;
}
if (!cnt)
if (sf->dch.debug & L1_DEB_ISAC)
printk(KERN_DEBUG "Sedlbauer IRQ LOOP\n");
writereg(sf->addr, sf->isar, ISAR_IRQBIT, 0);
writereg(sf->addr, sf->isac, ISAC_MASK, 0xFF);
writereg(sf->addr, sf->isac, ISAC_MASK, 0x0);
writereg(sf->addr, sf->isar, ISAR_IRQBIT, ISAR_IRQMSK);
}
static irqreturn_t
speedfax_isa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
sedl_fax *sf = dev_id;
spin_lock(&sf->lock);
sf->irqcnt++;
do_sedl_interrupt(sf);
spin_unlock(&sf->lock);
return IRQ_HANDLED;
}
static irqreturn_t
speedfax_pci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
sedl_fax *sf = dev_id;
u_char val;
spin_lock(&sf->lock);
val = bytein(sf->cfg + TIGER_AUX_STATUS);
if (val & SEDL_TIGER_IRQ_BIT) { /* for us or shared ? */
spin_unlock(&sf->lock);
return IRQ_NONE; /* shared */
}
sf->irqcnt++;
do_sedl_interrupt(sf);
spin_unlock(&sf->lock);
return IRQ_HANDLED;
}
static void
enable_hwirq(sedl_fax *sf)
{
WriteISAC(sf, ISAC_MASK, 0);
WriteISAR(sf, ISAR_IRQBIT, ISAR_IRQMSK);
if (sf->subtyp != SEDL_SPEEDFAX_ISA)
byteout(sf->cfg + TIGER_AUX_IRQMASK, SEDL_TIGER_IRQ_BIT);
}
static void
disable_hwirq(sedl_fax *sf)
{
WriteISAC(sf, ISAC_MASK, 0xFF);
WriteISAR(sf, ISAR_IRQBIT, 0);
if (sf->subtyp != SEDL_SPEEDFAX_ISA)
byteout(sf->cfg + TIGER_AUX_IRQMASK, 0);
}
void
release_sedlbauer(sedl_fax *sf)
{
int bytecnt = 256;
if (sf->subtyp == SEDL_SPEEDFAX_ISA)
bytecnt = 16;
if (sf->cfg)
release_region(sf->cfg, bytecnt);
}
static void
reset_speedfax(sedl_fax *sf)
{
printk(KERN_INFO "Sedlbauer: resetting card\n");
if (sf->subtyp == SEDL_SPEEDFAX_ISA) {
byteout(sf->cfg + SEDL_ISA_RESET_ON, SEDL_RESET);
mdelay(1);
byteout(sf->cfg + SEDL_ISA_RESET_OFF, 0);
mdelay(1);
} else {
byteout(sf->cfg + TIGER_RESET_ADDR, TIGER_EXTERN_RESET_ON);
byteout(sf->cfg + TIGER_AUX_DATA, SEDL_PCI_RESET_ON);
mdelay(1);
byteout(sf->cfg + TIGER_RESET_ADDR, TIGER_EXTERN_RESET_OFF);
byteout(sf->cfg + TIGER_AUX_DATA, SEDL_PCI_RESET_OFF);
mdelay(1);
}
}
static int init_card(sedl_fax *sf)
{
int cnt = 3;
u_long flags;
u_int shared = SA_SHIRQ;
void *irq_func = speedfax_pci_interrupt;
if (sf->subtyp == SEDL_SPEEDFAX_ISA) {
irq_func = speedfax_isa_interrupt;
shared = 0;
}
if (request_irq(sf->irq, irq_func, shared, "speedfax", sf)) {
printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n",
sf->irq);
return(-EIO);
}
spin_lock_irqsave(&sf->lock, flags);
while (cnt) {
int ret;
mISDN_clear_isac(&sf->dch);
if ((ret=mISDN_isac_init(&sf->dch))) {
printk(KERN_WARNING "mISDN: mISDN_isac_init failed with %d\n", ret);
break;
}
init_isar(&sf->bch[0]);
init_isar(&sf->bch[1]);
enable_hwirq(sf);
/* RESET Receiver and Transmitter */
WriteISAC(sf, ISAC_CMDR, 0x41);
spin_unlock_irqrestore(&sf->lock, flags);
current->state = TASK_UNINTERRUPTIBLE;
/* Timeout 10ms */
schedule_timeout((10*HZ)/1000);
printk(KERN_INFO "%s: IRQ %d count %d\n",
sf->dch.inst.name, sf->irq, sf->irqcnt);
if (!sf->irqcnt) {
printk(KERN_WARNING
"Sedlbauer speedfax: IRQ(%d) getting no interrupts during init %d\n",
sf->irq, 4 - cnt);
if (cnt == 1) {
return (-EIO);
} else {
spin_lock_irqsave(&sf->lock, flags);
reset_speedfax(sf);
cnt--;
}
} else {
return(0);
}
}
spin_unlock_irqrestore(&sf->lock, flags);
return(-EIO);
}
#define MAX_CARDS 4
#define MODULE_PARM_T "1-4i"
static int sedl_cnt;
static mISDNobject_t speedfax;
static uint debug;
static uint protocol_num;
static uint layermask_num;
static uint protocol[MAX_CARDS];
static uint layermask[MAX_CARDS];
#ifdef MODULE
MODULE_AUTHOR("Karsten Keil");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
module_param (debug, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC (debug, "sedlfax debug mask");
#ifdef OLD_MODULE_PARAM_ARRAY
module_param_array(protocol, uint, protocol_num, S_IRUGO | S_IWUSR);
module_param_array(layermask, uint, layermask_num, S_IRUGO | S_IWUSR);
#else
module_param_array(protocol, uint, &protocol_num, S_IRUGO | S_IWUSR);
module_param_array(layermask, uint, &layermask_num, S_IRUGO | S_IWUSR);
#endif
MODULE_PARM_DESC (protocol, "sedlfax protcol (DSS1 := 2)");
MODULE_PARM_DESC(layermask, "sedlfax layer mask");
#endif
static char SpeedfaxName[] = "Speedfax";
int
setup_speedfax(sedl_fax *sf)
{
int bytecnt, ver;
u_long flags;
bytecnt = (sf->subtyp == SEDL_SPEEDFAX_ISA) ? 16 : 256;
if (!request_region(sf->cfg, bytecnt, (sf->subtyp == SEDL_SPEEDFAX_ISA) ? "sedl PnP" : "sedl PCI")) {
printk(KERN_WARNING
"mISDN: %s config port %x-%x already in use\n",
"Speedfax +",
sf->cfg,
sf->cfg + bytecnt - 1);
return(-EIO);
}
sf->dch.read_reg = &ReadISAC;
sf->dch.write_reg = &WriteISAC;
sf->dch.read_fifo = &ReadISACfifo;
sf->dch.write_fifo = &WriteISACfifo;
sf->dch.hw = &sf->isac_hw;
if (sf->subtyp != SEDL_SPEEDFAX_ISA) {
sf->addr = sf->cfg + SEDL_PCI_ADR;
sf->isac = sf->cfg + SEDL_PCI_ISAC;
sf->isar = sf->cfg + SEDL_PCI_ISAR;
byteout(sf->cfg + TIGER_RESET_ADDR, 0xff);
mdelay(1);
byteout(sf->cfg + TIGER_RESET_ADDR, 0x00);
mdelay(1);
byteout(sf->cfg + TIGER_AUX_CTRL, SEDL_AUX_IOMASK);
byteout(sf->cfg + TIGER_AUX_IRQMASK, 0);
byteout(sf->cfg + TIGER_AUX_DATA, SEDL_PCI_RESET_ON);
mdelay(1);
byteout(sf->cfg + TIGER_AUX_DATA, SEDL_PCI_RESET_OFF);
mdelay(1);
} else {
sf->addr = sf->cfg + SEDL_ISA_ADR;
sf->isac = sf->cfg + SEDL_ISA_ISAC;
sf->isar = sf->cfg + SEDL_ISA_ISAR;
}
sf->isar_hw[0].reg = &sf->ir;
sf->isar_hw[1].reg = &sf->ir;
sf->bch[0].hw = &sf->isar_hw[0];
sf->bch[1].hw = &sf->isar_hw[1];
sf->bch[0].read_reg = &ReadISAR;
sf->bch[0].write_reg = &WriteISAR;
sf->bch[0].read_fifo = &ReadISARfifo;
sf->bch[0].write_fifo = &WriteISARfifo;
sf->bch[1].read_reg = &ReadISAR;
sf->bch[1].write_reg = &WriteISAR;
sf->bch[1].read_fifo = &ReadISARfifo;
sf->bch[1].write_fifo = &WriteISARfifo;
spin_lock_irqsave(&sf->lock, flags);
disable_hwirq(sf);
ver = ISARVersion(&sf->bch[0], "Sedlbauer:");
spin_unlock_irqrestore(&sf->lock, flags);
if (ver < 0) {
printk(KERN_WARNING
"Sedlbauer: wrong ISAR version (ret = %d)\n", ver);
release_sedlbauer(sf);
return (-EIO);
}
return (0);
}
static void
release_card(sedl_fax *card) {
u_long flags;
spin_lock_irqsave(&card->lock, flags);
disable_hwirq(card);
spin_unlock_irqrestore(&card->lock, flags);
free_irq(card->irq, card);
spin_lock_irqsave(&card->lock, flags);
free_isar(&card->bch[1]);
free_isar(&card->bch[0]);
mISDN_isac_free(&card->dch);
release_sedlbauer(card);
mISDN_freechannel(&card->bch[1]);
mISDN_freechannel(&card->bch[0]);
mISDN_freechannel(&card->dch);
spin_unlock_irqrestore(&card->lock, flags);
speedfax.ctrl(&card->dch.inst, MGR_UNREGLAYER | REQUEST, NULL);
spin_lock_irqsave(&speedfax.lock, flags);
list_del(&card->list);
spin_unlock_irqrestore(&speedfax.lock, flags);
if (card->subtyp == SEDL_SPEEDFAX_ISA) {
#if defined(CONFIG_PNP)
pnp_disable_dev(card->dev.pnp);
pnp_set_drvdata(card->dev.pnp, NULL);
#endif
} else {
pci_disable_device(card->dev.pci);
pci_set_drvdata(card->dev.pci, NULL);
}
kfree(card);
sedl_cnt--;
}
static int
speedfax_manager(void *data, u_int prim, void *arg) {
sedl_fax *card;
mISDNinstance_t *inst=data;
int channel = -1;
struct sk_buff *skb;
u_long flags;
if (debug & MISDN_DEBUG_MANAGER)
printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n",
__FUNCTION__, data, prim, arg);
if (!data) {
MGR_HASPROTOCOL_HANDLER(prim,arg,&speedfax)
printk(KERN_ERR "speedfax_manager no data prim %x arg %p\n",
prim, arg);
return(-EINVAL);
}
spin_lock_irqsave(&speedfax.lock, flags);
list_for_each_entry(card, &speedfax.ilist, list) {
if (&card->dch.inst == inst) {
channel = 2;
break;
}
if (&card->bch[0].inst == inst) {
channel = 0;
break;
}
if (&card->bch[1].inst == inst) {
channel = 1;
break;
}
}
spin_unlock_irqrestore(&speedfax.lock, flags);
if (channel<0) {
printk(KERN_ERR "speedfax_manager no channel data %p prim %x arg %p\n",
data, prim, arg);
return(-EINVAL);
}
if (debug & MISDN_DEBUG_MANAGER)
printk(KERN_DEBUG "%s: channel %d\n", __FUNCTION__, channel);
switch(prim) {
case MGR_REGLAYER | CONFIRM:
if (channel == 2)
mISDN_setpara(&card->dch, &inst->st->para);
else
mISDN_setpara(&card->bch[channel], &inst->st->para);
break;
case MGR_UNREGLAYER | REQUEST:
if ((skb = create_link_skb(PH_CONTROL | REQUEST,
HW_DEACTIVATE, 0, NULL, 0))) {
if (channel == 2) {
if (mISDN_ISAC_l1hw(inst, skb))
dev_kfree_skb(skb);
} else {
if (isar_down(inst, skb))
dev_kfree_skb(skb);
}
} else
printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__);
speedfax.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
break;
case MGR_CLRSTPARA | INDICATION:
arg = NULL;
case MGR_ADDSTPARA | INDICATION:
if (channel == 2)
mISDN_setpara(&card->dch, arg);
else
mISDN_setpara(&card->bch[channel], arg);
break;
case MGR_RELEASE | INDICATION:
if (channel == 2) {
release_card(card);
} else {
speedfax.refcnt--;
}
break;
#ifdef OBSOLETE
case MGR_CONNECT | REQUEST:
return(mISDN_ConnectIF(inst, arg));
case MGR_SETIF | REQUEST:
case MGR_SETIF | INDICATION:
if (channel==2)
return(mISDN_SetIF(inst, arg, prim, mISDN_ISAC_l1hw, NULL, &card->dch));
else
return(mISDN_SetIF(inst, arg, prim, isar_down, NULL, &card->bch[channel]));
case MGR_DISCONNECT | REQUEST:
case MGR_DISCONNECT | INDICATION:
return(mISDN_DisConnectIF(inst, arg));
#endif
case MGR_LOADFIRM | REQUEST:
{
struct firm {
int len;
void *data;
} *firm = arg;
if (!arg)
return(-EINVAL);
return(isar_load_firmware(&card->bch[0], firm->data, firm->len));
}
case MGR_LOADFIRM | CONFIRM:
speedfax.ctrl(card->dch.inst.st, MGR_CTRLREADY | INDICATION, NULL);
break;
case MGR_SETSTACK | INDICATION:
if ((channel!=2) && (inst->pid.global == 2)) {
// inst->down.fdata = &card->bch[channel];
if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
0, 0, NULL, 0))) {
if (isar_down(inst, skb))
dev_kfree_skb(skb);
}
if ((inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS) ||
(inst->pid.protocol[2] == ISDN_PID_L2_B_TRANSDTMF))
mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
0, 0, NULL, 0);
else
mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
0, 0, NULL, 0);
}
break;
PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
PRIM_NOT_HANDLED(MGR_GLOBALOPT | REQUEST);
default:
printk(KERN_WARNING "speedfax_manager prim %x not handled\n", prim);
return(-EINVAL);
}
return(0);
}
static int __devinit setup_instance(sedl_fax *card)
{
int i, err;
mISDN_pid_t pid;
struct device *dev;
u_long flags;
if (sedl_cnt >= MAX_CARDS) {
kfree(card);
return(-EINVAL);
}
if (card->subtyp == SEDL_SPEEDFAX_ISA) {
#if defined(CONFIG_PNP)
dev = &card->dev.pnp->dev;
#else
dev = NULL;
#endif
} else {
dev = &card->dev.pci->dev;
}
spin_lock_irqsave(&speedfax.lock, flags);
list_add_tail(&card->list, &speedfax.ilist);
spin_unlock_irqrestore(&speedfax.lock, flags);
card->dch.debug = debug;
spin_lock_init(&card->lock);
card->dch.inst.hwlock = &card->lock;
card->dch.inst.pid.layermask = ISDN_LAYER(0);
card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
card->dch.inst.class_dev.dev = dev;
mISDN_init_instance(&card->dch.inst, &speedfax, card, mISDN_ISAC_l1hw);
sprintf(card->dch.inst.name, "SpeedFax%d", sedl_cnt+1);
mISDN_set_dchannel_pid(&pid, protocol[sedl_cnt], layermask[sedl_cnt]);
mISDN_initchannel(&card->dch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
for (i=0; i<2; i++) {
card->bch[i].channel = i;
mISDN_init_instance(&card->bch[i].inst, &speedfax, card, isar_down);
card->bch[i].inst.pid.layermask = ISDN_LAYER(0);
card->bch[i].inst.hwlock = &card->lock;
card->bch[i].debug = debug;
card->bch[i].inst.class_dev.dev = dev;
sprintf(card->bch[i].inst.name, "%s B%d", card->dch.inst.name, i+1);
mISDN_initchannel(&card->bch[i], MSK_INIT_BCHANNEL, MAX_DATA_MEM);
}
printk(KERN_DEBUG "sfax card %p dch %p bch1 %p bch2 %p\n",
card, &card->dch, &card->bch[0], &card->bch[1]);
err = setup_speedfax(card);
if (err) {
mISDN_freechannel(&card->dch);
mISDN_freechannel(&card->bch[1]);
mISDN_freechannel(&card->bch[0]);
spin_lock_irqsave(&speedfax.lock, flags);
list_del(&card->list);
spin_unlock_irqrestore(&speedfax.lock, flags);
kfree(card);
return(err);
}
sedl_cnt++;
err = speedfax.ctrl(NULL, MGR_NEWSTACK | REQUEST, &card->dch.inst);
if (err) {
release_card(card);
return(err);
}
speedfax.ctrl(card->dch.inst.st, MGR_STOPSTACK | REQUEST, NULL);
for (i=0; i<2; i++) {
err = speedfax.ctrl(card->dch.inst.st, MGR_NEWSTACK | REQUEST, &card->bch[i].inst);
if (err) {
printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
speedfax.ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
return(err);
}
}
err = speedfax.ctrl(card->dch.inst.st, MGR_SETSTACK | REQUEST, &pid);
if (err) {
printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", err);
speedfax.ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
return(err);
}
err = init_card(card);
if (err) {
speedfax.ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
return(err);
}
speedfax.ctrl(card->dch.inst.st, MGR_STARTSTACK | REQUEST, NULL);
printk(KERN_INFO "SpeedFax %d cards installed\n", sedl_cnt);
return(0);
}
static int __devinit sedlpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int err = -ENOMEM;
sedl_fax *card;
if (!(card = kmalloc(sizeof(sedl_fax), GFP_ATOMIC))) {
printk(KERN_ERR "No kmem for Speedfax + PCI\n");
return(err);
}
memset(card, 0, sizeof(sedl_fax));
card->dev.pci = pdev;
if (PCI_SUBVENDOR_SPEEDFAX_PYRAMID == pdev->subsystem_vendor)
card->subtyp = SEDL_SPEEDFAX_PYRAMID;
else
card->subtyp = SEDL_SPEEDFAX_PCI;
err = pci_enable_device(pdev);
if (err) {
kfree(card);
return(err);
}
printk(KERN_INFO "mISDN: sedlpci 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);
}
#if defined(CONFIG_PNP)
#ifdef NEW_ISAPNP
static int __devinit sedlpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
#else
static int __devinit sedlpnp_probe(struct pci_dev *pdev, const struct isapnp_device_id *dev_id)
#endif
{
int err;
sedl_fax *card;
if (!pdev)
return(-ENODEV);
if (!(card = kmalloc(sizeof(sedl_fax), GFP_ATOMIC))) {
printk(KERN_ERR "No kmem for Speedfax + PnP\n");
return(-ENOMEM);
}
memset(card, 0, sizeof(sedl_fax));
card->subtyp = SEDL_SPEEDFAX_ISA;
card->dev.pnp = pdev;
pnp_disable_dev(pdev);
err = pnp_activate_dev(pdev);
if (err<0) {
printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __FUNCTION__,
(char *)dev_id->driver_data, err);
kfree(card);
return(err);
}
card->cfg = pnp_port_start(pdev, 0);
card->irq = pnp_irq(pdev, 0);
printk(KERN_INFO "mISDN: sedlpnp_probe found adapter %s at IO %#x irq %d\n",
(char *)dev_id->driver_data, card->addr, card->irq);
pnp_set_drvdata(pdev, card);
err = setup_instance(card);
if (err)
pnp_set_drvdata(pdev, NULL);
return(err);
}
#endif /* CONFIG_PNP */
static void __devexit sedl_remove_pci(struct pci_dev *pdev)
{
sedl_fax *card = pci_get_drvdata(pdev);
if (card)
speedfax.ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
else
printk(KERN_WARNING "%s: drvdata allready removed\n", __FUNCTION__);
}
#if defined(CONFIG_PNP)
#ifdef NEW_ISAPNP
static void __devexit sedl_remove_pnp(struct pnp_dev *pdev)
#else
static void __devexit sedl_remove_pnp(struct pci_dev *pdev)
#endif
{
sedl_fax *card = pnp_get_drvdata(pdev);
if (card)
speedfax.ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
else
printk(KERN_WARNING "%s: drvdata allready removed\n", __FUNCTION__);
}
#endif
static struct pci_device_id sedlpci_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, sedlpci_ids);
static struct pci_driver sedlpci_driver = {
name: "speedfax pci",
probe: sedlpci_probe,
remove: __devexit_p(sedl_remove_pci),
id_table: sedlpci_ids,
};
#if defined(CONFIG_PNP)
#ifdef NEW_ISAPNP
static struct pnp_device_id sedlpnp_ids[] __devinitdata = {
{
.id = "SAG0002",
.driver_data = (unsigned long) "Speedfax + PnP",
},
};
static struct pnp_driver sedlpnp_driver = {
#else
static struct isapnp_device_id sedlpnp_ids[] __devinitdata = {
{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
(unsigned long) "Speedfax + PnP" },
{ }
};
MODULE_DEVICE_TABLE(isapnp, sedlpnp_ids);
static struct isapnp_driver sedlpnp_driver = {
#endif
name: "speedfax pnp",
probe: sedlpnp_probe,
remove: __devexit_p(sedl_remove_pnp),
id_table: sedlpnp_ids,
};
#endif /* CONFIG_PNP */
static int __init Speedfax_init(void)
{
int err;
#ifdef OLD_PCI_REGISTER_DRIVER
int pci_nr_found;
#endif
#ifdef MODULE
speedfax.owner = THIS_MODULE;
#endif
spin_lock_init(&speedfax.lock);
INIT_LIST_HEAD(&speedfax.ilist);
speedfax.name = SpeedfaxName;
speedfax.own_ctrl = speedfax_manager;
speedfax.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0;
speedfax.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS |
ISDN_PID_L1_B_64HDLC |
ISDN_PID_L1_B_T30FAX |
ISDN_PID_L1_B_MODEM_ASYNC;
speedfax.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS |
ISDN_PID_L2_B_T30;
if ((err = mISDN_register(&speedfax))) {
printk(KERN_ERR "Can't register Speedfax error(%d)\n", err);
return(err);
}
err = pci_register_driver(&sedlpci_driver);
if (err < 0)
goto out;
#ifdef OLD_PCI_REGISTER_DRIVER
pci_nr_found = err;
#endif
#if defined(CONFIG_PNP)
err = pnp_register_driver(&sedlpnp_driver);
if (err < 0)
goto out_unregister_pci;
#endif
#ifdef OLD_PCI_REGISTER_DRIVER
#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
if (pci_nr_found + err == 0) {
err = -ENODEV;
goto out_unregister_isapnp;
}
#endif
#endif
return 0;
#ifdef OLD_PCI_REGISTER_DRIVER
#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
out_unregister_isapnp:
#if defined(CONFIG_PNP)
pnp_unregister_driver(&sedlpnp_driver);
#endif
#endif
#endif
#if defined(CONFIG_PNP)
out_unregister_pci:
#endif
pci_unregister_driver(&sedlpci_driver);
out:
return err;
}
static void __exit Speedfax_cleanup(void)
{
int err;
sedl_fax *card, *next;
if ((err = mISDN_unregister(&speedfax))) {
printk(KERN_ERR "Can't unregister Speedfax PCI error(%d)\n", err);
}
list_for_each_entry_safe(card, next, &speedfax.ilist, list) {
printk(KERN_ERR "Speedfax PCI card struct not empty refs %d\n",
speedfax.refcnt);
release_card(card);
}
#if defined(CONFIG_PNP)
pnp_unregister_driver(&sedlpnp_driver);
#endif
pci_unregister_driver(&sedlpci_driver);
}
module_init(Speedfax_init);
module_exit(Speedfax_cleanup);