Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* $Id: elsa.c,v 2.32.2.4 2004/01/24 20:47:21 keil Exp $ |
| 2 | * |
| 3 | * low level stuff for Elsa isdn cards |
| 4 | * |
| 5 | * Author Karsten Keil |
| 6 | * Copyright by Karsten Keil <keil@isdn4linux.de> |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 7 | * |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 8 | * This software may be used and distributed according to the terms |
| 9 | * of the GNU General Public License, incorporated herein by reference. |
| 10 | * |
| 11 | * For changes and modifications please read |
| 12 | * Documentation/isdn/HiSax.cert |
| 13 | * |
| 14 | * Thanks to Elsa GmbH for documents and information |
| 15 | * |
| 16 | * Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE) |
| 17 | * for ELSA PCMCIA support |
| 18 | * |
| 19 | */ |
| 20 | |
| 21 | #include <linux/init.h> |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 22 | #include <linux/slab.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 | #include "hisax.h" |
| 24 | #include "arcofi.h" |
| 25 | #include "isac.h" |
| 26 | #include "ipac.h" |
| 27 | #include "hscx.h" |
| 28 | #include "isdnl1.h" |
| 29 | #include <linux/pci.h> |
| 30 | #include <linux/isapnp.h> |
| 31 | #include <linux/serial.h> |
| 32 | #include <linux/serial_reg.h> |
| 33 | |
Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 34 | static const char *Elsa_revision = "$Revision: 2.32.2.4 $"; |
| 35 | static const char *Elsa_Types[] = |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 | {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 37 | "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 38 | "PCMCIA-IPAC" }; |
| 39 | |
Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 40 | static const char *ITACVer[] = |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 41 | {"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2", |
| 42 | "B1", "A1"}; |
| 43 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 44 | #define byteout(addr, val) outb(val, addr) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 45 | #define bytein(addr) inb(addr) |
| 46 | |
| 47 | #define ELSA_ISAC 0 |
| 48 | #define ELSA_ISAC_PCM 1 |
| 49 | #define ELSA_ITAC 1 |
| 50 | #define ELSA_HSCX 2 |
| 51 | #define ELSA_ALE 3 |
| 52 | #define ELSA_ALE_PCM 4 |
| 53 | #define ELSA_CONTROL 4 |
| 54 | #define ELSA_CONFIG 5 |
| 55 | #define ELSA_START_TIMER 6 |
| 56 | #define ELSA_TRIG_IRQ 7 |
| 57 | |
| 58 | #define ELSA_PC 1 |
| 59 | #define ELSA_PCC8 2 |
| 60 | #define ELSA_PCC16 3 |
| 61 | #define ELSA_PCF 4 |
| 62 | #define ELSA_PCFPRO 5 |
| 63 | #define ELSA_PCMCIA 6 |
| 64 | #define ELSA_QS1000 7 |
| 65 | #define ELSA_QS3000 8 |
| 66 | #define ELSA_QS1000PCI 9 |
| 67 | #define ELSA_QS3000PCI 10 |
| 68 | #define ELSA_PCMCIA_IPAC 11 |
| 69 | |
| 70 | /* PCI stuff */ |
| 71 | #define ELSA_PCI_IRQ_MASK 0x04 |
| 72 | |
| 73 | /* ITAC Registeradressen (only Microlink PC) */ |
| 74 | #define ITAC_SYS 0x34 |
| 75 | #define ITAC_ISEN 0x48 |
| 76 | #define ITAC_RFIE 0x4A |
| 77 | #define ITAC_XFIE 0x4C |
| 78 | #define ITAC_SCIE 0x4E |
| 79 | #define ITAC_STIE 0x46 |
| 80 | |
| 81 | /*** *** |
| 82 | *** Makros als Befehle fuer die Kartenregister *** |
| 83 | *** (mehrere Befehle werden durch Bit-Oderung kombiniert) *** |
| 84 | *** ***/ |
| 85 | |
| 86 | /* Config-Register (Read) */ |
Thomas Gleixner | 9ba02be | 2006-07-01 19:29:36 -0700 | [diff] [blame] | 87 | #define ELIRQF_TIMER_RUN 0x02 /* Bit 1 des Config-Reg */ |
| 88 | #define ELIRQF_TIMER_RUN_PCC8 0x01 /* Bit 0 des Config-Reg bei PCC */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 89 | #define ELSA_IRQ_IDX 0x38 /* Bit 3,4,5 des Config-Reg */ |
| 90 | #define ELSA_IRQ_IDX_PCC8 0x30 /* Bit 4,5 des Config-Reg */ |
| 91 | #define ELSA_IRQ_IDX_PC 0x0c /* Bit 2,3 des Config-Reg */ |
| 92 | |
| 93 | /* Control-Register (Write) */ |
| 94 | #define ELSA_LINE_LED 0x02 /* Bit 1 Gelbe LED */ |
| 95 | #define ELSA_STAT_LED 0x08 /* Bit 3 Gruene LED */ |
| 96 | #define ELSA_ISDN_RESET 0x20 /* Bit 5 Reset-Leitung */ |
| 97 | #define ELSA_ENA_TIMER_INT 0x80 /* Bit 7 Freigabe Timer Interrupt */ |
| 98 | |
| 99 | /* ALE-Register (Read) */ |
| 100 | #define ELSA_HW_RELEASE 0x07 /* Bit 0-2 Hardwarerkennung */ |
| 101 | #define ELSA_S0_POWER_BAD 0x08 /* Bit 3 S0-Bus Spannung fehlt */ |
| 102 | |
| 103 | /* Status Flags */ |
Thomas Gleixner | 9ba02be | 2006-07-01 19:29:36 -0700 | [diff] [blame] | 104 | #define ELIRQF_TIMER_AKTIV 1 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | #define ELSA_BAD_PWR 2 |
| 106 | #define ELSA_ASSIGN 4 |
| 107 | |
| 108 | #define RS_ISR_PASS_LIMIT 256 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 109 | #define FLG_MODEM_ACTIVE 1 |
| 110 | /* IPAC AUX */ |
| 111 | #define ELSA_IPAC_LINE_LED 0x40 /* Bit 6 Gelbe LED */ |
| 112 | #define ELSA_IPAC_STAT_LED 0x80 /* Bit 7 Gruene LED */ |
| 113 | |
| 114 | #if ARCOFI_USE |
| 115 | static struct arcofi_msg ARCOFI_XOP_F = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 116 | {NULL,0,2,{0xa1,0x3f,0,0,0,0,0,0,0,0}}; /* Normal OP */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 117 | static struct arcofi_msg ARCOFI_XOP_1 = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 118 | {&ARCOFI_XOP_F,0,2,{0xa1,0x31,0,0,0,0,0,0,0,0}}; /* PWR UP */ |
| 119 | static struct arcofi_msg ARCOFI_SOP_F = |
| 120 | {&ARCOFI_XOP_1,0,10,{0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12}}; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 121 | static struct arcofi_msg ARCOFI_COP_9 = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 122 | {&ARCOFI_SOP_F,0,10,{0xa1,0x29,0x80,0xcb,0xe9,0x88,0x00,0xc8,0xd8,0x80}}; /* RX */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 123 | static struct arcofi_msg ARCOFI_COP_8 = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 124 | {&ARCOFI_COP_9,0,10,{0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}}; /* TX */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 | static struct arcofi_msg ARCOFI_COP_7 = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 126 | {&ARCOFI_COP_8,0,4,{0xa1,0x27,0x80,0x80,0,0,0,0,0,0}}; /* GZ */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 | static struct arcofi_msg ARCOFI_COP_6 = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 128 | {&ARCOFI_COP_7,0,6,{0xa1,0x26,0,0,0x82,0x7c,0,0,0,0}}; /* GRL GRH */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 | static struct arcofi_msg ARCOFI_COP_5 = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 130 | {&ARCOFI_COP_6,0,4,{0xa1,0x25,0xbb,0x4a,0,0,0,0,0,0}}; /* GTX */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 131 | static struct arcofi_msg ARCOFI_VERSION = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 132 | {NULL,1,2,{0xa0,0,0,0,0,0,0,0,0,0}}; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 133 | static struct arcofi_msg ARCOFI_XOP_0 = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 134 | {NULL,0,2,{0xa1,0x30,0,0,0,0,0,0,0,0}}; /* PWR Down */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 135 | |
| 136 | static void set_arcofi(struct IsdnCardState *cs, int bc); |
| 137 | |
| 138 | #include "elsa_ser.c" |
| 139 | #endif /* ARCOFI_USE */ |
| 140 | |
| 141 | static inline u_char |
| 142 | readreg(unsigned int ale, unsigned int adr, u_char off) |
| 143 | { |
| 144 | register u_char ret; |
| 145 | |
| 146 | byteout(ale, off); |
| 147 | ret = bytein(adr); |
| 148 | return (ret); |
| 149 | } |
| 150 | |
| 151 | static inline void |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 152 | readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 153 | { |
| 154 | byteout(ale, off); |
| 155 | insb(adr, data, size); |
| 156 | } |
| 157 | |
| 158 | |
| 159 | static inline void |
| 160 | writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) |
| 161 | { |
| 162 | byteout(ale, off); |
| 163 | byteout(adr, data); |
| 164 | } |
| 165 | |
| 166 | static inline void |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 167 | writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 168 | { |
| 169 | byteout(ale, off); |
| 170 | outsb(adr, data, size); |
| 171 | } |
| 172 | |
| 173 | /* Interface functions */ |
| 174 | |
| 175 | static u_char |
| 176 | ReadISAC(struct IsdnCardState *cs, u_char offset) |
| 177 | { |
| 178 | return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset)); |
| 179 | } |
| 180 | |
| 181 | static void |
| 182 | WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) |
| 183 | { |
| 184 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset, value); |
| 185 | } |
| 186 | |
| 187 | static void |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 188 | ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 189 | { |
| 190 | readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size); |
| 191 | } |
| 192 | |
| 193 | static void |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 194 | WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 195 | { |
| 196 | writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size); |
| 197 | } |
| 198 | |
| 199 | static u_char |
| 200 | ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) |
| 201 | { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 202 | return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset + 0x80)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 203 | } |
| 204 | |
| 205 | static void |
| 206 | WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) |
| 207 | { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 208 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset | 0x80, value); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 209 | } |
| 210 | |
| 211 | static void |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 212 | ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 213 | { |
| 214 | readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size); |
| 215 | } |
| 216 | |
| 217 | static void |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 218 | WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 219 | { |
| 220 | writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size); |
| 221 | } |
| 222 | |
| 223 | static u_char |
| 224 | ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) |
| 225 | { |
| 226 | return (readreg(cs->hw.elsa.ale, |
| 227 | cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0))); |
| 228 | } |
| 229 | |
| 230 | static void |
| 231 | WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) |
| 232 | { |
| 233 | writereg(cs->hw.elsa.ale, |
| 234 | cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value); |
| 235 | } |
| 236 | |
| 237 | static inline u_char |
| 238 | readitac(struct IsdnCardState *cs, u_char off) |
| 239 | { |
| 240 | register u_char ret; |
| 241 | |
| 242 | byteout(cs->hw.elsa.ale, off); |
| 243 | ret = bytein(cs->hw.elsa.itac); |
| 244 | return (ret); |
| 245 | } |
| 246 | |
| 247 | static inline void |
| 248 | writeitac(struct IsdnCardState *cs, u_char off, u_char data) |
| 249 | { |
| 250 | byteout(cs->hw.elsa.ale, off); |
| 251 | byteout(cs->hw.elsa.itac, data); |
| 252 | } |
| 253 | |
| 254 | static inline int |
| 255 | TimerRun(struct IsdnCardState *cs) |
| 256 | { |
| 257 | register u_char v; |
| 258 | |
| 259 | v = bytein(cs->hw.elsa.cfg); |
| 260 | if ((cs->subtyp == ELSA_QS1000) || (cs->subtyp == ELSA_QS3000)) |
Thomas Gleixner | 9ba02be | 2006-07-01 19:29:36 -0700 | [diff] [blame] | 261 | return (0 == (v & ELIRQF_TIMER_RUN)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 262 | else if (cs->subtyp == ELSA_PCC8) |
Thomas Gleixner | 9ba02be | 2006-07-01 19:29:36 -0700 | [diff] [blame] | 263 | return (v & ELIRQF_TIMER_RUN_PCC8); |
| 264 | return (v & ELIRQF_TIMER_RUN); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 265 | } |
| 266 | /* |
| 267 | * fast interrupt HSCX stuff goes here |
| 268 | */ |
| 269 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 270 | #define READHSCX(cs, nr, reg) readreg(cs->hw.elsa.ale, \ |
| 271 | cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0)) |
| 272 | #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.elsa.ale, \ |
| 273 | cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0), data) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 274 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 275 | #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.elsa.ale, \ |
| 276 | cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 277 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 278 | #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.elsa.ale, \ |
| 279 | cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 280 | |
| 281 | #include "hscx_irq.c" |
| 282 | |
| 283 | static irqreturn_t |
David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 284 | elsa_interrupt(int intno, void *dev_id) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 285 | { |
| 286 | struct IsdnCardState *cs = dev_id; |
| 287 | u_long flags; |
| 288 | u_char val; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 289 | int icnt = 5; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 290 | |
| 291 | if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 292 | /* The card tends to generate interrupts while being removed |
| 293 | causing us to just crash the kernel. bad. */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 294 | printk(KERN_WARNING "Elsa: card not available!\n"); |
| 295 | return IRQ_NONE; |
| 296 | } |
| 297 | spin_lock_irqsave(&cs->lock, flags); |
| 298 | #if ARCOFI_USE |
| 299 | if (cs->hw.elsa.MFlag) { |
| 300 | val = serial_inp(cs, UART_IIR); |
| 301 | if (!(val & UART_IIR_NO_INT)) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 302 | debugl1(cs, "IIR %02x", val); |
Jeff Garzik | 896c6fa | 2007-10-31 05:42:50 -0400 | [diff] [blame] | 303 | rs_interrupt_elsa(cs); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 304 | } |
| 305 | } |
| 306 | #endif |
| 307 | val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 308 | Start_HSCX: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 309 | if (val) { |
| 310 | hscx_int_main(cs, val); |
| 311 | } |
| 312 | val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 313 | Start_ISAC: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 314 | if (val) { |
| 315 | isac_interrupt(cs, val); |
| 316 | } |
| 317 | val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); |
| 318 | if (val && icnt) { |
| 319 | if (cs->debug & L1_DEB_HSCX) |
| 320 | debugl1(cs, "HSCX IntStat after IntRoutine"); |
| 321 | icnt--; |
| 322 | goto Start_HSCX; |
| 323 | } |
| 324 | val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA); |
| 325 | if (val && icnt) { |
| 326 | if (cs->debug & L1_DEB_ISAC) |
| 327 | debugl1(cs, "ISAC IntStat after IntRoutine"); |
| 328 | icnt--; |
| 329 | goto Start_ISAC; |
| 330 | } |
| 331 | if (!icnt) |
| 332 | printk(KERN_WARNING"ELSA IRQ LOOP\n"); |
| 333 | writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF); |
| 334 | writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF); |
| 335 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF); |
Thomas Gleixner | 9ba02be | 2006-07-01 19:29:36 -0700 | [diff] [blame] | 336 | if (cs->hw.elsa.status & ELIRQF_TIMER_AKTIV) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 337 | if (!TimerRun(cs)) { |
| 338 | /* Timer Restart */ |
| 339 | byteout(cs->hw.elsa.timer, 0); |
| 340 | cs->hw.elsa.counter++; |
| 341 | } |
| 342 | } |
| 343 | #if ARCOFI_USE |
| 344 | if (cs->hw.elsa.MFlag) { |
| 345 | val = serial_inp(cs, UART_MCR); |
| 346 | val ^= 0x8; |
| 347 | serial_outp(cs, UART_MCR, val); |
| 348 | val = serial_inp(cs, UART_MCR); |
| 349 | val ^= 0x8; |
| 350 | serial_outp(cs, UART_MCR, val); |
| 351 | } |
| 352 | #endif |
| 353 | if (cs->hw.elsa.trig) |
| 354 | byteout(cs->hw.elsa.trig, 0x00); |
| 355 | writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0); |
| 356 | writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0x0); |
| 357 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0x0); |
| 358 | spin_unlock_irqrestore(&cs->lock, flags); |
| 359 | return IRQ_HANDLED; |
| 360 | } |
| 361 | |
| 362 | static irqreturn_t |
David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 363 | elsa_interrupt_ipac(int intno, void *dev_id) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 364 | { |
| 365 | struct IsdnCardState *cs = dev_id; |
| 366 | u_long flags; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 367 | u_char ista, val; |
| 368 | int icnt = 5; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 369 | |
| 370 | spin_lock_irqsave(&cs->lock, flags); |
| 371 | if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) { |
| 372 | val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */ |
| 373 | if (!(val & ELSA_PCI_IRQ_MASK)) { |
| 374 | spin_unlock_irqrestore(&cs->lock, flags); |
| 375 | return IRQ_NONE; |
| 376 | } |
| 377 | } |
| 378 | #if ARCOFI_USE |
| 379 | if (cs->hw.elsa.MFlag) { |
| 380 | val = serial_inp(cs, UART_IIR); |
| 381 | if (!(val & UART_IIR_NO_INT)) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 382 | debugl1(cs, "IIR %02x", val); |
Jeff Garzik | 896c6fa | 2007-10-31 05:42:50 -0400 | [diff] [blame] | 383 | rs_interrupt_elsa(cs); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 384 | } |
| 385 | } |
| 386 | #endif |
| 387 | ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); |
| 388 | Start_IPAC: |
| 389 | if (cs->debug & L1_DEB_IPAC) |
| 390 | debugl1(cs, "IPAC ISTA %02X", ista); |
| 391 | if (ista & 0x0f) { |
| 392 | val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); |
| 393 | if (ista & 0x01) |
| 394 | val |= 0x01; |
| 395 | if (ista & 0x04) |
| 396 | val |= 0x02; |
| 397 | if (ista & 0x08) |
| 398 | val |= 0x04; |
| 399 | if (val) |
| 400 | hscx_int_main(cs, val); |
| 401 | } |
| 402 | if (ista & 0x20) { |
| 403 | val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80); |
| 404 | if (val) { |
| 405 | isac_interrupt(cs, val); |
| 406 | } |
| 407 | } |
| 408 | if (ista & 0x10) { |
| 409 | val = 0x01; |
| 410 | isac_interrupt(cs, val); |
| 411 | } |
| 412 | ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); |
| 413 | if ((ista & 0x3f) && icnt) { |
| 414 | icnt--; |
| 415 | goto Start_IPAC; |
| 416 | } |
| 417 | if (!icnt) |
| 418 | printk(KERN_WARNING "ELSA IRQ LOOP\n"); |
| 419 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF); |
| 420 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0); |
| 421 | spin_unlock_irqrestore(&cs->lock, flags); |
| 422 | return IRQ_HANDLED; |
| 423 | } |
| 424 | |
Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 425 | static void |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 426 | release_io_elsa(struct IsdnCardState *cs) |
| 427 | { |
| 428 | int bytecnt = 8; |
| 429 | |
| 430 | del_timer(&cs->hw.elsa.tl); |
| 431 | #if ARCOFI_USE |
| 432 | clear_arcofi(cs); |
| 433 | #endif |
| 434 | if (cs->hw.elsa.ctrl) |
| 435 | byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */ |
| 436 | if (cs->subtyp == ELSA_QS1000PCI) { |
| 437 | byteout(cs->hw.elsa.cfg + 0x4c, 0x01); /* disable IRQ */ |
| 438 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); |
| 439 | bytecnt = 2; |
| 440 | release_region(cs->hw.elsa.cfg, 0x80); |
| 441 | } |
| 442 | if (cs->subtyp == ELSA_QS3000PCI) { |
| 443 | byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* disable ELSA PCI IRQ */ |
| 444 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); |
| 445 | release_region(cs->hw.elsa.cfg, 0x80); |
| 446 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 447 | if (cs->subtyp == ELSA_PCMCIA_IPAC) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 448 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 449 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 450 | if ((cs->subtyp == ELSA_PCFPRO) || |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 451 | (cs->subtyp == ELSA_QS3000) || |
| 452 | (cs->subtyp == ELSA_PCF) || |
| 453 | (cs->subtyp == ELSA_QS3000PCI)) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 454 | bytecnt = 16; |
| 455 | #if ARCOFI_USE |
| 456 | release_modem(cs); |
| 457 | #endif |
| 458 | } |
| 459 | if (cs->hw.elsa.base) |
| 460 | release_region(cs->hw.elsa.base, bytecnt); |
| 461 | } |
| 462 | |
| 463 | static void |
| 464 | reset_elsa(struct IsdnCardState *cs) |
| 465 | { |
| 466 | if (cs->hw.elsa.timer) { |
| 467 | /* Wait 1 Timer */ |
| 468 | byteout(cs->hw.elsa.timer, 0); |
| 469 | while (TimerRun(cs)); |
| 470 | cs->hw.elsa.ctrl_reg |= 0x50; |
| 471 | cs->hw.elsa.ctrl_reg &= ~ELSA_ISDN_RESET; /* Reset On */ |
| 472 | byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); |
| 473 | /* Wait 1 Timer */ |
| 474 | byteout(cs->hw.elsa.timer, 0); |
| 475 | while (TimerRun(cs)); |
| 476 | cs->hw.elsa.ctrl_reg |= ELSA_ISDN_RESET; /* Reset Off */ |
| 477 | byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); |
| 478 | /* Wait 1 Timer */ |
| 479 | byteout(cs->hw.elsa.timer, 0); |
| 480 | while (TimerRun(cs)); |
| 481 | if (cs->hw.elsa.trig) |
| 482 | byteout(cs->hw.elsa.trig, 0xff); |
| 483 | } |
| 484 | if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) { |
| 485 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20); |
| 486 | mdelay(10); |
| 487 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00); |
| 488 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0); |
| 489 | mdelay(10); |
| 490 | if (cs->subtyp != ELSA_PCMCIA_IPAC) { |
| 491 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0); |
| 492 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c); |
| 493 | } else { |
| 494 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_PCFG, 0x10); |
| 495 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x4); |
| 496 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0xf8); |
| 497 | } |
| 498 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); |
| 499 | if (cs->subtyp == ELSA_QS1000PCI) |
| 500 | byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */ |
| 501 | else if (cs->subtyp == ELSA_QS3000PCI) |
| 502 | byteout(cs->hw.elsa.cfg + 0x4c, 0x43); /* enable ELSA PCI IRQ */ |
| 503 | } |
| 504 | } |
| 505 | |
| 506 | #if ARCOFI_USE |
| 507 | |
| 508 | static void |
| 509 | set_arcofi(struct IsdnCardState *cs, int bc) { |
| 510 | cs->dc.isac.arcofi_bc = bc; |
| 511 | arcofi_fsm(cs, ARCOFI_START, &ARCOFI_COP_5); |
Arnd Bergmann | c728cc8 | 2014-02-26 12:01:53 +0100 | [diff] [blame] | 512 | wait_event_interruptible(cs->dc.isac.arcofi_wait, |
| 513 | cs->dc.isac.arcofi_state == ARCOFI_NOP); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 514 | } |
| 515 | |
| 516 | static int |
| 517 | check_arcofi(struct IsdnCardState *cs) |
| 518 | { |
| 519 | int arcofi_present = 0; |
| 520 | char tmp[40]; |
| 521 | char *t; |
| 522 | u_char *p; |
| 523 | |
| 524 | if (!cs->dc.isac.mon_tx) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 525 | if (!(cs->dc.isac.mon_tx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 526 | if (cs->debug & L1_DEB_WARN) |
| 527 | debugl1(cs, "ISAC MON TX out of buffers!"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 528 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 529 | } |
| 530 | cs->dc.isac.arcofi_bc = 0; |
| 531 | arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION); |
Arnd Bergmann | c728cc8 | 2014-02-26 12:01:53 +0100 | [diff] [blame] | 532 | wait_event_interruptible(cs->dc.isac.arcofi_wait, |
| 533 | cs->dc.isac.arcofi_state == ARCOFI_NOP); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 534 | if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 535 | debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp); |
| 536 | p = cs->dc.isac.mon_rx; |
| 537 | t = tmp; |
| 538 | t += sprintf(tmp, "Arcofi data"); |
| 539 | QuickHex(t, p, cs->dc.isac.mon_rxp); |
Kees Cook | 35a4a57 | 2013-09-13 14:52:04 -0700 | [diff] [blame] | 540 | debugl1(cs, "%s", tmp); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 541 | if ((cs->dc.isac.mon_rxp == 2) && (cs->dc.isac.mon_rx[0] == 0xa0)) { |
| 542 | switch (cs->dc.isac.mon_rx[1]) { |
| 543 | case 0x80: |
| 544 | debugl1(cs, "Arcofi 2160 detected"); |
| 545 | arcofi_present = 1; |
| 546 | break; |
| 547 | case 0x82: |
| 548 | debugl1(cs, "Arcofi 2165 detected"); |
| 549 | arcofi_present = 2; |
| 550 | break; |
| 551 | case 0x84: |
| 552 | debugl1(cs, "Arcofi 2163 detected"); |
| 553 | arcofi_present = 3; |
| 554 | break; |
| 555 | default: |
| 556 | debugl1(cs, "unknown Arcofi response"); |
| 557 | break; |
| 558 | } |
| 559 | } else |
| 560 | debugl1(cs, "undefined Monitor response"); |
| 561 | cs->dc.isac.mon_rxp = 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 562 | } else if (cs->dc.isac.mon_tx) { |
| 563 | debugl1(cs, "Arcofi not detected"); |
| 564 | } |
| 565 | if (arcofi_present) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 566 | if (cs->subtyp == ELSA_QS1000) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 567 | cs->subtyp = ELSA_QS3000; |
| 568 | printk(KERN_INFO |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 569 | "Elsa: %s detected modem at 0x%lx\n", |
| 570 | Elsa_Types[cs->subtyp], |
| 571 | cs->hw.elsa.base + 8); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 572 | release_region(cs->hw.elsa.base, 8); |
| 573 | if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) { |
| 574 | printk(KERN_WARNING |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 575 | "HiSax: %s config port %lx-%lx already in use\n", |
| 576 | Elsa_Types[cs->subtyp], |
| 577 | cs->hw.elsa.base + 8, |
| 578 | cs->hw.elsa.base + 16); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 579 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 580 | } else if (cs->subtyp == ELSA_PCC16) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 581 | cs->subtyp = ELSA_PCF; |
| 582 | printk(KERN_INFO |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 583 | "Elsa: %s detected modem at 0x%lx\n", |
| 584 | Elsa_Types[cs->subtyp], |
| 585 | cs->hw.elsa.base + 8); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 586 | release_region(cs->hw.elsa.base, 8); |
| 587 | if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) { |
| 588 | printk(KERN_WARNING |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 589 | "HiSax: %s config port %lx-%lx already in use\n", |
| 590 | Elsa_Types[cs->subtyp], |
| 591 | cs->hw.elsa.base + 8, |
| 592 | cs->hw.elsa.base + 16); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 593 | } |
| 594 | } else |
| 595 | printk(KERN_INFO |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 596 | "Elsa: %s detected modem at 0x%lx\n", |
| 597 | Elsa_Types[cs->subtyp], |
| 598 | cs->hw.elsa.base + 8); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 599 | arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0); |
Arnd Bergmann | c728cc8 | 2014-02-26 12:01:53 +0100 | [diff] [blame] | 600 | wait_event_interruptible(cs->dc.isac.arcofi_wait, |
| 601 | cs->dc.isac.arcofi_state == ARCOFI_NOP); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 602 | return (1); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 603 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 604 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 605 | } |
| 606 | #endif /* ARCOFI_USE */ |
| 607 | |
| 608 | static void |
| 609 | elsa_led_handler(struct IsdnCardState *cs) |
| 610 | { |
| 611 | int blink = 0; |
| 612 | |
| 613 | if (cs->subtyp == ELSA_PCMCIA || cs->subtyp == ELSA_PCMCIA_IPAC) |
| 614 | return; |
| 615 | del_timer(&cs->hw.elsa.tl); |
| 616 | if (cs->hw.elsa.status & ELSA_ASSIGN) |
| 617 | cs->hw.elsa.ctrl_reg |= ELSA_STAT_LED; |
| 618 | else if (cs->hw.elsa.status & ELSA_BAD_PWR) |
| 619 | cs->hw.elsa.ctrl_reg &= ~ELSA_STAT_LED; |
| 620 | else { |
| 621 | cs->hw.elsa.ctrl_reg ^= ELSA_STAT_LED; |
| 622 | blink = 250; |
| 623 | } |
| 624 | if (cs->hw.elsa.status & 0xf000) |
| 625 | cs->hw.elsa.ctrl_reg |= ELSA_LINE_LED; |
| 626 | else if (cs->hw.elsa.status & 0x0f00) { |
| 627 | cs->hw.elsa.ctrl_reg ^= ELSA_LINE_LED; |
| 628 | blink = 500; |
| 629 | } else |
| 630 | cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED; |
| 631 | |
| 632 | if ((cs->subtyp == ELSA_QS1000PCI) || |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 633 | (cs->subtyp == ELSA_QS3000PCI)) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 634 | u_char led = 0xff; |
| 635 | if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED) |
| 636 | led ^= ELSA_IPAC_LINE_LED; |
| 637 | if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED) |
| 638 | led ^= ELSA_IPAC_STAT_LED; |
| 639 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led); |
| 640 | } else |
| 641 | byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); |
| 642 | if (blink) { |
| 643 | init_timer(&cs->hw.elsa.tl); |
| 644 | cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000); |
| 645 | add_timer(&cs->hw.elsa.tl); |
| 646 | } |
| 647 | } |
| 648 | |
| 649 | static int |
| 650 | Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) |
| 651 | { |
| 652 | int ret = 0; |
| 653 | u_long flags; |
| 654 | |
| 655 | switch (mt) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 656 | case CARD_RESET: |
| 657 | spin_lock_irqsave(&cs->lock, flags); |
| 658 | reset_elsa(cs); |
| 659 | spin_unlock_irqrestore(&cs->lock, flags); |
| 660 | return (0); |
| 661 | case CARD_RELEASE: |
| 662 | release_io_elsa(cs); |
| 663 | return (0); |
| 664 | case CARD_INIT: |
| 665 | spin_lock_irqsave(&cs->lock, flags); |
| 666 | cs->debug |= L1_DEB_IPAC; |
| 667 | reset_elsa(cs); |
| 668 | inithscxisac(cs, 1); |
| 669 | if ((cs->subtyp == ELSA_QS1000) || |
| 670 | (cs->subtyp == ELSA_QS3000)) |
| 671 | { |
| 672 | byteout(cs->hw.elsa.timer, 0); |
| 673 | } |
| 674 | if (cs->hw.elsa.trig) |
| 675 | byteout(cs->hw.elsa.trig, 0xff); |
| 676 | inithscxisac(cs, 2); |
| 677 | spin_unlock_irqrestore(&cs->lock, flags); |
| 678 | return (0); |
| 679 | case CARD_TEST: |
| 680 | if ((cs->subtyp == ELSA_PCMCIA) || |
| 681 | (cs->subtyp == ELSA_PCMCIA_IPAC) || |
| 682 | (cs->subtyp == ELSA_QS1000PCI)) { |
| 683 | return (0); |
| 684 | } else if (cs->subtyp == ELSA_QS3000PCI) { |
| 685 | ret = 0; |
| 686 | } else { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 687 | spin_lock_irqsave(&cs->lock, flags); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 688 | cs->hw.elsa.counter = 0; |
| 689 | cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT; |
| 690 | cs->hw.elsa.status |= ELIRQF_TIMER_AKTIV; |
| 691 | byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); |
| 692 | byteout(cs->hw.elsa.timer, 0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 693 | spin_unlock_irqrestore(&cs->lock, flags); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 694 | msleep(110); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 695 | spin_lock_irqsave(&cs->lock, flags); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 696 | cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; |
| 697 | byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); |
| 698 | cs->hw.elsa.status &= ~ELIRQF_TIMER_AKTIV; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 699 | spin_unlock_irqrestore(&cs->lock, flags); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 700 | printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", |
| 701 | cs->hw.elsa.counter); |
| 702 | if ((cs->hw.elsa.counter > 10) && |
| 703 | (cs->hw.elsa.counter < 16)) { |
| 704 | printk(KERN_INFO "Elsa: timer and irq OK\n"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 705 | ret = 0; |
| 706 | } else { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 707 | printk(KERN_WARNING |
| 708 | "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n", |
| 709 | cs->hw.elsa.counter, cs->irq); |
| 710 | ret = 1; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 711 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 712 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 713 | #if ARCOFI_USE |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 714 | if (check_arcofi(cs)) { |
| 715 | init_modem(cs); |
| 716 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 717 | #endif |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 718 | elsa_led_handler(cs); |
| 719 | return (ret); |
| 720 | case (MDL_REMOVE | REQUEST): |
| 721 | cs->hw.elsa.status &= 0; |
| 722 | break; |
| 723 | case (MDL_ASSIGN | REQUEST): |
| 724 | cs->hw.elsa.status |= ELSA_ASSIGN; |
| 725 | break; |
| 726 | case MDL_INFO_SETUP: |
| 727 | if ((long) arg) |
| 728 | cs->hw.elsa.status |= 0x0200; |
| 729 | else |
| 730 | cs->hw.elsa.status |= 0x0100; |
| 731 | break; |
| 732 | case MDL_INFO_CONN: |
| 733 | if ((long) arg) |
| 734 | cs->hw.elsa.status |= 0x2000; |
| 735 | else |
| 736 | cs->hw.elsa.status |= 0x1000; |
| 737 | break; |
| 738 | case MDL_INFO_REL: |
| 739 | if ((long) arg) { |
| 740 | cs->hw.elsa.status &= ~0x2000; |
| 741 | cs->hw.elsa.status &= ~0x0200; |
| 742 | } else { |
| 743 | cs->hw.elsa.status &= ~0x1000; |
| 744 | cs->hw.elsa.status &= ~0x0100; |
| 745 | } |
| 746 | break; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 747 | #if ARCOFI_USE |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 748 | case CARD_AUX_IND: |
| 749 | if (cs->hw.elsa.MFlag) { |
| 750 | int len; |
| 751 | u_char *msg; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 752 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 753 | if (!arg) |
| 754 | return (0); |
| 755 | msg = arg; |
| 756 | len = *msg; |
| 757 | msg++; |
| 758 | modem_write_cmd(cs, msg, len); |
| 759 | } |
| 760 | break; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 761 | #endif |
| 762 | } |
| 763 | if (cs->typ == ISDN_CTYPE_ELSA) { |
| 764 | int pwr = bytein(cs->hw.elsa.ale); |
| 765 | if (pwr & 0x08) |
| 766 | cs->hw.elsa.status |= ELSA_BAD_PWR; |
| 767 | else |
| 768 | cs->hw.elsa.status &= ~ELSA_BAD_PWR; |
| 769 | } |
| 770 | elsa_led_handler(cs); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 771 | return (ret); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 772 | } |
| 773 | |
| 774 | static unsigned char |
| 775 | probe_elsa_adr(unsigned int adr, int typ) |
| 776 | { |
| 777 | int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 778 | pc_2 = 0, pfp_1 = 0, pfp_2 = 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 779 | |
| 780 | /* In case of the elsa pcmcia card, this region is in use, |
| 781 | reserved for us by the card manager. So we do not check it |
| 782 | here, it would fail. */ |
| 783 | if (typ != ISDN_CTYPE_ELSA_PCMCIA) { |
| 784 | if (request_region(adr, 8, "elsa card")) { |
| 785 | release_region(adr, 8); |
| 786 | } else { |
| 787 | printk(KERN_WARNING |
| 788 | "Elsa: Probing Port 0x%x: already in use\n", adr); |
| 789 | return (0); |
| 790 | } |
| 791 | } |
| 792 | for (i = 0; i < 16; i++) { |
| 793 | in1 = inb(adr + ELSA_CONFIG); /* 'toggelt' bei */ |
| 794 | in2 = inb(adr + ELSA_CONFIG); /* jedem Zugriff */ |
| 795 | p16_1 += 0x04 & in1; |
| 796 | p16_2 += 0x04 & in2; |
| 797 | p8_1 += 0x02 & in1; |
| 798 | p8_2 += 0x02 & in2; |
| 799 | pc_1 += 0x01 & in1; |
| 800 | pc_2 += 0x01 & in2; |
| 801 | pfp_1 += 0x40 & in1; |
| 802 | pfp_2 += 0x40 & in2; |
| 803 | } |
| 804 | printk(KERN_INFO "Elsa: Probing IO 0x%x", adr); |
| 805 | if (65 == ++p16_1 * ++p16_2) { |
| 806 | printk(" PCC-16/PCF found\n"); |
| 807 | return (ELSA_PCC16); |
| 808 | } else if (1025 == ++pfp_1 * ++pfp_2) { |
| 809 | printk(" PCF-Pro found\n"); |
| 810 | return (ELSA_PCFPRO); |
| 811 | } else if (33 == ++p8_1 * ++p8_2) { |
| 812 | printk(" PCC8 found\n"); |
| 813 | return (ELSA_PCC8); |
| 814 | } else if (17 == ++pc_1 * ++pc_2) { |
| 815 | printk(" PC found\n"); |
| 816 | return (ELSA_PC); |
| 817 | } else { |
| 818 | printk(" failed\n"); |
| 819 | return (0); |
| 820 | } |
| 821 | } |
| 822 | |
| 823 | static unsigned int |
| 824 | probe_elsa(struct IsdnCardState *cs) |
| 825 | { |
| 826 | int i; |
| 827 | unsigned int CARD_portlist[] = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 828 | {0x160, 0x170, 0x260, 0x360, 0}; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 829 | |
| 830 | for (i = 0; CARD_portlist[i]; i++) { |
| 831 | if ((cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ))) |
| 832 | break; |
| 833 | } |
| 834 | return (CARD_portlist[i]); |
| 835 | } |
| 836 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 837 | static int setup_elsa_isa(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 838 | { |
| 839 | struct IsdnCardState *cs = card->cs; |
| 840 | u_char val; |
| 841 | |
| 842 | cs->hw.elsa.base = card->para[0]; |
| 843 | printk(KERN_INFO "Elsa: Microlink IO probing\n"); |
| 844 | if (cs->hw.elsa.base) { |
| 845 | if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, |
| 846 | cs->typ))) { |
| 847 | printk(KERN_WARNING |
| 848 | "Elsa: no Elsa Microlink at %#lx\n", |
| 849 | cs->hw.elsa.base); |
| 850 | return (0); |
| 851 | } |
| 852 | } else |
| 853 | cs->hw.elsa.base = probe_elsa(cs); |
| 854 | |
| 855 | if (!cs->hw.elsa.base) { |
| 856 | printk(KERN_WARNING |
| 857 | "No Elsa Microlink found\n"); |
| 858 | return (0); |
| 859 | } |
| 860 | |
| 861 | cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; |
| 862 | cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; |
| 863 | cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; |
| 864 | cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; |
| 865 | cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; |
| 866 | cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; |
| 867 | cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; |
| 868 | cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; |
| 869 | val = bytein(cs->hw.elsa.cfg); |
| 870 | if (cs->subtyp == ELSA_PC) { |
| 871 | const u_char CARD_IrqTab[8] = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 872 | {7, 3, 5, 9, 0, 0, 0, 0}; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 873 | cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; |
| 874 | } else if (cs->subtyp == ELSA_PCC8) { |
| 875 | const u_char CARD_IrqTab[8] = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 876 | {7, 3, 5, 9, 0, 0, 0, 0}; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 877 | cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; |
| 878 | } else { |
| 879 | const u_char CARD_IrqTab[8] = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 880 | {15, 10, 15, 3, 11, 5, 11, 9}; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 881 | cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; |
| 882 | } |
| 883 | val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; |
| 884 | if (val < 3) |
| 885 | val |= 8; |
| 886 | val += 'A' - 3; |
| 887 | if (val == 'B' || val == 'C') |
| 888 | val ^= 1; |
Roel Kluin | df59ebc | 2007-11-05 14:50:51 -0800 | [diff] [blame] | 889 | if ((cs->subtyp == ELSA_PCFPRO) && (val == 'G')) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 890 | val = 'C'; |
| 891 | printk(KERN_INFO |
| 892 | "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", |
| 893 | Elsa_Types[cs->subtyp], |
| 894 | cs->hw.elsa.base, |
| 895 | val, cs->irq); |
| 896 | val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; |
| 897 | if (val) { |
| 898 | printk(KERN_WARNING |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 899 | "Elsa: Microlink S0 bus power bad\n"); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 900 | cs->hw.elsa.status |= ELSA_BAD_PWR; |
| 901 | } |
| 902 | |
| 903 | return (1); |
| 904 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 905 | |
| 906 | #ifdef __ISAPNP__ |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 907 | static struct isapnp_device_id elsa_ids[] = { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 908 | { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 909 | ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 910 | (unsigned long) "Elsa QS1000" }, |
| 911 | { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134), |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 912 | ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134), |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 913 | (unsigned long) "Elsa QS3000" }, |
| 914 | { 0, } |
| 915 | }; |
| 916 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 917 | static struct isapnp_device_id *ipid = &elsa_ids[0]; |
| 918 | static struct pnp_card *pnp_c = NULL; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 919 | #endif /* __ISAPNP__ */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 920 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 921 | static int setup_elsa_isapnp(struct IsdnCard *card) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 922 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 923 | struct IsdnCardState *cs = card->cs; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 924 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 925 | #ifdef __ISAPNP__ |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 926 | if (!card->para[1] && isapnp_present()) { |
| 927 | struct pnp_dev *pnp_d; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 928 | while (ipid->card_vendor) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 929 | if ((pnp_c = pnp_find_card(ipid->card_vendor, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 930 | ipid->card_device, pnp_c))) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 931 | pnp_d = NULL; |
| 932 | if ((pnp_d = pnp_find_dev(pnp_c, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 933 | ipid->vendor, ipid->function, pnp_d))) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 934 | int err; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 935 | |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 936 | printk(KERN_INFO "HiSax: %s detected\n", |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 937 | (char *)ipid->driver_data); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 938 | pnp_disable_dev(pnp_d); |
| 939 | err = pnp_activate_dev(pnp_d); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 940 | if (err < 0) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 941 | printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 942 | __func__, err); |
| 943 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 944 | } |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 945 | card->para[1] = pnp_port_start(pnp_d, 0); |
| 946 | card->para[0] = pnp_irq(pnp_d, 0); |
| 947 | |
| 948 | if (!card->para[0] || !card->para[1]) { |
| 949 | printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 950 | card->para[0], card->para[1]); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 951 | pnp_disable_dev(pnp_d); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 952 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 953 | } |
| 954 | if (ipid->function == ISAPNP_FUNCTION(0x133)) |
| 955 | cs->subtyp = ELSA_QS1000; |
| 956 | else |
| 957 | cs->subtyp = ELSA_QS3000; |
| 958 | break; |
| 959 | } else { |
| 960 | printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 961 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 962 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 963 | } |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 964 | ipid++; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 965 | pnp_c = NULL; |
| 966 | } |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 967 | if (!ipid->card_vendor) { |
| 968 | printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 969 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 970 | } |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 971 | } |
| 972 | #endif /* __ISAPNP__ */ |
| 973 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 974 | if (card->para[1] && card->para[0]) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 975 | cs->hw.elsa.base = card->para[1]; |
| 976 | cs->irq = card->para[0]; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 977 | if (!cs->subtyp) |
| 978 | cs->subtyp = ELSA_QS1000; |
| 979 | } else { |
| 980 | printk(KERN_ERR "Elsa PnP: no parameter\n"); |
| 981 | } |
| 982 | cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; |
| 983 | cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; |
| 984 | cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; |
| 985 | cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; |
| 986 | cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; |
| 987 | cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; |
| 988 | cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; |
| 989 | printk(KERN_INFO |
| 990 | "Elsa: %s defined at %#lx IRQ %d\n", |
| 991 | Elsa_Types[cs->subtyp], |
| 992 | cs->hw.elsa.base, |
| 993 | cs->irq); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 994 | |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 995 | return (1); |
| 996 | } |
| 997 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 998 | static void setup_elsa_pcmcia(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 999 | { |
| 1000 | struct IsdnCardState *cs = card->cs; |
| 1001 | u_char val; |
| 1002 | |
| 1003 | cs->hw.elsa.base = card->para[1]; |
| 1004 | cs->irq = card->para[0]; |
| 1005 | val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); |
| 1006 | if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ |
| 1007 | cs->subtyp = ELSA_PCMCIA_IPAC; |
| 1008 | cs->hw.elsa.ale = cs->hw.elsa.base + 0; |
| 1009 | cs->hw.elsa.isac = cs->hw.elsa.base + 2; |
| 1010 | cs->hw.elsa.hscx = cs->hw.elsa.base + 2; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1011 | test_and_set_bit(HW_IPAC, &cs->HW_Flags); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1012 | } else { |
| 1013 | cs->subtyp = ELSA_PCMCIA; |
| 1014 | cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; |
| 1015 | cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; |
| 1016 | cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; |
| 1017 | } |
| 1018 | cs->hw.elsa.timer = 0; |
| 1019 | cs->hw.elsa.trig = 0; |
| 1020 | cs->hw.elsa.ctrl = 0; |
| 1021 | cs->irq_flags |= IRQF_SHARED; |
| 1022 | printk(KERN_INFO |
| 1023 | "Elsa: %s defined at %#lx IRQ %d\n", |
| 1024 | Elsa_Types[cs->subtyp], |
| 1025 | cs->hw.elsa.base, |
| 1026 | cs->irq); |
| 1027 | } |
| 1028 | |
Tilman Schmidt | 41a68a7 | 2010-01-18 17:24:10 +0100 | [diff] [blame] | 1029 | #ifdef CONFIG_PCI |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 1030 | static struct pci_dev *dev_qs1000 = NULL; |
| 1031 | static struct pci_dev *dev_qs3000 = NULL; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1032 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 1033 | static int setup_elsa_pci(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1034 | { |
| 1035 | struct IsdnCardState *cs = card->cs; |
| 1036 | |
| 1037 | cs->subtyp = 0; |
Tilman Schmidt | 41a68a7 | 2010-01-18 17:24:10 +0100 | [diff] [blame] | 1038 | if ((dev_qs1000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1039 | PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1040 | if (pci_enable_device(dev_qs1000)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1041 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1042 | cs->subtyp = ELSA_QS1000PCI; |
| 1043 | cs->irq = dev_qs1000->irq; |
| 1044 | cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); |
| 1045 | cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); |
Tilman Schmidt | 41a68a7 | 2010-01-18 17:24:10 +0100 | [diff] [blame] | 1046 | } else if ((dev_qs3000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1047 | PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1048 | if (pci_enable_device(dev_qs3000)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1049 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1050 | cs->subtyp = ELSA_QS3000PCI; |
| 1051 | cs->irq = dev_qs3000->irq; |
| 1052 | cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); |
| 1053 | cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); |
| 1054 | } else { |
| 1055 | printk(KERN_WARNING "Elsa: No PCI card found\n"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1056 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1057 | } |
| 1058 | if (!cs->irq) { |
| 1059 | printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1060 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1061 | } |
| 1062 | |
| 1063 | if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { |
| 1064 | printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1065 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1066 | } |
| 1067 | if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { |
| 1068 | printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); |
| 1069 | printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); |
| 1070 | printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); |
| 1071 | } |
| 1072 | cs->hw.elsa.ale = cs->hw.elsa.base; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1073 | cs->hw.elsa.isac = cs->hw.elsa.base + 1; |
| 1074 | cs->hw.elsa.hscx = cs->hw.elsa.base + 1; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1075 | test_and_set_bit(HW_IPAC, &cs->HW_Flags); |
| 1076 | cs->hw.elsa.timer = 0; |
| 1077 | cs->hw.elsa.trig = 0; |
| 1078 | cs->irq_flags |= IRQF_SHARED; |
| 1079 | printk(KERN_INFO |
| 1080 | "Elsa: %s defined at %#lx/0x%x IRQ %d\n", |
| 1081 | Elsa_Types[cs->subtyp], |
| 1082 | cs->hw.elsa.base, |
| 1083 | cs->hw.elsa.cfg, |
| 1084 | cs->irq); |
| 1085 | |
| 1086 | return (1); |
| 1087 | } |
| 1088 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1089 | #else |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1090 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 1091 | static int setup_elsa_pci(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1092 | { |
| 1093 | return (1); |
| 1094 | } |
Tilman Schmidt | 41a68a7 | 2010-01-18 17:24:10 +0100 | [diff] [blame] | 1095 | #endif /* CONFIG_PCI */ |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1096 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 1097 | static int setup_elsa_common(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1098 | { |
| 1099 | struct IsdnCardState *cs = card->cs; |
| 1100 | u_char val; |
| 1101 | int bytecnt; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1102 | |
| 1103 | switch (cs->subtyp) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1104 | case ELSA_PC: |
| 1105 | case ELSA_PCC8: |
| 1106 | case ELSA_PCC16: |
| 1107 | case ELSA_QS1000: |
| 1108 | case ELSA_PCMCIA: |
| 1109 | case ELSA_PCMCIA_IPAC: |
| 1110 | bytecnt = 8; |
| 1111 | break; |
| 1112 | case ELSA_PCFPRO: |
| 1113 | case ELSA_PCF: |
| 1114 | case ELSA_QS3000: |
| 1115 | case ELSA_QS3000PCI: |
| 1116 | bytecnt = 16; |
| 1117 | break; |
| 1118 | case ELSA_QS1000PCI: |
| 1119 | bytecnt = 2; |
| 1120 | break; |
| 1121 | default: |
| 1122 | printk(KERN_WARNING |
| 1123 | "Unknown ELSA subtype %d\n", cs->subtyp); |
| 1124 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1125 | } |
| 1126 | /* In case of the elsa pcmcia card, this region is in use, |
| 1127 | reserved for us by the card manager. So we do not check it |
| 1128 | here, it would fail. */ |
| 1129 | if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) { |
| 1130 | printk(KERN_WARNING |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1131 | "HiSax: ELSA config port %#lx-%#lx already in use\n", |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1132 | cs->hw.elsa.base, |
| 1133 | cs->hw.elsa.base + bytecnt); |
| 1134 | return (0); |
| 1135 | } |
| 1136 | if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { |
| 1137 | if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) { |
| 1138 | printk(KERN_WARNING |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1139 | "HiSax: ELSA pci port %x-%x already in use\n", |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1140 | cs->hw.elsa.cfg, |
| 1141 | cs->hw.elsa.cfg + 0x80); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1142 | release_region(cs->hw.elsa.base, bytecnt); |
| 1143 | return (0); |
| 1144 | } |
| 1145 | } |
| 1146 | #if ARCOFI_USE |
| 1147 | init_arcofi(cs); |
| 1148 | #endif |
| 1149 | setup_isac(cs); |
| 1150 | cs->hw.elsa.tl.function = (void *) elsa_led_handler; |
| 1151 | cs->hw.elsa.tl.data = (long) cs; |
| 1152 | init_timer(&cs->hw.elsa.tl); |
| 1153 | /* Teste Timer */ |
| 1154 | if (cs->hw.elsa.timer) { |
| 1155 | byteout(cs->hw.elsa.trig, 0xff); |
| 1156 | byteout(cs->hw.elsa.timer, 0); |
| 1157 | if (!TimerRun(cs)) { |
| 1158 | byteout(cs->hw.elsa.timer, 0); /* 2. Versuch */ |
| 1159 | if (!TimerRun(cs)) { |
| 1160 | printk(KERN_WARNING |
| 1161 | "Elsa: timer do not start\n"); |
| 1162 | release_io_elsa(cs); |
| 1163 | return (0); |
| 1164 | } |
| 1165 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1166 | HZDELAY((HZ / 100) + 1); /* wait >=10 ms */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1167 | if (TimerRun(cs)) { |
| 1168 | printk(KERN_WARNING "Elsa: timer do not run down\n"); |
| 1169 | release_io_elsa(cs); |
| 1170 | return (0); |
| 1171 | } |
| 1172 | printk(KERN_INFO "Elsa: timer OK; resetting card\n"); |
| 1173 | } |
| 1174 | cs->BC_Read_Reg = &ReadHSCX; |
| 1175 | cs->BC_Write_Reg = &WriteHSCX; |
| 1176 | cs->BC_Send_Data = &hscx_fill_fifo; |
| 1177 | cs->cardmsg = &Elsa_card_msg; |
| 1178 | if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) { |
| 1179 | cs->readisac = &ReadISAC_IPAC; |
| 1180 | cs->writeisac = &WriteISAC_IPAC; |
| 1181 | cs->readisacfifo = &ReadISACfifo_IPAC; |
| 1182 | cs->writeisacfifo = &WriteISACfifo_IPAC; |
| 1183 | cs->irq_func = &elsa_interrupt_ipac; |
| 1184 | val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID); |
| 1185 | printk(KERN_INFO "Elsa: IPAC version %x\n", val); |
| 1186 | } else { |
| 1187 | cs->readisac = &ReadISAC; |
| 1188 | cs->writeisac = &WriteISAC; |
| 1189 | cs->readisacfifo = &ReadISACfifo; |
| 1190 | cs->writeisacfifo = &WriteISACfifo; |
| 1191 | cs->irq_func = &elsa_interrupt; |
| 1192 | ISACVersion(cs, "Elsa:"); |
| 1193 | if (HscxVersion(cs, "Elsa:")) { |
| 1194 | printk(KERN_WARNING |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1195 | "Elsa: wrong HSCX versions check IO address\n"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1196 | release_io_elsa(cs); |
| 1197 | return (0); |
| 1198 | } |
| 1199 | } |
| 1200 | if (cs->subtyp == ELSA_PC) { |
| 1201 | val = readitac(cs, ITAC_SYS); |
| 1202 | printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]); |
| 1203 | writeitac(cs, ITAC_ISEN, 0); |
| 1204 | writeitac(cs, ITAC_RFIE, 0); |
| 1205 | writeitac(cs, ITAC_XFIE, 0); |
| 1206 | writeitac(cs, ITAC_SCIE, 0); |
| 1207 | writeitac(cs, ITAC_STIE, 0); |
| 1208 | } |
| 1209 | return (1); |
| 1210 | } |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1211 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 1212 | int setup_elsa(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1213 | { |
| 1214 | int rc; |
| 1215 | struct IsdnCardState *cs = card->cs; |
| 1216 | char tmp[64]; |
| 1217 | |
| 1218 | strcpy(tmp, Elsa_revision); |
| 1219 | printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); |
| 1220 | cs->hw.elsa.ctrl_reg = 0; |
| 1221 | cs->hw.elsa.status = 0; |
| 1222 | cs->hw.elsa.MFlag = 0; |
| 1223 | cs->subtyp = 0; |
| 1224 | |
| 1225 | if (cs->typ == ISDN_CTYPE_ELSA) { |
| 1226 | rc = setup_elsa_isa(card); |
| 1227 | if (!rc) |
| 1228 | return (0); |
| 1229 | |
| 1230 | } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { |
| 1231 | rc = setup_elsa_isapnp(card); |
| 1232 | if (!rc) |
| 1233 | return (0); |
| 1234 | |
| 1235 | } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) |
| 1236 | setup_elsa_pcmcia(card); |
| 1237 | |
| 1238 | else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { |
| 1239 | rc = setup_elsa_pci(card); |
| 1240 | if (!rc) |
| 1241 | return (0); |
| 1242 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1243 | } else |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1244 | return (0); |
| 1245 | |
| 1246 | return setup_elsa_common(card); |
| 1247 | } |