patch-2.0.36 linux/drivers/isdn/hisax/elsa.c
Next file: linux/drivers/isdn/hisax/elsa_ser.c
Previous file: linux/drivers/isdn/hisax/diva.c
Back to the patch index
Back to the overall index
- Lines: 2351
- Date:
Sun Nov 15 10:32:58 1998
- Orig file:
v2.0.35/linux/drivers/isdn/hisax/elsa.c
- Orig date:
Tue Aug 5 09:00:12 1997
diff -u --recursive --new-file v2.0.35/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c
@@ -1,1248 +1,876 @@
-/* $Id: elsa.c,v 1.14 1997/04/13 19:53:25 keil Exp $
+/* $Id: elsa.c,v 1.14.2.16 1998/11/05 21:13:55 keil Exp $
* elsa.c low level stuff for Elsa isdn cards
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ * For changes and modifications please read
+ * ../../../Documentation/isdn/HiSax.cert
*
* Thanks to Elsa GmbH for documents and informations
*
+ * Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE)
+ * for ELSA PCMCIA support
+ *
*
* $Log: elsa.c,v $
- * Revision 1.14 1997/04/13 19:53:25 keil
- * Fixed QS1000 init, change in IRQ check delay for SMP
+ * Revision 1.14.2.16 1998/11/05 21:13:55 keil
+ * minor fixes
*
- * Revision 1.13 1997/04/07 22:58:07 keil
- * need include config.h
+ * Revision 1.14.2.15 1998/11/03 00:06:14 keil
+ * certification related changes
+ * fixed logging for smaller stack use
*
- * Revision 1.12 1997/04/06 22:54:14 keil
- * Using SKB's
+ * Revision 1.14.2.14 1998/10/25 19:43:58 fritz
+ * Removed a compiler warning
+ *
+ * Revision 1.14.2.13 1998/10/25 17:47:48 fritz
+ * Line power status only valid for ISA cards.
+ *
+ * Revision 1.14.2.12 1998/09/27 13:05:53 keil
+ * Apply most changes from 2.1.X (HiSax 3.1)
*
- * Revision 1.11 1997/03/23 21:45:46 keil
- * Add support for ELSA PCMCIA
+ * Revision 1.14.2.11 1998/05/27 18:05:14 keil
+ * HiSax 3.0
*
- * Revision 1.10 1997/03/12 21:42:19 keil
- * Bugfix: IRQ hangs with QS1000
+ * Revision 1.14.2.10 1998/04/11 18:46:03 keil
+ * QS3000PCI support, changes for arcofi
*
- * Revision 1.9 1997/03/04 15:57:39 keil
- * bugfix IRQ reset Quickstep, ELSA PC changes, some stuff for new cards
+ * Revision 1.14.2.9 1998/04/08 21:44:36 keil
+ * new init; fix PCI for more as one card
*
- * Revision 1.8 1997/01/27 15:51:48 keil
- * SMP proof,cosmetics
+ * Revision 1.14.2.8 1998/03/07 23:15:15 tsbogend
+ * made HiSax working on Linux/Alpha
*
- * Revision 1.7 1997/01/21 22:20:48 keil
- * Elsa Quickstep support
+ * Revision 1.14.2.7 1998/01/27 22:37:36 keil
+ * fast io
*
- * Revision 1.6 1997/01/09 18:22:46 keil
- * one more PCC-8 fix
+ * Revision 1.14.2.6 1998/01/11 22:57:10 keil
+ * add PCMCIA maintainer Klaus
*
- * Revision 1.5 1996/12/08 19:46:14 keil
- * PCC-8 correct IRQs; starting ARCOFI support
+ * Revision 1.14.2.5 1997/11/15 18:50:47 keil
+ * new common init function
*
- * Revision 1.4 1996/11/18 20:50:54 keil
- * with PCF Pro release 16 Byte IO
+ * Revision 1.14.2.4 1997/10/17 22:13:44 keil
+ * update to last hisax version
*
- * Revision 1.3 1996/11/18 15:33:04 keil
- * PCC and PCFPro support
+ * Revision 2.1 1997/07/27 21:47:08 keil
+ * new interface structures
+ *
+ * Revision 2.0 1997/06/26 11:02:40 keil
+ * New Layer and card interface
+ *
+ * Revision 1.14 1997/04/13 19:53:25 keil
+ * Fixed QS1000 init, change in IRQ check delay for SMP
*
- * Revision 1.2 1996/10/27 22:08:03 keil
- * cosmetic changes
+ * Revision 1.13 1997/04/07 22:58:07 keil
+ * need include config.h
*
- * Revision 1.1 1996/10/13 20:04:52 keil
- * Initial revision
+ * Revision 1.12 1997/04/06 22:54:14 keil
+ * Using SKB's
*
+ * old changes removed KKe
*
*/
-#define ARCOFI_USE 0
-
#define __NO_VERSION__
#include <linux/config.h>
-#include "siemens.h"
#include "hisax.h"
-#include "elsa.h"
+#include "arcofi.h"
+#include "isac.h"
+#include "ipac.h"
+#include "hscx.h"
#include "isdnl1.h"
-#include <linux/kernel_stat.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
extern const char *CardType[];
-const char *Elsa_revision = "$Revision: 1.14 $";
+const char *Elsa_revision = "$Revision: 1.14.2.16 $";
const char *Elsa_Types[] =
{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
- "PCMCIA", "QS 1000", "QS 3000"};
+ "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI"};
const char *ITACVer[] =
{"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2",
"B1", "A1"};
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
-
-static inline u_char
-readhscx(unsigned int adr, int hscx, u_char off)
-{
- register u_char ret;
- long flags;
-
- save_flags(flags);
- cli();
- byteout(adr + CARD_ALE, off + (hscx ? 0x60 : 0x20));
- ret = bytein(adr + CARD_HSCX);
- restore_flags(flags);
- return (ret);
-}
-
-static inline void
-read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
-{
- /* fifo read without cli because it's allready done */
-
- byteout(adr + CARD_ALE, (hscx ? 0x40 : 0));
- insb(adr + CARD_HSCX, data, size);
-}
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+#define ELSA_ISAC 0
+#define ELSA_ISAC_PCM 1
+#define ELSA_ITAC 1
+#define ELSA_HSCX 2
+#define ELSA_ALE 3
+#define ELSA_ALE_PCM 4
+#define ELSA_CONTROL 4
+#define ELSA_CONFIG 5
+#define ELSA_START_TIMER 6
+#define ELSA_TRIG_IRQ 7
+
+#define ELSA_PC 1
+#define ELSA_PCC8 2
+#define ELSA_PCC16 3
+#define ELSA_PCF 4
+#define ELSA_PCFPRO 5
+#define ELSA_PCMCIA 6
+#define ELSA_QS1000 7
+#define ELSA_QS3000 8
+#define ELSA_QS1000PCI 9
+#define ELSA_QS3000PCI 10
+
+/* PCI stuff */
+#define PCI_VENDOR_ELSA 0x1048
+#define PCI_QS1000_ID 0x1000
+#define PCI_QS3000_ID 0x3000
+#define ELSA_PCI_IRQ_MASK 0x04
+
+/* ITAC Registeradressen (only Microlink PC) */
+#define ITAC_SYS 0x34
+#define ITAC_ISEN 0x48
+#define ITAC_RFIE 0x4A
+#define ITAC_XFIE 0x4C
+#define ITAC_SCIE 0x4E
+#define ITAC_STIE 0x46
+
+/*** ***
+ *** Makros als Befehle fuer die Kartenregister ***
+ *** (mehrere Befehle werden durch Bit-Oderung kombiniert) ***
+ *** ***/
+
+/* Config-Register (Read) */
+#define ELSA_TIMER_RUN 0x02 /* Bit 1 des Config-Reg */
+#define ELSA_TIMER_RUN_PCC8 0x01 /* Bit 0 des Config-Reg bei PCC */
+#define ELSA_IRQ_IDX 0x38 /* Bit 3,4,5 des Config-Reg */
+#define ELSA_IRQ_IDX_PCC8 0x30 /* Bit 4,5 des Config-Reg */
+#define ELSA_IRQ_IDX_PC 0x0c /* Bit 2,3 des Config-Reg */
+
+/* Control-Register (Write) */
+#define ELSA_LINE_LED 0x02 /* Bit 1 Gelbe LED */
+#define ELSA_STAT_LED 0x08 /* Bit 3 Gruene LED */
+#define ELSA_ISDN_RESET 0x20 /* Bit 5 Reset-Leitung */
+#define ELSA_ENA_TIMER_INT 0x80 /* Bit 7 Freigabe Timer Interrupt */
+
+/* ALE-Register (Read) */
+#define ELSA_HW_RELEASE 0x07 /* Bit 0-2 Hardwarerkennung */
+#define ELSA_S0_POWER_BAD 0x08 /* Bit 3 S0-Bus Spannung fehlt */
+
+/* Status Flags */
+#define ELSA_TIMER_AKTIV 1
+#define ELSA_BAD_PWR 2
+#define ELSA_ASSIGN 4
+
+#define RS_ISR_PASS_LIMIT 256
+#define _INLINE_ inline
+#define FLG_MODEM_ACTIVE 1
+/* IPAC AUX */
+#define ELSA_IPAC_LINE_LED 0x40 /* Bit 6 Gelbe LED */
+#define ELSA_IPAC_STAT_LED 0x80 /* Bit 7 Gruene LED */
+
+const u_char ARCOFI_VERSION[] = {2,0xa0,0};
+const u_char ARCOFI_COP_5[] = {4,0xa1,0x25,0xbb,0x4a}; /* GTX */
+const u_char ARCOFI_COP_6[] = {6,0xa1,0x26,0,0,0x82,0x7c}; /* GRL GRH */
+const u_char ARCOFI_COP_7[] = {4,0xa1,0x27,0x80,0x80}; /* GZ */
+const u_char ARCOFI_COP_8[] = {10,0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}; /* TX */
+const u_char ARCOFI_COP_9[] = {10,0xa1,0x29,0x80,0xcb,0xe9,0x88,0x00,0xc8,0xd8,0x80}; /* RX */
+const u_char ARCOFI_XOP_0[] = {2,0xa1,0x30}; /* PWR Down */
+const u_char ARCOFI_XOP_1[] = {2,0xa1,0x31}; /* PWR UP */
+const u_char ARCOFI_XOP_F[] = {2,0xa1,0x3f}; /* Normal OP */
+const u_char ARCOFI_SOP_F[] = {10,0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12};
-static inline void
-writehscx(unsigned int adr, int hscx, u_char off, u_char data)
-{
- long flags;
-
- save_flags(flags);
- cli();
- byteout(adr + CARD_ALE, off + (hscx ? 0x60 : 0x20));
- byteout(adr + CARD_HSCX, data);
- restore_flags(flags);
-}
+static void set_arcofi(struct IsdnCardState *cs, int bc);
-static inline void
-write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
-{
- /* fifo write without cli because it's allready done */
- byteout(adr + CARD_ALE, (hscx ? 0x40 : 0));
- outsb(adr + CARD_HSCX, data, size);
-}
+#if ARCOFI_USE
+#include "elsa_ser.c"
+#endif
static inline u_char
-readisac(unsigned int adr, u_char off)
+readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
long flags;
save_flags(flags);
cli();
- byteout(adr + CARD_ALE, off + 0x20);
- ret = bytein(adr + CARD_ISAC);
+ byteout(ale, off);
+ ret = bytein(adr);
restore_flags(flags);
return (ret);
}
static inline void
-read_fifo_isac(unsigned int adr, u_char * data, int size)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
/* fifo read without cli because it's allready done */
- byteout(adr + CARD_ALE, 0);
- insb(adr + CARD_ISAC, data, size);
+ byteout(ale, off);
+ insb(adr, data, size);
}
static inline void
-writeisac(unsigned int adr, u_char off, u_char data)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
long flags;
save_flags(flags);
cli();
- byteout(adr + CARD_ALE, off + 0x20);
- byteout(adr + CARD_ISAC, data);
+ byteout(ale, off);
+ byteout(adr, data);
restore_flags(flags);
}
static inline void
-write_fifo_isac(unsigned int adr, u_char * data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
/* fifo write without cli because it's allready done */
-
- byteout(adr + CARD_ALE, 0);
- outsb(adr + CARD_ISAC, data, size);
+ byteout(ale, off);
+ outsb(adr, data, size);
}
-#ifdef CONFIG_HISAX_ELSA_PCC
-static inline u_char
-readitac(unsigned int adr, u_char off)
-{
- register u_char ret;
- long flags;
+/* Interface functions */
- save_flags(flags);
- cli();
- byteout(adr + CARD_ALE, off);
- ret = bytein(adr + CARD_ITAC);
- restore_flags(flags);
- return (ret);
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset));
}
-static inline void
-writeitac(unsigned int adr, u_char off, u_char data)
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
- long flags;
-
- save_flags(flags);
- cli();
- byteout(adr + CARD_ALE, off);
- byteout(adr + CARD_ITAC, data);
- restore_flags(flags);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset, value);
}
-static inline int
-TimerRun(struct IsdnCardState *sp)
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- register u_char val;
-
- val = bytein(sp->cfg_reg + CARD_CONFIG);
- if (sp->subtyp == ELSA_QS1000)
- return (0 == (val & TIMER_RUN));
- else if (sp->subtyp == ELSA_PCC8)
- return (val & TIMER_RUN_PCC8);
- return (val & TIMER_RUN);
+ readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
}
-static inline void
-elsa_led_handler(struct IsdnCardState *sp)
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
-
- u_char outval = 0xf0;
- int stat = 0, cval;
-
-
- if ((sp->ph_state == 0) || (sp->ph_state == 15)) {
- stat = 1;
- } else {
- if (sp->hs[0].mode != 0)
- stat |= 2;
- if (sp->hs[1].mode != 0)
- stat |= 4;
- }
- cval = (sp->counter >> 6) & 3;
- switch (cval) {
- case 0:
- if (!stat)
- outval |= STAT_LED;
- else if (stat == 1)
- outval |= LINE_LED | STAT_LED;
- else {
- if (stat & 2)
- outval |= STAT_LED;
- if (stat & 4)
- outval |= LINE_LED;
- }
- break;
- case 1:
- if (!stat)
- outval |= LINE_LED;
- else if (stat == 1)
- outval |= LINE_LED | STAT_LED;
- else {
- if (stat & 2)
- outval |= STAT_LED;
- if (stat & 4)
- outval |= LINE_LED;
- }
- break;
- case 2:
- if (!stat)
- outval |= STAT_LED;
- else if (stat == 1)
- outval |= 0;
- else {
- if (stat & 2)
- outval |= STAT_LED;
- if (stat & 4)
- outval |= LINE_LED;
- }
- break;
- case 3:
- if (!stat)
- outval |= LINE_LED;
- break;
- }
- byteout(sp->cfg_reg + CARD_CONTROL, outval);
+ writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
}
-#endif
-static inline void
-waitforCEC(int adr, int hscx)
+static u_char
+ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
{
- int to = 50;
-
- while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "Elsa: waitforCEC timeout\n");
+ return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset+0x80));
}
-
-static inline void
-waitforXFW(int adr, int hscx)
+static void
+WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
- int to = 50;
-
- while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "Elsa: waitforXFW timeout\n");
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset|0x80, value);
}
-static inline void
-writehscxCMDR(int adr, int hscx, u_char data)
+static void
+ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
{
- long flags;
-
- save_flags(flags);
- cli();
- waitforCEC(adr, hscx);
- writehscx(adr, hscx, HSCX_CMDR, data);
- restore_flags(flags);
+ readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
}
-/*
- * fast interrupt here
- */
-
-
static void
-hscxreport(struct IsdnCardState *sp, int hscx)
+WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
{
- printk(KERN_DEBUG "HSCX %d\n", hscx);
- printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->cfg_reg, hscx, HSCX_ISTA));
- printk(KERN_DEBUG "STAR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_STAR));
- printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_EXIR));
+ writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
}
-void
-elsa_report(struct IsdnCardState *sp)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
- printk(KERN_DEBUG "ISAC\n");
- printk(KERN_DEBUG "ISTA %x\n", readisac(sp->cfg_reg, ISAC_ISTA));
- printk(KERN_DEBUG "STAR %x\n", readisac(sp->cfg_reg, ISAC_STAR));
- printk(KERN_DEBUG "EXIR %x\n", readisac(sp->cfg_reg, ISAC_EXIR));
- hscxreport(sp, 0);
- hscxreport(sp, 1);
+ return (readreg(cs->hw.elsa.ale,
+ cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0)));
}
-/*
- * HSCX stuff goes here
- */
-
static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
- u_char *ptr;
- struct IsdnCardState *sp = hsp->sp;
- long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_empty_fifo");
-
- if (hsp->rcvidx + count > HSCX_BUFMAX) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "hscx_empty_fifo: incoming packet too large");
- writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
- hsp->rcvidx = 0;
- return;
- }
- ptr = hsp->rcvbuf + hsp->rcvidx;
- hsp->rcvidx += count;
- save_flags(flags);
- cli();
- read_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count);
- writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
- restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_empty_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ writereg(cs->hw.elsa.ale,
+ cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value);
}
-static void
-hscx_fill_fifo(struct HscxState *hsp)
+static inline u_char
+readitac(struct IsdnCardState *cs, u_char off)
{
- struct IsdnCardState *sp = hsp->sp;
- int more, count;
- u_char *ptr;
+ register u_char ret;
long flags;
-
- if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
- debugl1(sp, "hscx_fill_fifo");
-
- if (!hsp->tx_skb)
- return;
- if (hsp->tx_skb->len <= 0)
- return;
-
- more = (hsp->mode == 1) ? 1 : 0;
- if (hsp->tx_skb->len > 32) {
- more = !0;
- count = 32;
- } else
- count = hsp->tx_skb->len;
-
- waitforXFW(sp->cfg_reg, hsp->hscx);
save_flags(flags);
cli();
- ptr = hsp->tx_skb->data;
- skb_pull(hsp->tx_skb, count);
- hsp->tx_cnt -= count;
- hsp->count += count;
- write_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count);
- writehscxCMDR(sp->cfg_reg, hsp->hscx, more ? 0x8 : 0xa);
+ byteout(cs->hw.elsa.ale, off);
+ ret = bytein(cs->hw.elsa.itac);
restore_flags(flags);
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "hscx_fill_fifo %c cnt %d",
- hsp->hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ return (ret);
}
static inline void
-hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
-{
- u_char r;
- struct HscxState *hsp = sp->hs + hscx;
- struct sk_buff *skb;
- int count;
- char tmp[32];
-
- if (!hsp->init)
- return;
-
- if (val & 0x80) { /* RME */
-
- r = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!(r & 0x80))
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX invalid frame");
- if ((r & 0x40) && hsp->mode)
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX RDO mode=%d",
- hsp->mode);
- debugl1(sp, tmp);
- }
- if (!(r & 0x20))
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "HSCX CRC error");
- writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
- } else {
- count = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- hscx_empty_fifo(hsp, count);
- if ((count = hsp->rcvidx - 1) > 0) {
- if (sp->debug & L1_DEB_HSCX_FIFO) {
- sprintf(tmp, "HX Frame %d", count);
- debugl1(sp, tmp);
- }
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "Elsa: receive out of memory\n");
- else {
- memcpy(skb_put(skb, count), hsp->rcvbuf, count);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- }
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- hscx_empty_fifo(hsp, 32);
- if (hsp->mode == 1) {
- /* receive audio data */
- if (!(skb = dev_alloc_skb(32)))
- printk(KERN_WARNING "elsa: receive out of memory\n");
- else {
- memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
- skb_queue_tail(&hsp->rqueue, skb);
- }
- hsp->rcvidx = 0;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- }
- if (val & 0x10) { /* XPR */
- if (hsp->tx_skb)
- if (hsp->tx_skb->len) {
- hscx_fill_fifo(hsp);
- return;
- } else {
- dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
- hsp->count = 0;
- if (hsp->st->l4.l1writewakeup)
- hsp->st->l4.l1writewakeup(hsp->st);
- hsp->tx_skb = NULL;
- }
- if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
- hsp->count = 0;
- hscx_fill_fifo(hsp);
- } else
- hscx_sched_event(hsp, HSCX_XMTBUFREADY);
- }
-}
-
-/*
- * ISAC stuff goes here
- */
-
-static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
+writeitac(struct IsdnCardState *cs, u_char off, u_char data)
{
- u_char *ptr;
long flags;
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- debugl1(sp, "isac_empty_fifo");
-
- if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
- if (sp->debug & L1_DEB_WARN) {
- char tmp[40];
- sprintf(tmp, "isac_empty_fifo overrun %d",
- sp->rcvidx + count);
- debugl1(sp, tmp);
- }
- writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
- sp->rcvidx = 0;
- return;
- }
- ptr = sp->rcvbuf + sp->rcvidx;
- sp->rcvidx += count;
save_flags(flags);
cli();
- read_fifo_isac(sp->cfg_reg, ptr, count);
- writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+ byteout(cs->hw.elsa.ale, off);
+ byteout(cs->hw.elsa.itac, data);
restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_empty_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
}
-static void
-isac_fill_fifo(struct IsdnCardState *sp)
+static inline int
+TimerRun(struct IsdnCardState *cs)
{
- int count, more;
- u_char *ptr;
- long flags;
-
- if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
- debugl1(sp, "isac_fill_fifo");
-
- if (!sp->tx_skb)
- return;
-
- count = sp->tx_skb->len;
- if (count <= 0)
- return;
+ register u_char v;
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- save_flags(flags);
- cli();
- ptr = sp->tx_skb->data;
- skb_pull(sp->tx_skb, count);
- sp->tx_cnt += count;
- write_fifo_isac(sp->cfg_reg, ptr, count);
- writeisac(sp->cfg_reg, ISAC_CMDR, more ? 0x8 : 0xa);
- restore_flags(flags);
- if (sp->debug & L1_DEB_ISAC_FIFO) {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "isac_fill_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(sp, tmp);
- }
+ v = bytein(cs->hw.elsa.cfg);
+ if ((cs->subtyp == ELSA_QS1000) || (cs->subtyp == ELSA_QS3000))
+ return (0 == (v & ELSA_TIMER_RUN));
+ else if (cs->subtyp == ELSA_PCC8)
+ return (v & ELSA_TIMER_RUN_PCC8);
+ return (v & ELSA_TIMER_RUN);
}
+/*
+ * fast interrupt HSCX stuff goes here
+ */
-static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
-{
- if (sp->debug & L1_DEB_ISAC) {
- char tmp[32];
- sprintf(tmp, "ph_command %d", command);
- debugl1(sp, tmp);
- }
- writeisac(sp->cfg_reg, ISAC_CIX0, (command << 2) | 3);
-}
+#define READHSCX(cs, nr, reg) readreg(cs->hw.elsa.ale, \
+ cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.elsa.ale, \
+ cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0), data)
-static inline void
-isac_interrupt(struct IsdnCardState *sp, u_char val)
-{
- u_char exval, v1;
- struct sk_buff *skb;
- unsigned int count;
- char tmp[32];
-#if ARCOFI_USE
- struct BufHeader *ibh;
- u_char *ptr;
-#endif
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.elsa.ale, \
+ cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "ISAC interrupt %x", val);
- debugl1(sp, tmp);
- }
- if (val & 0x80) { /* RME */
- exval = readisac(sp->cfg_reg, ISAC_RSTA);
- if ((exval & 0x70) != 0x20) {
- if (exval & 0x40)
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RDO");
- if (!(exval & 0x20))
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC CRC error");
- writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
- } else {
- count = readisac(sp->cfg_reg, ISAC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- isac_empty_fifo(sp, count);
- if ((count = sp->rcvidx) > 0) {
- sp->rcvidx = 0;
- if (!(skb = alloc_skb(count, GFP_ATOMIC)))
- printk(KERN_WARNING "Elsa: D receive out of memory\n");
- else {
- SET_SKB_FREE(skb);
- memcpy(skb_put(skb, count), sp->rcvbuf, count);
- skb_queue_tail(&sp->rq, skb);
- }
- }
- }
- sp->rcvidx = 0;
- isac_sched_event(sp, ISAC_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- isac_empty_fifo(sp, 32);
- }
- if (val & 0x20) { /* RSC */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC RSC interrupt");
- }
- if (val & 0x10) { /* XPR */
- if (sp->tx_skb)
- if (sp->tx_skb->len) {
- isac_fill_fifo(sp);
- goto afterXPR;
- } else {
- dev_kfree_skb(sp->tx_skb, FREE_WRITE);
- sp->tx_cnt = 0;
- sp->tx_skb = NULL;
- }
- if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
- sp->tx_cnt = 0;
- isac_fill_fifo(sp);
- } else
- isac_sched_event(sp, ISAC_XMTBUFREADY);
- }
- afterXPR:
- if (val & 0x04) { /* CISQ */
- sp->ph_state = (readisac(sp->cfg_reg, ISAC_CIX0) >> 2)
- & 0xf;
- if (sp->debug & L1_DEB_ISAC) {
- sprintf(tmp, "l1state %d", sp->ph_state);
- debugl1(sp, tmp);
- }
- isac_new_ph(sp);
- }
- if (val & 0x02) { /* SIN */
- /* never */
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC SIN interrupt");
- }
- if (val & 0x01) { /* EXI */
- exval = readisac(sp->cfg_reg, ISAC_EXIR);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC EXIR %02x", exval);
- debugl1(sp, tmp);
- }
- if (exval & 0x08) {
- v1 = readisac(sp->cfg_reg, ISAC_MOSR);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC MOSR %02x", v1);
- debugl1(sp, tmp);
- }
-#if ARCOFI_USE
- if (v1 & 0x08) {
- if (!sp->mon_rx)
- if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
- GFP_ATOMIC, (void *) 1, 3)) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC MON RX out of buffers!");
- writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
- goto afterMONR0;
- } else
- sp->mon_rxp = 0;
- ibh = sp->mon_rx;
- ptr = DATAPTR(ibh);
- ptr += sp->mon_rxp;
- sp->mon_rxp++;
- if (sp->mon_rxp >= 3072) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
- sp->mon_rxp = 0;
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC MON RX overflow!");
- goto afterMONR0;
- }
- *ptr = readisac(sp->cfg_reg, ISAC_MOR0);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC MOR0 %02x", *ptr);
- debugl1(sp, tmp);
- }
- }
- afterMONR0:
- if (v1 & 0x80) {
- if (!sp->mon_rx)
- if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
- GFP_ATOMIC, (void *) 1, 3)) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC MON RX out of buffers!");
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
- goto afterMONR1;
- } else
- sp->mon_rxp = 0;
- ibh = sp->mon_rx;
- ptr = DATAPTR(ibh);
- ptr += sp->mon_rxp;
- sp->mon_rxp++;
- if (sp->mon_rxp >= 3072) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
- sp->mon_rxp = 0;
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC MON RX overflow!");
- goto afterMONR1;
- }
- *ptr = readisac(sp->cfg_reg, ISAC_MOR1);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "ISAC MOR1 %02x", *ptr);
- debugl1(sp, tmp);
- }
- }
- afterMONR1:
- if (v1 & 0x04) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
- sp->mon_rx->datasize = sp->mon_rxp;
- sp->mon_flg |= MON0_RX;
- }
- if (v1 & 0x40) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
- sp->mon_rx->datasize = sp->mon_rxp;
- sp->mon_flg |= MON1_RX;
- }
- if (v1 == 0x02) {
- ibh = sp->mon_tx;
- if (!ibh) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
- goto AfterMOX0;
- }
- count = ibh->datasize - sp->mon_txp;
- if (count <= 0) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0x0f);
- BufPoolRelease(sp->mon_tx);
- sp->mon_tx = NULL;
- sp->mon_txp = 0;
- sp->mon_flg |= MON0_TX;
- goto AfterMOX0;
- }
- ptr = DATAPTR(ibh);
- ptr += sp->mon_txp;
- sp->mon_txp++;
- writeisac(sp->cfg_reg, ISAC_MOX0, *ptr);
- }
- AfterMOX0:
- if (v1 == 0x20) {
- ibh = sp->mon_tx;
- if (!ibh) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
- goto AfterMOX1;
- }
- count = ibh->datasize - sp->mon_txp;
- if (count <= 0) {
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xf0);
- BufPoolRelease(sp->mon_tx);
- sp->mon_tx = NULL;
- sp->mon_txp = 0;
- sp->mon_flg |= MON1_TX;
- goto AfterMOX1;
- }
- ptr = DATAPTR(ibh);
- ptr += sp->mon_txp;
- sp->mon_txp++;
- writeisac(sp->cfg_reg, ISAC_MOX1, *ptr);
- }
- AfterMOX1:
-#endif
- }
- }
-}
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.elsa.ale, \
+ cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
-
- u_char exval;
- struct HscxState *hsp;
- char tmp[32];
-
- if (val & 0x01) {
- hsp = sp->hs + 1;
- exval = readhscx(sp->cfg_reg, 1, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0xf8) {
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX B interrupt %x", val);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, val, 1);
- }
- if (val & 0x02) {
- hsp = sp->hs;
- exval = readhscx(sp->cfg_reg, 0, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (hsp->tx_skb) {
- skb_push(hsp->tx_skb, hsp->count);
- hsp->tx_cnt += hsp->count;
- hsp->count = 0;
- }
- writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01);
- if (sp->debug & L1_DEB_WARN) {
- sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
- debugl1(sp, tmp);
- }
- }
- } else if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A EXIR %x", exval);
- debugl1(sp, tmp);
- }
- }
- if (val & 0x04) {
- exval = readhscx(sp->cfg_reg, 0, HSCX_ISTA);
- if (sp->debug & L1_DEB_HSCX) {
- sprintf(tmp, "HSCX A interrupt %x", exval);
- debugl1(sp, tmp);
- }
- hscx_interrupt(sp, exval, 0);
- }
-}
+#include "hscx_irq.c"
static void
elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
- struct IsdnCardState *sp;
+ struct IsdnCardState *cs = dev_id;
u_char val;
+ int icnt=20;
- sp = (struct IsdnCardState *) irq2dev_map[intno];
-
- if (!sp) {
+ if (!cs) {
printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
return;
}
-#ifdef CONFIG_HISAX_ELSA_PCC
- INT_RESTART:
- if (!TimerRun(sp)) {
- /* Timer Restart */
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- if (!(sp->counter++ & 0x3f)) {
- /* Call LEDs all 64 tics */
- elsa_led_handler(sp);
+ if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) {
+ /* The card tends to generate interrupts while being removed
+ causing us to just crash the kernel. bad. */
+ printk(KERN_WARNING "Elsa: card not available!\n");
+ return;
+ }
+#if ARCOFI_USE
+ if (cs->hw.elsa.MFlag) {
+ val = serial_inp(cs, UART_IIR);
+ if (!(val & UART_IIR_NO_INT)) {
+ debugl1(cs,"IIR %02x", val);
+ rs_interrupt_elsa(intno, cs);
}
}
#endif
- val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
if (val) {
- hscx_int_main(sp, val);
+ hscx_int_main(cs, val);
}
- val = readisac(sp->cfg_reg, ISAC_ISTA);
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
Start_ISAC:
if (val) {
- isac_interrupt(sp, val);
+ isac_interrupt(cs, val);
}
-#ifdef CONFIG_HISAX_ELSA_PCC
- if (!TimerRun(sp))
- goto INT_RESTART;
-#endif
- val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
- if (val) {
- if (sp->debug & L1_DEB_HSCX)
- debugl1(sp, "HSCX IntStat after IntRoutine");
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
+ if (val && icnt) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX IntStat after IntRoutine");
+ icnt--;
goto Start_HSCX;
}
- val = readisac(sp->cfg_reg, ISAC_ISTA);
- if (val) {
- if (sp->debug & L1_DEB_ISAC)
- debugl1(sp, "ISAC IntStat after IntRoutine");
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
+ if (val && icnt) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
+ icnt--;
goto Start_ISAC;
}
- writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF);
- writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF);
- writeisac(sp->cfg_reg, ISAC_MASK, 0xFF);
-#ifdef CONFIG_HISAX_ELSA_PCC
- if (sp->subtyp == ELSA_QS1000) {
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+ if (!icnt)
+ printk(KERN_WARNING"ELSA IRQ LOOP\n");
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF);
+ if (cs->hw.elsa.status & ELSA_TIMER_AKTIV) {
+ if (!TimerRun(cs)) {
+ /* Timer Restart */
+ byteout(cs->hw.elsa.timer, 0);
+ cs->hw.elsa.counter++;
+ }
}
-#endif
- writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0);
- writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0);
- writeisac(sp->cfg_reg, ISAC_MASK, 0x0);
+ if (cs->hw.elsa.MFlag) {
+ val = serial_inp(cs, UART_MCR);
+ val ^= 0x8;
+ serial_outp(cs, UART_MCR, val);
+ val = serial_inp(cs, UART_MCR);
+ val ^= 0x8;
+ serial_outp(cs, UART_MCR, val);
+ }
+ if (cs->hw.elsa.trig)
+ byteout(cs->hw.elsa.trig, 0x00);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0x0);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0x0);
}
-
static void
-initisac(struct IsdnCardState *sp)
+elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
{
- unsigned int adr = sp->cfg_reg;
+ struct IsdnCardState *cs = dev_id;
+ u_char ista,val;
+ int icnt=20;
- /* Elsa IOM 2 Mode */
- writeisac(adr, ISAC_MASK, 0xff);
- writeisac(adr, ISAC_ADF2, 0x80);
- writeisac(adr, ISAC_SQXR, 0x2f);
- writeisac(adr, ISAC_SPCR, 0x00);
- writeisac(adr, ISAC_STCR, 0x70);
- writeisac(adr, ISAC_MODE, 0xc9);
- writeisac(adr, ISAC_TIMR, 0x00);
- writeisac(adr, ISAC_ADF1, 0x00);
- writeisac(adr, ISAC_CIX0, (1 << 2) | 3);
- writeisac(adr, ISAC_MASK, 0xff);
- writeisac(adr, ISAC_MASK, 0x0);
-}
-
-static void
-modehscx(struct HscxState *hs, int mode, int ichan)
-{
- struct IsdnCardState *sp = hs->sp;
- int hscx = hs->hscx;
-
- if (sp->debug & L1_DEB_HSCX) {
- char tmp[40];
- sprintf(tmp, "hscx %c mode %d ichan %d",
- 'A' + hscx, mode, ichan);
- debugl1(sp, tmp);
- }
- hs->mode = mode;
- writehscx(sp->cfg_reg, hscx, HSCX_CCR1, 0x85);
- writehscx(sp->cfg_reg, hscx, HSCX_XAD1, 0xFF);
- writehscx(sp->cfg_reg, hscx, HSCX_XAD2, 0xFF);
- writehscx(sp->cfg_reg, hscx, HSCX_RAH2, 0xFF);
- writehscx(sp->cfg_reg, hscx, HSCX_XBCH, 0x0);
- writehscx(sp->cfg_reg, hscx, HSCX_RLCR, 0x0);
- writehscx(sp->cfg_reg, hscx, HSCX_CCR2, 0x30);
-
- switch (mode) {
- case (0):
- writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0xff);
- writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0xff);
- writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x84);
- break;
- case (1):
- if (ichan == 0) {
- writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f);
- writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f);
- } else {
- writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3);
- writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3);
- }
- writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0xe4);
- writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41);
- break;
- case (2):
- if (ichan == 0) {
- writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f);
- writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f);
- } else {
- writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3);
- writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3);
- }
- writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
- writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x8c);
- writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41);
- break;
+ if (!cs) {
+ printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
+ return;
}
- writehscx(sp->cfg_reg, hscx, HSCX_ISTA, 0x00);
+ val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */
+ if (!(val & ELSA_PCI_IRQ_MASK))
+ return;
+#if ARCOFI_USE
+ if (cs->hw.elsa.MFlag) {
+ val = serial_inp(cs, UART_IIR);
+ if (!(val & UART_IIR_NO_INT)) {
+ debugl1(cs,"IIR %02x", val);
+ rs_interrupt_elsa(intno, cs);
+ }
+ }
+#endif
+ ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
+Start_IPAC:
+ if (cs->debug & L1_DEB_IPAC)
+ debugl1(cs, "IPAC ISTA %02X", ista);
+ if (ista & 0x0f) {
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.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.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80);
+ if (val) {
+ isac_interrupt(cs, val);
+ }
+ }
+ if (ista & 0x10) {
+ val = 0x01;
+ isac_interrupt(cs, val);
+ }
+ ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
+ if ((ista & 0x3f) && icnt) {
+ icnt--;
+ goto Start_IPAC;
+ }
+ if (!icnt)
+ printk(KERN_WARNING "ELSA IRQ LOOP\n");
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0);
}
void
-release_io_elsa(struct IsdnCard *card)
+release_io_elsa(struct IsdnCardState *cs)
{
int bytecnt = 8;
- if (card->sp->subtyp == ELSA_PCFPRO)
+ del_timer(&cs->hw.elsa.tl);
+ if (cs->hw.elsa.ctrl)
+ byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */
+ if (cs->subtyp == ELSA_QS1000PCI) {
+ byteout(cs->hw.elsa.cfg + 0x4c, 0x01); /* disable IRQ */
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+ bytecnt = 2;
+ release_region(cs->hw.elsa.cfg, 0x80);
+ }
+ if (cs->subtyp == ELSA_QS3000PCI) {
+ byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* disable ELSA PCI IRQ */
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+ release_region(cs->hw.elsa.cfg, 0x80);
+ }
+ if ((cs->subtyp == ELSA_PCFPRO) ||
+ (cs->subtyp == ELSA_QS3000) ||
+ (cs->subtyp == ELSA_PCF) ||
+ (cs->subtyp == ELSA_QS3000PCI)) {
bytecnt = 16;
- if (card->sp->cfg_reg)
- release_region(card->sp->cfg_reg, bytecnt);
-}
-
-static void
-reset_elsa(struct IsdnCardState *sp)
-{
-#ifdef CONFIG_HISAX_ELSA_PCC
- /* Wait 1 Timer */
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- while (TimerRun(sp));
- byteout(sp->cfg_reg + CARD_CONTROL, 0x00); /* Reset On */
- /* Wait 1 Timer */
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- while (TimerRun(sp));
- byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET); /* Reset Off */
- /* Wait 1 Timer */
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- while (TimerRun(sp));
- byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
-#endif
+ release_modem(cs);
+ }
+ if (cs->hw.elsa.base)
+ release_region(cs->hw.elsa.base, bytecnt);
}
static void
-clear_pending_ints(struct IsdnCardState *sp)
+reset_elsa(struct IsdnCardState *cs)
{
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
- int val;
- char tmp[64];
+ long flags;
- val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
- sprintf(tmp, "HSCX B ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = readhscx(sp->cfg_reg, 1, HSCX_EXIR);
- sprintf(tmp, "HSCX B EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x02) {
- val = readhscx(sp->cfg_reg, 0, HSCX_EXIR);
- sprintf(tmp, "HSCX A EXIR %x", val);
- debugl1(sp, tmp);
- }
- val = readhscx(sp->cfg_reg, 0, HSCX_ISTA);
- sprintf(tmp, "HSCX A ISTA %x", val);
- debugl1(sp, tmp);
- val = readhscx(sp->cfg_reg, 1, HSCX_STAR);
- sprintf(tmp, "HSCX B STAR %x", val);
- debugl1(sp, tmp);
- val = readhscx(sp->cfg_reg, 0, HSCX_STAR);
- sprintf(tmp, "HSCX A STAR %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->cfg_reg, ISAC_STAR);
- sprintf(tmp, "ISAC STAR %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->cfg_reg, ISAC_MODE);
- sprintf(tmp, "ISAC MODE %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->cfg_reg, ISAC_ADF2);
- sprintf(tmp, "ISAC ADF2 %x", val);
- debugl1(sp, tmp);
- val = readisac(sp->cfg_reg, ISAC_ISTA);
- sprintf(tmp, "ISAC ISTA %x", val);
- debugl1(sp, tmp);
- if (val & 0x01) {
- val = readisac(sp->cfg_reg, ISAC_EXIR);
- sprintf(tmp, "ISAC EXIR %x", val);
- debugl1(sp, tmp);
- } else if (val & 0x04) {
- val = readisac(sp->cfg_reg, ISAC_CIR0);
- sprintf(tmp, "ISAC CIR0 %x", val);
- debugl1(sp, tmp);
+ if (cs->hw.elsa.timer) {
+ /* Wait 1 Timer */
+ byteout(cs->hw.elsa.timer, 0);
+ while (TimerRun(cs));
+ cs->hw.elsa.ctrl_reg |= 0x50;
+ cs->hw.elsa.ctrl_reg &= ~ELSA_ISDN_RESET; /* Reset On */
+ byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+ /* Wait 1 Timer */
+ byteout(cs->hw.elsa.timer, 0);
+ while (TimerRun(cs));
+ cs->hw.elsa.ctrl_reg |= ELSA_ISDN_RESET; /* Reset Off */
+ byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+ /* Wait 1 Timer */
+ byteout(cs->hw.elsa.timer, 0);
+ while (TimerRun(cs));
+ if (cs->hw.elsa.trig)
+ byteout(cs->hw.elsa.trig, 0xff);
}
-#endif
- writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF);
- writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF);
- writeisac(sp->cfg_reg, ISAC_MASK, 0xFF);
-#ifdef CONFIG_HISAX_ELSA_PCC
- if (sp->subtyp == ELSA_QS1000) {
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+ if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
+ save_flags(flags);
+ sti();
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */
+ schedule();
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */
+ schedule();
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
+ schedule();
+ restore_flags(flags);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+ if (cs->subtyp == ELSA_QS1000PCI)
+ byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */
+ else if (cs->subtyp == ELSA_QS3000PCI)
+ byteout(cs->hw.elsa.cfg + 0x4c, 0x43); /* enable ELSA PCI IRQ */
}
-#endif
- writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0);
- writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0);
- writeisac(sp->cfg_reg, ISAC_MASK, 0x0);
- writeisac(sp->cfg_reg, ISAC_CMDR, 0x41);
}
static void
-check_arcofi(struct IsdnCardState *sp)
-{
-#if 0
- u_char val;
- char tmp[40];
- char *t;
+init_arcofi(struct IsdnCardState *cs) {
+ send_arcofi(cs, ARCOFI_XOP_0, 1, 0);
+/* send_arcofi(cs, ARCOFI_XOP_F, 1);
+*/
+}
+
+#define ARCDEL 500
+
+static void
+set_arcofi(struct IsdnCardState *cs, int bc) {
long flags;
- u_char *p;
- if (BufPoolGet(&(sp->mon_tx), &(sp->sbufpool),
- GFP_ATOMIC, (void *) 1, 3)) {
- if (sp->debug & L1_DEB_WARN)
- debugl1(sp, "ISAC MON TX out of buffers!");
- return;
- } else
- sp->mon_txp = 0;
- p = DATAPTR(sp->mon_tx);
- *p++ = 0xa0;
- *p++ = 0x0;
- sp->mon_tx->datasize = 2;
- sp->mon_txp = 1;
- sp->mon_flg = 0;
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
- val = readisac(sp->cfg_reg, ISAC_MOSR);
- writeisac(sp->cfg_reg, ISAC_MOX1, 0xa0);
- writeisac(sp->cfg_reg, ISAC_MOCR, 0xb0);
+ debugl1(cs,"set_arcofi bc=%d", bc);
save_flags(flags);
sti();
- HZDELAY(3);
+ send_arcofi(cs, ARCOFI_XOP_0, bc, 0);
+ udelay(ARCDEL);
+ send_arcofi(cs, ARCOFI_COP_5, bc, 0);
+ udelay(ARCDEL);
+ send_arcofi(cs, ARCOFI_COP_6, bc, 0);
+ udelay(ARCDEL);
+ send_arcofi(cs, ARCOFI_COP_7, bc, 0);
+ udelay(ARCDEL);
+ send_arcofi(cs, ARCOFI_COP_8, bc, 0);
+ udelay(ARCDEL);
+ send_arcofi(cs, ARCOFI_COP_9, bc, 0);
+ udelay(ARCDEL);
+ send_arcofi(cs, ARCOFI_SOP_F, bc, 0);
+ udelay(ARCDEL);
+ send_arcofi(cs, ARCOFI_XOP_1, bc, 0);
+ udelay(ARCDEL);
+ send_arcofi(cs, ARCOFI_XOP_F, bc, 0);
restore_flags(flags);
- if (sp->mon_flg & MON1_TX) {
- if (sp->mon_flg & MON1_RX) {
- sprintf(tmp, "Arcofi response received %d bytes", sp->mon_rx->datasize);
- debugl1(sp, tmp);
- p = DATAPTR(sp->mon_rx);
+ debugl1(cs,"end set_arcofi bc=%d", bc);
+}
+
+static int
+check_arcofi(struct IsdnCardState *cs)
+{
+#if ARCOFI_USE
+ int arcofi_present = 0;
+ char tmp[40];
+ char *t;
+ u_char *p;
+
+ if (!cs->mon_tx)
+ if (!(cs->mon_tx=kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "ISAC MON TX out of buffers!");
+ return(0);
+ }
+ send_arcofi(cs, ARCOFI_VERSION, 0, 1);
+ if (test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags)) {
+ if (test_and_clear_bit(HW_MON1_RX_END, &cs->HW_Flags)) {
+ debugl1(cs, "Arcofi response received %d bytes", cs->mon_rxp);
+ p = cs->mon_rx;
t = tmp;
t += sprintf(tmp, "Arcofi data");
- QuickHex(t, p, sp->mon_rx->datasize);
- debugl1(sp, tmp);
- BufPoolRelease(sp->mon_rx);
- sp->mon_rx = NULL;
- sp->mon_rxp = 0;
- sp->mon_flg = 0;
+ QuickHex(t, p, cs->mon_rxp);
+ debugl1(cs, tmp);
+ if ((cs->mon_rxp == 2) && (cs->mon_rx[0] == 0xa0)) {
+ switch(cs->mon_rx[1]) {
+ case 0x80:
+ debugl1(cs, "Arcofi 2160 detected");
+ arcofi_present = 1;
+ break;
+ case 0x82:
+ debugl1(cs, "Arcofi 2165 detected");
+ arcofi_present = 2;
+ break;
+ case 0x84:
+ debugl1(cs, "Arcofi 2163 detected");
+ arcofi_present = 3;
+ break;
+ default:
+ debugl1(cs, "unknown Arcofi response");
+ break;
+ }
+ } else
+ debugl1(cs, "undefined Monitor response");
+ cs->mon_rxp = 0;
}
- } else if (sp->mon_tx) {
- BufPoolRelease(sp->mon_tx);
- sp->mon_tx = NULL;
- sp->mon_txp = 0;
- sprintf(tmp, "Arcofi not detected");
- debugl1(sp, tmp);
+ } else if (cs->mon_tx) {
+ debugl1(cs, "Arcofi not detected");
+ }
+ if (arcofi_present) {
+ if (cs->subtyp==ELSA_QS1000) {
+ cs->subtyp = ELSA_QS3000;
+ printk(KERN_INFO
+ "Elsa: %s detected modem at 0x%x\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base+8);
+ release_region(cs->hw.elsa.base, 8);
+ if (check_region(cs->hw.elsa.base, 16)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base + 8,
+ cs->hw.elsa.base + 16);
+ } else
+ request_region(cs->hw.elsa.base, 16,
+ "elsa isdn modem");
+ } else if (cs->subtyp==ELSA_PCC16) {
+ cs->subtyp = ELSA_PCF;
+ printk(KERN_INFO
+ "Elsa: %s detected modem at 0x%x\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base+8);
+ release_region(cs->hw.elsa.base, 8);
+ if (check_region(cs->hw.elsa.base, 16)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base + 8,
+ cs->hw.elsa.base + 16);
+ } else
+ request_region(cs->hw.elsa.base, 16,
+ "elsa isdn modem");
+ } else
+ printk(KERN_INFO
+ "Elsa: %s detected modem at 0x%x\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base+8);
+ init_arcofi(cs);
+ return(1);
}
- sp->mon_flg = 0;
#endif
+ return(0);
}
-int
-initelsa(struct IsdnCardState *sp)
+static void
+elsa_led_handler(struct IsdnCardState *cs)
+{
+ int blink = 0;
+
+ if (cs->subtyp == ELSA_PCMCIA)
+ return;
+ del_timer(&cs->hw.elsa.tl);
+ if (cs->hw.elsa.status & ELSA_ASSIGN)
+ cs->hw.elsa.ctrl_reg |= ELSA_STAT_LED;
+ else if (cs->hw.elsa.status & ELSA_BAD_PWR)
+ cs->hw.elsa.ctrl_reg &= ~ELSA_STAT_LED;
+ else {
+ cs->hw.elsa.ctrl_reg ^= ELSA_STAT_LED;
+ blink = 250;
+ }
+ if (cs->hw.elsa.status & 0xf000)
+ cs->hw.elsa.ctrl_reg |= ELSA_LINE_LED;
+ else if (cs->hw.elsa.status & 0x0f00) {
+ cs->hw.elsa.ctrl_reg ^= ELSA_LINE_LED;
+ blink = 500;
+ } else
+ cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED;
+
+ if ((cs->subtyp == ELSA_QS1000PCI) ||
+ (cs->subtyp == ELSA_QS3000PCI)) {
+ u_char led = 0xff;
+ if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED)
+ led ^= ELSA_IPAC_LINE_LED;
+ if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED)
+ led ^= ELSA_IPAC_STAT_LED;
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led);
+ } else
+ byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+ if (blink) {
+ init_timer(&cs->hw.elsa.tl);
+ cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000);
+ add_timer(&cs->hw.elsa.tl);
+ }
+}
+
+static int
+Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
- int ret, irq_cnt, cnt = 3;
+ int len, ret = 0;
+ u_char *msg;
long flags;
- irq_cnt = kstat.interrupts[sp->irq];
- printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq, irq_cnt);
- ret = get_irq(sp->cardnr, &elsa_interrupt);
-#ifdef CONFIG_HISAX_ELSA_PCC
- byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
-#endif
- while (ret && cnt) {
- sp->counter = 0;
- clear_pending_ints(sp);
- initisac(sp);
- sp->modehscx(sp->hs, 0, 0);
- sp->modehscx(sp->hs + 1, 0, 0);
- save_flags(flags);
- sp->counter = 0;
- sti();
-#ifdef CONFIG_HISAX_ELSA_PCC
- byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET | ENABLE_TIM_INT);
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + (110 * HZ) / 1000; /* Timeout 110ms */
- schedule();
- restore_flags(flags);
- printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
- sp->counter);
- if (abs(sp->counter - 13) < 3) {
- printk(KERN_INFO "Elsa: timer and irq OK\n");
- } else {
- printk(KERN_WARNING
- "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
- sp->counter, sp->irq);
- }
+ switch (mt) {
+ case CARD_RESET:
+ reset_elsa(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_elsa(cs);
+ return(0);
+ case CARD_SETIRQ:
+ if ((cs->subtyp == ELSA_QS1000PCI) ||
+ (cs->subtyp == ELSA_QS3000PCI))
+ ret = request_irq(cs->irq, &elsa_interrupt_ipac,
+ I4L_IRQ_FLAG | SA_SHIRQ, "HiSax", cs);
+ else
+ ret = request_irq(cs->irq, &elsa_interrupt,
+ I4L_IRQ_FLAG, "HiSax", cs);
+ return(ret);
+ case CARD_INIT:
+ cs->debug |= L1_DEB_IPAC;
+ inithscxisac(cs, 1);
+ if ((cs->subtyp == ELSA_QS1000) ||
+ (cs->subtyp == ELSA_QS3000))
+ {
+ byteout(cs->hw.elsa.timer, 0);
+ }
+ if (cs->hw.elsa.trig)
+ byteout(cs->hw.elsa.trig, 0xff);
+ inithscxisac(cs, 2);
+ return(0);
+ case CARD_TEST:
+ if ((cs->subtyp == ELSA_PCMCIA) ||
+ (cs->subtyp == ELSA_QS1000PCI)) {
+ return(0);
+ } else if (cs->subtyp == ELSA_QS3000PCI) {
+ ret = 0;
+ } else {
+ save_flags(flags);
+ cs->hw.elsa.counter = 0;
+ sti();
+ cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT;
+ cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
+ byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+ byteout(cs->hw.elsa.timer, 0);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (110 * HZ) / 1000; /* Timeout 110ms */
+ schedule();
+ restore_flags(flags);
+ cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
+ byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+ cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV;
+ printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
+ cs->hw.elsa.counter);
+ if (abs(cs->hw.elsa.counter - 13) < 3) {
+ printk(KERN_INFO "Elsa: timer and irq OK\n");
+ ret = 0;
+ } else {
+ printk(KERN_WARNING
+ "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
+ cs->hw.elsa.counter, cs->irq);
+ ret = 1;
+ }
+ }
+#if ARCOFI_USE
+ if (check_arcofi(cs)) {
+ init_modem(cs);
+ }
#endif
- printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq,
- kstat.interrupts[sp->irq]);
- if (kstat.interrupts[sp->irq] == irq_cnt) {
- printk(KERN_WARNING
- "Elsa: IRQ(%d) getting no interrupts during init %d\n",
- sp->irq, 4 - cnt);
- if (cnt == 1) {
- irq2dev_map[sp->irq] = NULL;
- free_irq(sp->irq, NULL);
- return (0);
+ elsa_led_handler(cs);
+ return(ret);
+ case (MDL_REMOVE | REQUEST):
+ cs->hw.elsa.status &= 0;
+ break;
+ case (MDL_ASSIGN | REQUEST):
+ cs->hw.elsa.status |= ELSA_ASSIGN;
+ break;
+ case MDL_INFO_SETUP:
+ if ((long) arg)
+ cs->hw.elsa.status |= 0x0200;
+ else
+ cs->hw.elsa.status |= 0x0100;
+ break;
+ case MDL_INFO_CONN:
+ if ((long) arg)
+ cs->hw.elsa.status |= 0x2000;
+ else
+ cs->hw.elsa.status |= 0x1000;
+ break;
+ case MDL_INFO_REL:
+ if ((long) arg) {
+ cs->hw.elsa.status &= ~0x2000;
+ cs->hw.elsa.status &= ~0x0200;
} else {
- reset_elsa(sp);
- cnt--;
+ cs->hw.elsa.status &= ~0x1000;
+ cs->hw.elsa.status &= ~0x0100;
}
- } else {
- check_arcofi(sp);
- cnt = 0;
- }
+ break;
+ case CARD_AUX_IND:
+ if (cs->hw.elsa.MFlag) {
+ if (!arg)
+ return(0);
+ msg = arg;
+ len = *msg;
+ msg++;
+ modem_write_cmd(cs, msg, len);
+ }
+ break;
}
- sp->counter = 0;
- return (ret);
+ if (cs->typ == ISDN_CTYPE_ELSA) {
+ int pwr = bytein(cs->hw.elsa.ale);
+ if (pwr & 0x08)
+ cs->hw.elsa.status |= ELSA_BAD_PWR;
+ else
+ cs->hw.elsa.status &= ~ELSA_BAD_PWR;
+ }
+ elsa_led_handler(cs);
+ return(ret);
}
-#ifdef CONFIG_HISAX_ELSA_PCC
static unsigned char
-probe_elsa_adr(unsigned int adr)
+probe_elsa_adr(unsigned int adr, int typ)
{
int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0,
pc_2 = 0, pfp_1 = 0, pfp_2 = 0;
long flags;
- if (check_region(adr, 8)) {
+ /* In case of the elsa pcmcia card, this region is in use,
+ reserved for us by the card manager. So we do not check it
+ here, it would fail. */
+ if (typ != ISDN_CTYPE_ELSA_PCMCIA && check_region(adr, 8)) {
printk(KERN_WARNING
"Elsa: Probing Port 0x%x: already in use\n",
adr);
@@ -1251,8 +879,8 @@
save_flags(flags);
cli();
for (i = 0; i < 16; i++) {
- in1 = inb(adr + CARD_CONFIG); /* 'toggelt' bei */
- in2 = inb(adr + CARD_CONFIG); /* jedem Zugriff */
+ in1 = inb(adr + ELSA_CONFIG); /* 'toggelt' bei */
+ in2 = inb(adr + ELSA_CONFIG); /* jedem Zugriff */
p16_1 += 0x04 & in1;
p16_2 += 0x04 & in2;
p8_1 += 0x02 & in1;
@@ -1283,205 +911,301 @@
}
static unsigned int
-probe_elsa(struct IsdnCardState *sp)
+probe_elsa(struct IsdnCardState *cs)
{
int i;
unsigned int CARD_portlist[] =
{0x160, 0x170, 0x260, 0x360, 0};
for (i = 0; CARD_portlist[i]; i++) {
- if ((sp->subtyp = probe_elsa_adr(CARD_portlist[i])))
+ if ((cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ)))
break;
}
return (CARD_portlist[i]);
}
-#endif
+
+static int pci_index __initdata = 0;
int
setup_elsa(struct IsdnCard *card)
{
-#ifdef CONFIG_HISAX_ELSA_PCC
long flags;
-#endif
int bytecnt;
- u_char val, verA, verB;
- struct IsdnCardState *sp = card->sp;
+ u_char val;
+ struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, Elsa_revision);
- printk(KERN_NOTICE "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
-#ifdef CONFIG_HISAX_ELSA_PCC
- if (sp->typ == ISDN_CTYPE_ELSA) {
- sp->cfg_reg = card->para[0];
+ printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+ cs->hw.elsa.ctrl_reg = 0;
+ cs->hw.elsa.status = 0;
+ cs->hw.elsa.MFlag = 0;
+ if (cs->typ == ISDN_CTYPE_ELSA) {
+ cs->hw.elsa.base = card->para[0];
printk(KERN_INFO "Elsa: Microlink IO probing\n");
- if (sp->cfg_reg) {
- if (!(sp->subtyp = probe_elsa_adr(sp->cfg_reg))) {
+ if (cs->hw.elsa.base) {
+ if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+ cs->typ))) {
printk(KERN_WARNING
"Elsa: no Elsa Microlink at 0x%x\n",
- sp->cfg_reg);
+ cs->hw.elsa.base);
return (0);
}
} else
- sp->cfg_reg = probe_elsa(sp);
- if (sp->cfg_reg) {
- val = bytein(sp->cfg_reg + CARD_CONFIG);
- if (sp->subtyp == ELSA_PC) {
+ cs->hw.elsa.base = probe_elsa(cs);
+ if (cs->hw.elsa.base) {
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ val = bytein(cs->hw.elsa.cfg);
+ if (cs->subtyp == ELSA_PC) {
const u_char CARD_IrqTab[8] =
{7, 3, 5, 9, 0, 0, 0, 0};
- sp->irq = CARD_IrqTab[(val & IRQ_INDEX_PC) >> 2];
- } else if (sp->subtyp == ELSA_PCC8) {
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+ } else if (cs->subtyp == ELSA_PCC8) {
const u_char CARD_IrqTab[8] =
{7, 3, 5, 9, 0, 0, 0, 0};
- sp->irq = CARD_IrqTab[(val & IRQ_INDEX_PCC8) >> 4];
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
} else {
const u_char CARD_IrqTab[8] =
{15, 10, 15, 3, 11, 5, 11, 9};
- sp->irq = CARD_IrqTab[(val & IRQ_INDEX) >> 3];
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
}
- val = bytein(sp->cfg_reg + CARD_ALE) & 0x7;
+ val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
if (val < 3)
val |= 8;
val += 'A' - 3;
if (val == 'B' || val == 'C')
val ^= 1;
- if ((sp->subtyp == ELSA_PCFPRO) && (val = 'G'))
+ if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
val = 'C';
printk(KERN_INFO
"Elsa: %s found at 0x%x Rev.:%c IRQ %d\n",
- Elsa_Types[sp->subtyp],
- sp->cfg_reg,
- val, sp->irq);
- val = bytein(sp->cfg_reg + CARD_ALE) & 0x08;
- if (val)
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ val, cs->irq);
+ val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
+ if (val) {
printk(KERN_WARNING
"Elsa: Microlink S0 bus power bad\n");
+ cs->hw.elsa.status |= ELSA_BAD_PWR;
+ }
} else {
printk(KERN_WARNING
"No Elsa Microlink found\n");
return (0);
}
- } else if (sp->typ == ISDN_CTYPE_ELSA_QS1000) {
- sp->cfg_reg = card->para[1];
- sp->irq = card->para[0];
- sp->subtyp = ELSA_QS1000;
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
+ cs->hw.elsa.base = card->para[1];
+ cs->irq = card->para[0];
+ cs->subtyp = ELSA_QS1000;
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
printk(KERN_INFO
- "Elsa: %s found at 0x%x IRQ %d\n",
- Elsa_Types[sp->subtyp],
- sp->cfg_reg,
- sp->irq);
- } else
- return (0);
-#endif
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
- if (sp->typ == ISDN_CTYPE_ELSA_QS1000) {
- sp->cfg_reg = card->para[1];
- sp->irq = card->para[0];
- sp->subtyp = ELSA_PCMCIA;
+ "Elsa: %s defined at 0x%x IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
+ cs->hw.elsa.base = card->para[1];
+ cs->irq = card->para[0];
+ cs->subtyp = ELSA_PCMCIA;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ cs->hw.elsa.ctrl = 0;
+ printk(KERN_INFO
+ "Elsa: %s defined at 0x%x IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+#if CONFIG_PCI
+ u_char pci_bus, pci_device_fn, pci_irq;
+ u_int pci_ioaddr;
+
+ cs->subtyp = 0;
+ for (; pci_index < 0xff; pci_index++) {
+ if (pcibios_find_device(PCI_VENDOR_ELSA,
+ PCI_QS1000_ID, pci_index, &pci_bus, &pci_device_fn)
+ == PCIBIOS_SUCCESSFUL)
+ cs->subtyp = ELSA_QS1000PCI;
+ else if (pcibios_find_device(PCI_VENDOR_ELSA,
+ PCI_QS3000_ID, pci_index, &pci_bus, &pci_device_fn)
+ == PCIBIOS_SUCCESSFUL)
+ cs->subtyp = ELSA_QS3000PCI;
+ else
+ break;
+ /* get IRQ */
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq);
+
+ /* get IO address */
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, &pci_ioaddr);
+ pci_ioaddr &= ~3; /* remove io/mem flag */
+ cs->hw.elsa.cfg = pci_ioaddr;
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_3, &pci_ioaddr);
+ if (cs->subtyp)
+ break;
+ }
+ if (!cs->subtyp) {
+ printk(KERN_WARNING "Elsa: No PCI card found\n");
+ return(0);
+ }
+ pci_index++;
+ if (!pci_irq) {
+ printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+ return(0);
+ }
+
+ if (!pci_ioaddr) {
+ printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ pci_ioaddr &= ~3; /* remove io/mem flag */
+ cs->hw.elsa.base = pci_ioaddr;
+ cs->hw.elsa.ale = pci_ioaddr;
+ cs->hw.elsa.isac = pci_ioaddr +1;
+ cs->hw.elsa.hscx = pci_ioaddr +1;
+ cs->irq = pci_irq;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
printk(KERN_INFO
- "Elsa: %s found at 0x%x IRQ %d\n",
- Elsa_Types[sp->subtyp],
- sp->cfg_reg,
- sp->irq);
+ "Elsa: %s defined at 0x%x/0x%x IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->hw.elsa.cfg,
+ cs->irq);
+#else
+ printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
+ printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
+ return (0);
+#endif /* CONFIG_PCI */
} else
return (0);
-#endif
- switch (sp->subtyp) {
+ switch (cs->subtyp) {
case ELSA_PC:
- bytecnt = 8;
- break;
case ELSA_PCC8:
- bytecnt = 8;
- break;
- case ELSA_PCFPRO:
- bytecnt = 16;
- break;
case ELSA_PCC16:
+ case ELSA_QS1000:
+ case ELSA_PCMCIA:
bytecnt = 8;
break;
+ case ELSA_PCFPRO:
case ELSA_PCF:
+ case ELSA_QS3000PCI:
bytecnt = 16;
break;
- case ELSA_QS1000:
- bytecnt = 8;
- break;
- case ELSA_PCMCIA:
- bytecnt = 8;
+ case ELSA_QS1000PCI:
+ bytecnt = 2;
break;
default:
printk(KERN_WARNING
- "Unknown ELSA subtype %d\n", sp->subtyp);
+ "Unknown ELSA subtype %d\n", cs->subtyp);
return (0);
}
-
- if (check_region((sp->cfg_reg), bytecnt)) {
+ /* In case of the elsa pcmcia card, this region is in use,
+ reserved for us by the card manager. So we do not check it
+ here, it would fail. */
+ if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && check_region(cs->hw.elsa.base, bytecnt)) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
- sp->cfg_reg,
- sp->cfg_reg + bytecnt);
+ cs->hw.elsa.base,
+ cs->hw.elsa.base + bytecnt);
return (0);
} else {
- request_region(sp->cfg_reg, bytecnt, "elsa isdn");
+ request_region(cs->hw.elsa.base, bytecnt, "elsa isdn");
}
-
- /* Teste Timer */
-#ifdef CONFIG_HISAX_ELSA_PCC
- byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
- byteout(sp->cfg_reg + CARD_START_TIMER, 0);
- if (!TimerRun(sp)) {
- byteout(sp->cfg_reg + CARD_START_TIMER, 0); /* 2. Versuch */
- if (!TimerRun(sp)) {
+ if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
+ if (check_region(cs->hw.elsa.cfg, 0x80)) {
printk(KERN_WARNING
- "Elsa: timer do not start\n");
- release_io_elsa(card);
+ "HiSax: %s pci port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.elsa.cfg,
+ cs->hw.elsa.cfg + 0x80);
+ release_region(cs->hw.elsa.base, bytecnt);
return (0);
+ } else {
+ request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci");
}
}
- save_flags(flags);
- sti();
- HZDELAY(1); /* wait >=10 ms */
- restore_flags(flags);
- if (TimerRun(sp)) {
- printk(KERN_WARNING "Elsa: timer do not run down\n");
- release_io_elsa(card);
- return (0);
+ cs->hw.elsa.tl.function = (void *) elsa_led_handler;
+ cs->hw.elsa.tl.data = (long) cs;
+ init_timer(&cs->hw.elsa.tl);
+ /* Teste Timer */
+ if (cs->hw.elsa.timer) {
+ byteout(cs->hw.elsa.trig, 0xff);
+ byteout(cs->hw.elsa.timer, 0);
+ if (!TimerRun(cs)) {
+ byteout(cs->hw.elsa.timer, 0); /* 2. Versuch */
+ if (!TimerRun(cs)) {
+ printk(KERN_WARNING
+ "Elsa: timer do not start\n");
+ release_io_elsa(cs);
+ return (0);
+ }
+ }
+ save_flags(flags);
+ sti();
+ HZDELAY(1); /* wait >=10 ms */
+ restore_flags(flags);
+ if (TimerRun(cs)) {
+ printk(KERN_WARNING "Elsa: timer do not run down\n");
+ release_io_elsa(cs);
+ return (0);
+ }
+ printk(KERN_INFO "Elsa: timer OK; resetting card\n");
}
- printk(KERN_INFO "Elsa: timer OK; resetting card\n");
- reset_elsa(sp);
-#endif
- verA = readhscx(sp->cfg_reg, 0, HSCX_VSTR) & 0xf;
- verB = readhscx(sp->cfg_reg, 1, HSCX_VSTR) & 0xf;
- printk(KERN_INFO "Elsa: HSCX version A: %s B: %s\n",
- HscxVersion(verA), HscxVersion(verB));
- val = readisac(sp->cfg_reg, ISAC_RBCH);
- printk(KERN_INFO "Elsa: ISAC %s\n",
- ISACVersion(val));
-
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
- if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
- printk(KERN_WARNING
- "Elsa: wrong HSCX versions check IO address\n");
- release_io_elsa(card);
- return (0);
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &Elsa_card_msg;
+ reset_elsa(cs);
+ if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
+ cs->readisac = &ReadISAC_IPAC;
+ cs->writeisac = &WriteISAC_IPAC;
+ cs->readisacfifo = &ReadISACfifo_IPAC;
+ cs->writeisacfifo = &WriteISACfifo_IPAC;
+ val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID);
+ printk(KERN_INFO "Elsa: IPAC version %x\n", val);
+ } else {
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ ISACVersion(cs, "Elsa:");
+ if (HscxVersion(cs, "Elsa:")) {
+ printk(KERN_WARNING
+ "Elsa: wrong HSCX versions check IO address\n");
+ release_io_elsa(cs);
+ return (0);
+ }
}
-#endif
-
-#ifdef CONFIG_HISAX_ELSA_PCC
- if (sp->subtyp == ELSA_PC) {
- val = readitac(sp->cfg_reg, ITAC_SYS);
+ if (cs->subtyp == ELSA_PC) {
+ val = readitac(cs, ITAC_SYS);
printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]);
- writeitac(sp->cfg_reg, ITAC_ISEN, 0);
- writeitac(sp->cfg_reg, ITAC_RFIE, 0);
- writeitac(sp->cfg_reg, ITAC_XFIE, 0);
- writeitac(sp->cfg_reg, ITAC_SCIE, 0);
- writeitac(sp->cfg_reg, ITAC_STIE, 0);
+ writeitac(cs, ITAC_ISEN, 0);
+ writeitac(cs, ITAC_RFIE, 0);
+ writeitac(cs, ITAC_XFIE, 0);
+ writeitac(cs, ITAC_SCIE, 0);
+ writeitac(cs, ITAC_STIE, 0);
}
-#endif
- sp->modehscx = &modehscx;
- sp->ph_command = &ph_command;
- sp->hscx_fill_fifo = &hscx_fill_fifo;
- sp->isac_fill_fifo = &isac_fill_fifo;
-
return (1);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov