Commit 4a0540b8 authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN: Add support for Formula-n enter:now, a.k.a. Gerdes Power ISDN

(by Christoph Ersfeld/Karsten Keil)
parent db72b2ad
......@@ -68,6 +68,8 @@ Gazel ISDN cards
HFC-PCI based cards
Winbond W6692 based cards
HFC-S+, HFC-SP/PCMCIA cards
formula-n enternow
Gerdes Power ISDN
Note: PCF, PCF-Pro: up to now, only the ISDN part is supported
PCC-8: not tested yet
......@@ -192,6 +194,8 @@ Card types:
37 HFC 2BDS0 S+, SP irq,io
38 NETspider U PCI card none
39 HFC 2BDS0 SP/PCMCIA irq,io (set with cardmgr)
40 hotplug interface
41 Formula-n enter:now PCI none
At the moment IRQ sharing is only possible with PCI cards. Please make sure
that your IRQ is free and enabled for ISA use.
......@@ -297,7 +301,9 @@ type
36 W6692 based PCI cards none
37 HFC 2BDS0 S+,SP/PCMCIA ONLY WORKS AS A MODULE !
38 NETspider U PCI card none
39 HFC 2BDS0 SP/PCMCIA ONLY WORKS AS A MODULE !
40 hotplug interface ONLY WORKS AS A MODULE !
41 Formula-n enter:now PCI none
Running the driver
------------------
......
......@@ -43,6 +43,7 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
bool ' HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
# bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
bool ' Formula-n enter:now PCI card' CONFIG_HISAX_ENTERNOW_PCI
if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
bool ' Am7930' CONFIG_HISAX_AMD7930
fi
......
......@@ -57,6 +57,7 @@ hisax-objs-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o
hisax-objs-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_W6692) += w6692.o
hisax-objs-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o
#hisax-objs-$(CONFIG_HISAX_TESTEMU) += testemu.o
hisax-objs += $(hisax-objs-y)
......
/* 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
* neccessary 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.
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include "isdnl1.h"
#include "isac.h"
#include "amd7930_fn.h"
#include <linux/interrupt.h>
#include <linux/init.h>
static void Amd7930_new_ph(struct IsdnCardState *cs);
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));
}
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 IsdnCardState *cs)
{
struct PStack *stptr;
if (!cs)
return;
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->l2.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);
}
}
void
Amd7930_sched_event(struct IsdnCardState *cs, int event) // ok
{
if (cs->debug & L1_DEB_ISAC) {
debugl1(cs, "AMD7930: sched_event 0x%X", event);
}
test_and_set_bit(event, &cs->event);
queue_task(&cs->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
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, cs->dlog);
}
/* moves recieved data in sk-buffer */
memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx);
skb_queue_tail(&cs->rq, skb);
}
}
}
/* throw damaged packets away, reset recieve-buffer, indicate RX */
ptr = cs->rcvbuf;
cs->rcvidx = 0;
Amd7930_sched_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);
}
init_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, 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))
Amd7930_sched_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))
Amd7930_sched_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))
Amd7930_sched_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))
Amd7930_sched_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
Amd7930_sched_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;
Amd7930_sched_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;
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);
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);
}
break;
case (PH_PULL | INDICATION):
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);
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);
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->l2.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (HW_RESET | REQUEST):
if ((cs->dc.amd7930.ph_state == 8))
/* b-channels off, PH-AR cleared
* change to F3 */
Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5
else {
Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
cs->dc.amd7930.ph_state = 2;
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))
Amd7930_sched_event(cs, D_CLEARBUSY);
break;
default:
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
break;
}
}
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;
}
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 IsdnCardState *cs)
{
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)) {
/* 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;
while (stptr != NULL) {
stptr->l2.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);
cs->irq_func(cs->irq, cs, NULL);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
}
}
}
void __devinit
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->tqueue.routine = (void *) (void *) Amd7930_bh;
cs->setstack_d = setstack_Amd7930;
cs->DC_Close = DC_Close_Amd7930;
cs->dbusytimer.function = (void *) dbusy_timer_handler;
cs->dbusytimer.data = (long) cs;
init_timer(&cs->dbusytimer);
/* AMD Initialisation */
for (ptr = initAMD; *ptr != 0xFFFF; ) {
cmd = LOBYTE(*ptr);
/* read */
if (*ptr++ >= 0x100) {
if (cmd < 8)
/* setzt Register zurck */
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++));
}
}
}
/* 2001/10/02
*
* 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
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};
extern void Amd7930_interrupt(struct IsdnCardState *cs, unsigned char irflags);
extern void Amd7930_init(struct IsdnCardState *cs);
......@@ -75,6 +75,8 @@
* 37 HFC 2BDS0 S+/SP p0=irq p1=iobase
* 38 Travers Technologies NETspider-U PCI card
* 39 HFC 2BDS0-SP PCMCIA p0=irq p1=iobase
* 40 hotplug interface
* 41 Formula-n enter:now ISDN PCI a/b none
*
* protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
*
......@@ -93,6 +95,7 @@ const char *CardType[] = {
"Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T",
"Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
"HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
"Hotplug", "Formula-n enter:now PCI a/b",
};
void HiSax_closecard(int cardnr);
......@@ -601,6 +604,10 @@ extern int setup_w6692(struct IsdnCard *card);
extern int setup_netjet_u(struct IsdnCard *card);
#endif
#if CARD_FN_ENTERNOW_PCI
extern int setup_enternow_pci(struct IsdnCard *card);
#endif
/*
* Find card with given driverId
*/
......@@ -1137,6 +1144,11 @@ static int __devinit checkcard(int cardnr, char *id, int *busy_flag)
case ISDN_CTYPE_NETJET_U:
ret = setup_netjet_u(card);
break;
#endif
#if CARD_FN_ENTERNOW_PCI
case ISDN_CTYPE_ENTERNOW:
ret = setup_enternow_pci(card);
break;
#endif
case ISDN_CTYPE_DYNAMIC:
ret = 2;
......
/* 2001/10/02
*
* enternow.h Header-file included by
* enternow_pci.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
*/
/* ***************************************************************************************** *
* ****************************** datatypes and macros ************************************* *
* ***************************************************************************************** */
#define BYTE unsigned char
#define WORD unsigned int
#define HIBYTE(w) ((unsigned char)((w & 0xff00) / 256))
#define LOBYTE(w) ((unsigned char)(w & 0x00ff))
#define InByte(addr) inb(addr)
#define OutByte(addr,val) outb(val,addr)
/* ***************************************************************************************** *
* *********************************** card-specific *************************************** *
* ***************************************************************************************** */
/* fr PowerISDN PCI */
#define TJ_AMD_IRQ 0x20
#define TJ_LED1 0x40
#define TJ_LED2 0x80
/* Das Fenster zum AMD...
* Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in
* den TigerJet i/o-Raum gemappt
* -> 0x01 des AMD bei hw.njet.base + 0C4 */
#define TJ_AMD_PORT 0xC0
/* ***************************************************************************************** *
* *************************************** Prototypen ************************************** *
* ***************************************************************************************** */
BYTE ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset);
void WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value);
/* 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
* neccessary 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.
*
*/
#define __NO_VERSION__
#include <linux/config.h>
#include "hisax.h"
#include "isac.h"
#include "isdnl1.h"
#include "amd7930_fn.h"
#include "enternow.h"
#include <linux/interrupt.h>
#include <linux/ppp_defs.h>
#include <linux/pci.h>
#include <linux/init.h>
#include "netjet.h"
const char *enternow_pci_rev = "$Revision: 1.1.2.1 $";
/* *************************** I/O-Interface functions ************************************* */
/* cs->readisac, macro rByteAMD */
BYTE
ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset)
{
/* direktes Register */
if(offset < 8)
return (InByte(cs->hw.njet.isac + 4*offset));
/* indirektes Register */
else {
OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
return(InByte(cs->hw.njet.isac + 4*AMD_DR));
}
}
/* cs->writeisac, macro wByteAMD */
void
WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value)
{
/* direktes Register */
if(offset < 8)
OutByte(cs->hw.njet.isac + 4*offset, value);
/* indirektes Register */
else {
OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
OutByte(cs->hw.njet.isac + 4*AMD_DR, value);
}
}
void
enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) {
if (!val)
OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00);
else
OutByte(cs->hw.njet.base+NETJET_IRQMASK1, TJ_AMD_IRQ);
}
static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off)
{
return(5);
}
static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value)
{
}
/* ******************************************************************************** */
static void
reset_enpci(struct IsdnCardState *cs)
{
long flags;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: reset");
save_flags(flags);
sti();
/* Reset on, (also for AMD) */
cs->hw.njet.ctrl_reg = 0x07;
OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
set_current_state(TASK_UNINTERRUPTIBLE);
/* 80 ms delay */
schedule_timeout((80*HZ)/1000);
/* Reset off */
cs->hw.njet.ctrl_reg = 0x70;
OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
set_current_state(TASK_UNINTERRUPTIBLE);
/* 80ms delay */
schedule_timeout((80*HZ)/1000);
restore_flags(flags);
cs->hw.njet.auxd = 0; // LED-status
cs->hw.njet.dmactrl = 0;
OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off
}
static int
enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
BYTE *chan;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
switch (mt) {
case CARD_RESET:
reset_enpci(cs);
Amd7930_init(cs);
break;
case CARD_RELEASE:
release_io_netjet(cs);
break;
case CARD_INIT:
inittiger(cs);
Amd7930_init(cs);
break;
case CARD_TEST:
break;
case MDL_ASSIGN:
/* TEI assigned, LED1 on */
cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
break;
case MDL_REMOVE:
/* TEI removed, LEDs off */
cs->hw.njet.auxd = 0;
OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00);
break;
case MDL_BC_ASSIGN:
/* activate B-channel */
chan = (BYTE *)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;
OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
break;
case MDL_BC_RELEASE:
/* deactivate B-channel */
chan = (BYTE *)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);
OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
}
break;
default:
break;
}
return(0);
}
static void
enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
BYTE sval, ir;
long flags;
if (!cs) {
printk(KERN_WARNING "enter:now PCI: Spurious interrupt!\n");
return;
}
sval = InByte(cs->hw.njet.base + NETJET_IRQSTAT1);
/* AMD threw an interrupt */
if (!(sval & TJ_AMD_IRQ)) {
/* read and clear interrupt-register */
ir = ReadByteAmd7930(cs, 0x00);
Amd7930_interrupt(cs, ir);
}
/* DMA-Interrupt: B-channel-stuff */
/* set bits in sval to indicate which page is free */
save_flags(flags);
cli();
/* 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 */
sval = 0x08;
else /* the 1st write page is free */
sval = 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 */
sval = sval | 0x02;
else /* the 1st read page is free */
sval = sval | 0x01;
if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
{
if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
restore_flags(flags);
return;
}
cs->hw.njet.irqstat0 = sval;
restore_flags(flags);
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);
} else
restore_flags(flags);
}
static struct pci_dev *dev_netjet __initdata = NULL;
/* called by config.c */
int __init
setup_enternow_pci(struct IsdnCard *card)
{
int bytecnt;
struct IsdnCardState *cs = card->cs;
char tmp[64];
long flags;
#if CONFIG_PCI
#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 (!pci_present()) {
printk(KERN_ERR "enter:now PCI: no PCI bus present\n");
return(0);
}
if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
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);
}
} else {
printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
return(0);
}
cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
save_flags(flags);
sti();
/* Reset an */
cs->hw.njet.ctrl_reg = 0x07; // gendert von 0xff
OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
set_current_state(TASK_UNINTERRUPTIBLE);
/* 50 ms Pause */
schedule_timeout((50*HZ)/1000);
cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */
OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
restore_flags(flags);
cs->hw.njet.auxd = 0x00; // war 0xc0
cs->hw.njet.dmactrl = 0;
OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd);
break;
}
#else
printk(KERN_WARNING "enter:now PCI: NO_PCI_BIOS\n");
printk(KERN_WARNING "enter:now PCI: unable to config Formula-n enter:now ISDN PCI ab\n");
return (0);
#endif /* CONFIG_PCI */
bytecnt = 256;
printk(KERN_INFO
"enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
cs->hw.njet.base, cs->irq);
if (check_region(cs->hw.njet.base, bytecnt)) {
printk(KERN_WARNING
"HiSax: %s config port %lx-%lx already in use\n",
CardType[card->typ],
cs->hw.njet.base,
cs->hw.njet.base + bytecnt);
return (0);
} else {
request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN");
}
reset_enpci(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 |= SA_SHIRQ;
return (1);
}
......@@ -67,6 +67,9 @@
#define DL_DATA 0x0220
#define DL_FLUSH 0x0224
#define DL_UNIT_DATA 0x0230
#define MDL_BC_RELEASE 0x0278 // Formula-n enter:now
#define MDL_BC_ASSIGN 0x027C // Formula-n enter:now
#define MDL_ASSIGN 0x0280
#define MDL_REMOVE 0x0284
#define MDL_ERROR 0x0288
......@@ -835,6 +838,17 @@ struct w6692_chip {
int ph_state;
};
struct amd7930_chip {
u_char lmr1;
u_char ph_state;
u_char old_state;
u_char flg_t3;
unsigned int tx_xmtlen;
struct timer_list timer3;
void (*ph_command) (struct IsdnCardState *, u_char, char *);
void (*setIrqMask) (struct IsdnCardState *, u_char);
};
struct icc_chip {
int ph_state;
u_char *mon_tx;
......@@ -932,6 +946,7 @@ struct IsdnCardState {
struct hfcpci_chip hfcpci;
struct hfcsx_chip hfcsx;
struct w6692_chip w6692;
struct amd7930_chip amd7930;
struct icc_chip icc;
} dc;
u_char *rcvbuf;
......@@ -993,7 +1008,8 @@ struct IsdnCardState {
#define ISDN_CTYPE_NETJET_U 38
#define ISDN_CTYPE_HFC_SP_PCMCIA 39
#define ISDN_CTYPE_DYNAMIC 40
#define ISDN_CTYPE_COUNT 40
#define ISDN_CTYPE_ENTERNOW 41
#define ISDN_CTYPE_COUNT 41
#ifdef ISDN_CHIP_ISAC
......@@ -1252,6 +1268,10 @@ struct IsdnCardState {
#define CARD_NETJET_U 0
#endif
#ifdef CONFIG_HISAX_ENTERNOW_PCI
#define CARD_FN_ENTERNOW_PCI 1
#endif
#define TEI_PER_CARD 1
/* L1 Debug */
......
......@@ -858,9 +858,13 @@ tiger_l2l1(struct PStack *st, int pr, void *arg)
case (PH_ACTIVATE | REQUEST):
test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc);
/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
st->l1.bcs->cs->cardmsg(st->l1.bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc));
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
st->l1.bcs->cs->cardmsg(st->l1.bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc));
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
......
......@@ -184,6 +184,14 @@ setup_netjet_s(struct IsdnCard *card)
printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
return(0);
}
/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
if ((dev_netjet->subsystem_vendor == 0x55) &&
(dev_netjet->subsystem_device == 0x02)) {
printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
return(0);
}
/* end new code */
cs->hw.njet.pdev = dev_netjet;
} else {
printk(KERN_WARNING "NETjet-S: No PCI card found\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment