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); |
| 512 | interruptible_sleep_on(&cs->dc.isac.arcofi_wait); |
| 513 | } |
| 514 | |
| 515 | static int |
| 516 | check_arcofi(struct IsdnCardState *cs) |
| 517 | { |
| 518 | int arcofi_present = 0; |
| 519 | char tmp[40]; |
| 520 | char *t; |
| 521 | u_char *p; |
| 522 | |
| 523 | if (!cs->dc.isac.mon_tx) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 524 | if (!(cs->dc.isac.mon_tx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 525 | if (cs->debug & L1_DEB_WARN) |
| 526 | debugl1(cs, "ISAC MON TX out of buffers!"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 527 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 528 | } |
| 529 | cs->dc.isac.arcofi_bc = 0; |
| 530 | arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION); |
| 531 | interruptible_sleep_on(&cs->dc.isac.arcofi_wait); |
| 532 | if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 533 | debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp); |
| 534 | p = cs->dc.isac.mon_rx; |
| 535 | t = tmp; |
| 536 | t += sprintf(tmp, "Arcofi data"); |
| 537 | QuickHex(t, p, cs->dc.isac.mon_rxp); |
| 538 | debugl1(cs, tmp); |
| 539 | if ((cs->dc.isac.mon_rxp == 2) && (cs->dc.isac.mon_rx[0] == 0xa0)) { |
| 540 | switch (cs->dc.isac.mon_rx[1]) { |
| 541 | case 0x80: |
| 542 | debugl1(cs, "Arcofi 2160 detected"); |
| 543 | arcofi_present = 1; |
| 544 | break; |
| 545 | case 0x82: |
| 546 | debugl1(cs, "Arcofi 2165 detected"); |
| 547 | arcofi_present = 2; |
| 548 | break; |
| 549 | case 0x84: |
| 550 | debugl1(cs, "Arcofi 2163 detected"); |
| 551 | arcofi_present = 3; |
| 552 | break; |
| 553 | default: |
| 554 | debugl1(cs, "unknown Arcofi response"); |
| 555 | break; |
| 556 | } |
| 557 | } else |
| 558 | debugl1(cs, "undefined Monitor response"); |
| 559 | cs->dc.isac.mon_rxp = 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 560 | } else if (cs->dc.isac.mon_tx) { |
| 561 | debugl1(cs, "Arcofi not detected"); |
| 562 | } |
| 563 | if (arcofi_present) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 564 | if (cs->subtyp == ELSA_QS1000) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 565 | cs->subtyp = ELSA_QS3000; |
| 566 | printk(KERN_INFO |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 567 | "Elsa: %s detected modem at 0x%lx\n", |
| 568 | Elsa_Types[cs->subtyp], |
| 569 | cs->hw.elsa.base + 8); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 570 | release_region(cs->hw.elsa.base, 8); |
| 571 | if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) { |
| 572 | printk(KERN_WARNING |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 573 | "HiSax: %s config port %lx-%lx already in use\n", |
| 574 | Elsa_Types[cs->subtyp], |
| 575 | cs->hw.elsa.base + 8, |
| 576 | cs->hw.elsa.base + 16); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 577 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 578 | } else if (cs->subtyp == ELSA_PCC16) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 579 | cs->subtyp = ELSA_PCF; |
| 580 | printk(KERN_INFO |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 581 | "Elsa: %s detected modem at 0x%lx\n", |
| 582 | Elsa_Types[cs->subtyp], |
| 583 | cs->hw.elsa.base + 8); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 584 | release_region(cs->hw.elsa.base, 8); |
| 585 | if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) { |
| 586 | printk(KERN_WARNING |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 587 | "HiSax: %s config port %lx-%lx already in use\n", |
| 588 | Elsa_Types[cs->subtyp], |
| 589 | cs->hw.elsa.base + 8, |
| 590 | cs->hw.elsa.base + 16); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 591 | } |
| 592 | } else |
| 593 | printk(KERN_INFO |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 594 | "Elsa: %s detected modem at 0x%lx\n", |
| 595 | Elsa_Types[cs->subtyp], |
| 596 | cs->hw.elsa.base + 8); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 597 | arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0); |
| 598 | interruptible_sleep_on(&cs->dc.isac.arcofi_wait); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 599 | return (1); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 600 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 601 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 602 | } |
| 603 | #endif /* ARCOFI_USE */ |
| 604 | |
| 605 | static void |
| 606 | elsa_led_handler(struct IsdnCardState *cs) |
| 607 | { |
| 608 | int blink = 0; |
| 609 | |
| 610 | if (cs->subtyp == ELSA_PCMCIA || cs->subtyp == ELSA_PCMCIA_IPAC) |
| 611 | return; |
| 612 | del_timer(&cs->hw.elsa.tl); |
| 613 | if (cs->hw.elsa.status & ELSA_ASSIGN) |
| 614 | cs->hw.elsa.ctrl_reg |= ELSA_STAT_LED; |
| 615 | else if (cs->hw.elsa.status & ELSA_BAD_PWR) |
| 616 | cs->hw.elsa.ctrl_reg &= ~ELSA_STAT_LED; |
| 617 | else { |
| 618 | cs->hw.elsa.ctrl_reg ^= ELSA_STAT_LED; |
| 619 | blink = 250; |
| 620 | } |
| 621 | if (cs->hw.elsa.status & 0xf000) |
| 622 | cs->hw.elsa.ctrl_reg |= ELSA_LINE_LED; |
| 623 | else if (cs->hw.elsa.status & 0x0f00) { |
| 624 | cs->hw.elsa.ctrl_reg ^= ELSA_LINE_LED; |
| 625 | blink = 500; |
| 626 | } else |
| 627 | cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED; |
| 628 | |
| 629 | if ((cs->subtyp == ELSA_QS1000PCI) || |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 630 | (cs->subtyp == ELSA_QS3000PCI)) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 631 | u_char led = 0xff; |
| 632 | if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED) |
| 633 | led ^= ELSA_IPAC_LINE_LED; |
| 634 | if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED) |
| 635 | led ^= ELSA_IPAC_STAT_LED; |
| 636 | writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led); |
| 637 | } else |
| 638 | byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); |
| 639 | if (blink) { |
| 640 | init_timer(&cs->hw.elsa.tl); |
| 641 | cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000); |
| 642 | add_timer(&cs->hw.elsa.tl); |
| 643 | } |
| 644 | } |
| 645 | |
| 646 | static int |
| 647 | Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) |
| 648 | { |
| 649 | int ret = 0; |
| 650 | u_long flags; |
| 651 | |
| 652 | switch (mt) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 653 | case CARD_RESET: |
| 654 | spin_lock_irqsave(&cs->lock, flags); |
| 655 | reset_elsa(cs); |
| 656 | spin_unlock_irqrestore(&cs->lock, flags); |
| 657 | return (0); |
| 658 | case CARD_RELEASE: |
| 659 | release_io_elsa(cs); |
| 660 | return (0); |
| 661 | case CARD_INIT: |
| 662 | spin_lock_irqsave(&cs->lock, flags); |
| 663 | cs->debug |= L1_DEB_IPAC; |
| 664 | reset_elsa(cs); |
| 665 | inithscxisac(cs, 1); |
| 666 | if ((cs->subtyp == ELSA_QS1000) || |
| 667 | (cs->subtyp == ELSA_QS3000)) |
| 668 | { |
| 669 | byteout(cs->hw.elsa.timer, 0); |
| 670 | } |
| 671 | if (cs->hw.elsa.trig) |
| 672 | byteout(cs->hw.elsa.trig, 0xff); |
| 673 | inithscxisac(cs, 2); |
| 674 | spin_unlock_irqrestore(&cs->lock, flags); |
| 675 | return (0); |
| 676 | case CARD_TEST: |
| 677 | if ((cs->subtyp == ELSA_PCMCIA) || |
| 678 | (cs->subtyp == ELSA_PCMCIA_IPAC) || |
| 679 | (cs->subtyp == ELSA_QS1000PCI)) { |
| 680 | return (0); |
| 681 | } else if (cs->subtyp == ELSA_QS3000PCI) { |
| 682 | ret = 0; |
| 683 | } else { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 684 | spin_lock_irqsave(&cs->lock, flags); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 685 | cs->hw.elsa.counter = 0; |
| 686 | cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT; |
| 687 | cs->hw.elsa.status |= ELIRQF_TIMER_AKTIV; |
| 688 | byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); |
| 689 | byteout(cs->hw.elsa.timer, 0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 690 | spin_unlock_irqrestore(&cs->lock, flags); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 691 | msleep(110); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 692 | spin_lock_irqsave(&cs->lock, flags); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 693 | cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; |
| 694 | byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); |
| 695 | cs->hw.elsa.status &= ~ELIRQF_TIMER_AKTIV; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 696 | spin_unlock_irqrestore(&cs->lock, flags); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 697 | printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", |
| 698 | cs->hw.elsa.counter); |
| 699 | if ((cs->hw.elsa.counter > 10) && |
| 700 | (cs->hw.elsa.counter < 16)) { |
| 701 | printk(KERN_INFO "Elsa: timer and irq OK\n"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 702 | ret = 0; |
| 703 | } else { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 704 | printk(KERN_WARNING |
| 705 | "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n", |
| 706 | cs->hw.elsa.counter, cs->irq); |
| 707 | ret = 1; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 708 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 709 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 710 | #if ARCOFI_USE |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 711 | if (check_arcofi(cs)) { |
| 712 | init_modem(cs); |
| 713 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 714 | #endif |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 715 | elsa_led_handler(cs); |
| 716 | return (ret); |
| 717 | case (MDL_REMOVE | REQUEST): |
| 718 | cs->hw.elsa.status &= 0; |
| 719 | break; |
| 720 | case (MDL_ASSIGN | REQUEST): |
| 721 | cs->hw.elsa.status |= ELSA_ASSIGN; |
| 722 | break; |
| 723 | case MDL_INFO_SETUP: |
| 724 | if ((long) arg) |
| 725 | cs->hw.elsa.status |= 0x0200; |
| 726 | else |
| 727 | cs->hw.elsa.status |= 0x0100; |
| 728 | break; |
| 729 | case MDL_INFO_CONN: |
| 730 | if ((long) arg) |
| 731 | cs->hw.elsa.status |= 0x2000; |
| 732 | else |
| 733 | cs->hw.elsa.status |= 0x1000; |
| 734 | break; |
| 735 | case MDL_INFO_REL: |
| 736 | if ((long) arg) { |
| 737 | cs->hw.elsa.status &= ~0x2000; |
| 738 | cs->hw.elsa.status &= ~0x0200; |
| 739 | } else { |
| 740 | cs->hw.elsa.status &= ~0x1000; |
| 741 | cs->hw.elsa.status &= ~0x0100; |
| 742 | } |
| 743 | break; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 744 | #if ARCOFI_USE |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 745 | case CARD_AUX_IND: |
| 746 | if (cs->hw.elsa.MFlag) { |
| 747 | int len; |
| 748 | u_char *msg; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 749 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 750 | if (!arg) |
| 751 | return (0); |
| 752 | msg = arg; |
| 753 | len = *msg; |
| 754 | msg++; |
| 755 | modem_write_cmd(cs, msg, len); |
| 756 | } |
| 757 | break; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 758 | #endif |
| 759 | } |
| 760 | if (cs->typ == ISDN_CTYPE_ELSA) { |
| 761 | int pwr = bytein(cs->hw.elsa.ale); |
| 762 | if (pwr & 0x08) |
| 763 | cs->hw.elsa.status |= ELSA_BAD_PWR; |
| 764 | else |
| 765 | cs->hw.elsa.status &= ~ELSA_BAD_PWR; |
| 766 | } |
| 767 | elsa_led_handler(cs); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 768 | return (ret); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 769 | } |
| 770 | |
| 771 | static unsigned char |
| 772 | probe_elsa_adr(unsigned int adr, int typ) |
| 773 | { |
| 774 | 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] | 775 | pc_2 = 0, pfp_1 = 0, pfp_2 = 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 776 | |
| 777 | /* In case of the elsa pcmcia card, this region is in use, |
| 778 | reserved for us by the card manager. So we do not check it |
| 779 | here, it would fail. */ |
| 780 | if (typ != ISDN_CTYPE_ELSA_PCMCIA) { |
| 781 | if (request_region(adr, 8, "elsa card")) { |
| 782 | release_region(adr, 8); |
| 783 | } else { |
| 784 | printk(KERN_WARNING |
| 785 | "Elsa: Probing Port 0x%x: already in use\n", adr); |
| 786 | return (0); |
| 787 | } |
| 788 | } |
| 789 | for (i = 0; i < 16; i++) { |
| 790 | in1 = inb(adr + ELSA_CONFIG); /* 'toggelt' bei */ |
| 791 | in2 = inb(adr + ELSA_CONFIG); /* jedem Zugriff */ |
| 792 | p16_1 += 0x04 & in1; |
| 793 | p16_2 += 0x04 & in2; |
| 794 | p8_1 += 0x02 & in1; |
| 795 | p8_2 += 0x02 & in2; |
| 796 | pc_1 += 0x01 & in1; |
| 797 | pc_2 += 0x01 & in2; |
| 798 | pfp_1 += 0x40 & in1; |
| 799 | pfp_2 += 0x40 & in2; |
| 800 | } |
| 801 | printk(KERN_INFO "Elsa: Probing IO 0x%x", adr); |
| 802 | if (65 == ++p16_1 * ++p16_2) { |
| 803 | printk(" PCC-16/PCF found\n"); |
| 804 | return (ELSA_PCC16); |
| 805 | } else if (1025 == ++pfp_1 * ++pfp_2) { |
| 806 | printk(" PCF-Pro found\n"); |
| 807 | return (ELSA_PCFPRO); |
| 808 | } else if (33 == ++p8_1 * ++p8_2) { |
| 809 | printk(" PCC8 found\n"); |
| 810 | return (ELSA_PCC8); |
| 811 | } else if (17 == ++pc_1 * ++pc_2) { |
| 812 | printk(" PC found\n"); |
| 813 | return (ELSA_PC); |
| 814 | } else { |
| 815 | printk(" failed\n"); |
| 816 | return (0); |
| 817 | } |
| 818 | } |
| 819 | |
| 820 | static unsigned int |
| 821 | probe_elsa(struct IsdnCardState *cs) |
| 822 | { |
| 823 | int i; |
| 824 | unsigned int CARD_portlist[] = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 825 | {0x160, 0x170, 0x260, 0x360, 0}; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 826 | |
| 827 | for (i = 0; CARD_portlist[i]; i++) { |
| 828 | if ((cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ))) |
| 829 | break; |
| 830 | } |
| 831 | return (CARD_portlist[i]); |
| 832 | } |
| 833 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 834 | static int setup_elsa_isa(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 835 | { |
| 836 | struct IsdnCardState *cs = card->cs; |
| 837 | u_char val; |
| 838 | |
| 839 | cs->hw.elsa.base = card->para[0]; |
| 840 | printk(KERN_INFO "Elsa: Microlink IO probing\n"); |
| 841 | if (cs->hw.elsa.base) { |
| 842 | if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, |
| 843 | cs->typ))) { |
| 844 | printk(KERN_WARNING |
| 845 | "Elsa: no Elsa Microlink at %#lx\n", |
| 846 | cs->hw.elsa.base); |
| 847 | return (0); |
| 848 | } |
| 849 | } else |
| 850 | cs->hw.elsa.base = probe_elsa(cs); |
| 851 | |
| 852 | if (!cs->hw.elsa.base) { |
| 853 | printk(KERN_WARNING |
| 854 | "No Elsa Microlink found\n"); |
| 855 | return (0); |
| 856 | } |
| 857 | |
| 858 | cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; |
| 859 | cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; |
| 860 | cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; |
| 861 | cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; |
| 862 | cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; |
| 863 | cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; |
| 864 | cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; |
| 865 | cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; |
| 866 | val = bytein(cs->hw.elsa.cfg); |
| 867 | if (cs->subtyp == ELSA_PC) { |
| 868 | const u_char CARD_IrqTab[8] = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 869 | {7, 3, 5, 9, 0, 0, 0, 0}; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 870 | cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; |
| 871 | } else if (cs->subtyp == ELSA_PCC8) { |
| 872 | const u_char CARD_IrqTab[8] = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 873 | {7, 3, 5, 9, 0, 0, 0, 0}; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 874 | cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; |
| 875 | } else { |
| 876 | const u_char CARD_IrqTab[8] = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 877 | {15, 10, 15, 3, 11, 5, 11, 9}; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 878 | cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; |
| 879 | } |
| 880 | val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; |
| 881 | if (val < 3) |
| 882 | val |= 8; |
| 883 | val += 'A' - 3; |
| 884 | if (val == 'B' || val == 'C') |
| 885 | val ^= 1; |
Roel Kluin | df59ebc | 2007-11-05 14:50:51 -0800 | [diff] [blame] | 886 | if ((cs->subtyp == ELSA_PCFPRO) && (val == 'G')) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 887 | val = 'C'; |
| 888 | printk(KERN_INFO |
| 889 | "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", |
| 890 | Elsa_Types[cs->subtyp], |
| 891 | cs->hw.elsa.base, |
| 892 | val, cs->irq); |
| 893 | val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; |
| 894 | if (val) { |
| 895 | printk(KERN_WARNING |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 896 | "Elsa: Microlink S0 bus power bad\n"); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 897 | cs->hw.elsa.status |= ELSA_BAD_PWR; |
| 898 | } |
| 899 | |
| 900 | return (1); |
| 901 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 902 | |
| 903 | #ifdef __ISAPNP__ |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 904 | static struct isapnp_device_id elsa_ids[] = { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 905 | { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 906 | ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 907 | (unsigned long) "Elsa QS1000" }, |
| 908 | { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134), |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 909 | ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134), |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 910 | (unsigned long) "Elsa QS3000" }, |
| 911 | { 0, } |
| 912 | }; |
| 913 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 914 | static struct isapnp_device_id *ipid = &elsa_ids[0]; |
| 915 | static struct pnp_card *pnp_c = NULL; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 916 | #endif /* __ISAPNP__ */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 917 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 918 | static int setup_elsa_isapnp(struct IsdnCard *card) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 919 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 920 | struct IsdnCardState *cs = card->cs; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 921 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 922 | #ifdef __ISAPNP__ |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 923 | if (!card->para[1] && isapnp_present()) { |
| 924 | struct pnp_dev *pnp_d; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 925 | while (ipid->card_vendor) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 926 | if ((pnp_c = pnp_find_card(ipid->card_vendor, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 927 | ipid->card_device, pnp_c))) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 928 | pnp_d = NULL; |
| 929 | if ((pnp_d = pnp_find_dev(pnp_c, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 930 | ipid->vendor, ipid->function, pnp_d))) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 931 | int err; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 932 | |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 933 | printk(KERN_INFO "HiSax: %s detected\n", |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 934 | (char *)ipid->driver_data); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 935 | pnp_disable_dev(pnp_d); |
| 936 | err = pnp_activate_dev(pnp_d); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 937 | if (err < 0) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 938 | printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 939 | __func__, err); |
| 940 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 941 | } |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 942 | card->para[1] = pnp_port_start(pnp_d, 0); |
| 943 | card->para[0] = pnp_irq(pnp_d, 0); |
| 944 | |
| 945 | if (!card->para[0] || !card->para[1]) { |
| 946 | printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 947 | card->para[0], card->para[1]); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 948 | pnp_disable_dev(pnp_d); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 949 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 950 | } |
| 951 | if (ipid->function == ISAPNP_FUNCTION(0x133)) |
| 952 | cs->subtyp = ELSA_QS1000; |
| 953 | else |
| 954 | cs->subtyp = ELSA_QS3000; |
| 955 | break; |
| 956 | } else { |
| 957 | printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 958 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 959 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 960 | } |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 961 | ipid++; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 962 | pnp_c = NULL; |
| 963 | } |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 964 | if (!ipid->card_vendor) { |
| 965 | printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 966 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 967 | } |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 968 | } |
| 969 | #endif /* __ISAPNP__ */ |
| 970 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 971 | if (card->para[1] && card->para[0]) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 972 | cs->hw.elsa.base = card->para[1]; |
| 973 | cs->irq = card->para[0]; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 974 | if (!cs->subtyp) |
| 975 | cs->subtyp = ELSA_QS1000; |
| 976 | } else { |
| 977 | printk(KERN_ERR "Elsa PnP: no parameter\n"); |
| 978 | } |
| 979 | cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; |
| 980 | cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; |
| 981 | cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; |
| 982 | cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; |
| 983 | cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; |
| 984 | cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; |
| 985 | cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; |
| 986 | printk(KERN_INFO |
| 987 | "Elsa: %s defined at %#lx IRQ %d\n", |
| 988 | Elsa_Types[cs->subtyp], |
| 989 | cs->hw.elsa.base, |
| 990 | cs->irq); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 991 | |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 992 | return (1); |
| 993 | } |
| 994 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 995 | static void setup_elsa_pcmcia(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 996 | { |
| 997 | struct IsdnCardState *cs = card->cs; |
| 998 | u_char val; |
| 999 | |
| 1000 | cs->hw.elsa.base = card->para[1]; |
| 1001 | cs->irq = card->para[0]; |
| 1002 | val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); |
| 1003 | if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ |
| 1004 | cs->subtyp = ELSA_PCMCIA_IPAC; |
| 1005 | cs->hw.elsa.ale = cs->hw.elsa.base + 0; |
| 1006 | cs->hw.elsa.isac = cs->hw.elsa.base + 2; |
| 1007 | cs->hw.elsa.hscx = cs->hw.elsa.base + 2; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1008 | test_and_set_bit(HW_IPAC, &cs->HW_Flags); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1009 | } else { |
| 1010 | cs->subtyp = ELSA_PCMCIA; |
| 1011 | cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; |
| 1012 | cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; |
| 1013 | cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; |
| 1014 | } |
| 1015 | cs->hw.elsa.timer = 0; |
| 1016 | cs->hw.elsa.trig = 0; |
| 1017 | cs->hw.elsa.ctrl = 0; |
| 1018 | cs->irq_flags |= IRQF_SHARED; |
| 1019 | printk(KERN_INFO |
| 1020 | "Elsa: %s defined at %#lx IRQ %d\n", |
| 1021 | Elsa_Types[cs->subtyp], |
| 1022 | cs->hw.elsa.base, |
| 1023 | cs->irq); |
| 1024 | } |
| 1025 | |
Tilman Schmidt | 41a68a7 | 2010-01-18 17:24:10 +0100 | [diff] [blame] | 1026 | #ifdef CONFIG_PCI |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 1027 | static struct pci_dev *dev_qs1000 = NULL; |
| 1028 | static struct pci_dev *dev_qs3000 = NULL; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1029 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 1030 | static int setup_elsa_pci(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1031 | { |
| 1032 | struct IsdnCardState *cs = card->cs; |
| 1033 | |
| 1034 | cs->subtyp = 0; |
Tilman Schmidt | 41a68a7 | 2010-01-18 17:24:10 +0100 | [diff] [blame] | 1035 | if ((dev_qs1000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1036 | PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1037 | if (pci_enable_device(dev_qs1000)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1038 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1039 | cs->subtyp = ELSA_QS1000PCI; |
| 1040 | cs->irq = dev_qs1000->irq; |
| 1041 | cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); |
| 1042 | cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); |
Tilman Schmidt | 41a68a7 | 2010-01-18 17:24:10 +0100 | [diff] [blame] | 1043 | } else if ((dev_qs3000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1044 | PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1045 | if (pci_enable_device(dev_qs3000)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1046 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1047 | cs->subtyp = ELSA_QS3000PCI; |
| 1048 | cs->irq = dev_qs3000->irq; |
| 1049 | cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); |
| 1050 | cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); |
| 1051 | } else { |
| 1052 | printk(KERN_WARNING "Elsa: No PCI card found\n"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1053 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1054 | } |
| 1055 | if (!cs->irq) { |
| 1056 | printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1057 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1058 | } |
| 1059 | |
| 1060 | if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { |
| 1061 | printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1062 | return (0); |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1063 | } |
| 1064 | if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { |
| 1065 | printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); |
| 1066 | printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); |
| 1067 | printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); |
| 1068 | } |
| 1069 | cs->hw.elsa.ale = cs->hw.elsa.base; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1070 | cs->hw.elsa.isac = cs->hw.elsa.base + 1; |
| 1071 | cs->hw.elsa.hscx = cs->hw.elsa.base + 1; |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1072 | test_and_set_bit(HW_IPAC, &cs->HW_Flags); |
| 1073 | cs->hw.elsa.timer = 0; |
| 1074 | cs->hw.elsa.trig = 0; |
| 1075 | cs->irq_flags |= IRQF_SHARED; |
| 1076 | printk(KERN_INFO |
| 1077 | "Elsa: %s defined at %#lx/0x%x IRQ %d\n", |
| 1078 | Elsa_Types[cs->subtyp], |
| 1079 | cs->hw.elsa.base, |
| 1080 | cs->hw.elsa.cfg, |
| 1081 | cs->irq); |
| 1082 | |
| 1083 | return (1); |
| 1084 | } |
| 1085 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1086 | #else |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1087 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 1088 | static int setup_elsa_pci(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1089 | { |
| 1090 | return (1); |
| 1091 | } |
Tilman Schmidt | 41a68a7 | 2010-01-18 17:24:10 +0100 | [diff] [blame] | 1092 | #endif /* CONFIG_PCI */ |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1093 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 1094 | static int setup_elsa_common(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1095 | { |
| 1096 | struct IsdnCardState *cs = card->cs; |
| 1097 | u_char val; |
| 1098 | int bytecnt; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1099 | |
| 1100 | switch (cs->subtyp) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1101 | case ELSA_PC: |
| 1102 | case ELSA_PCC8: |
| 1103 | case ELSA_PCC16: |
| 1104 | case ELSA_QS1000: |
| 1105 | case ELSA_PCMCIA: |
| 1106 | case ELSA_PCMCIA_IPAC: |
| 1107 | bytecnt = 8; |
| 1108 | break; |
| 1109 | case ELSA_PCFPRO: |
| 1110 | case ELSA_PCF: |
| 1111 | case ELSA_QS3000: |
| 1112 | case ELSA_QS3000PCI: |
| 1113 | bytecnt = 16; |
| 1114 | break; |
| 1115 | case ELSA_QS1000PCI: |
| 1116 | bytecnt = 2; |
| 1117 | break; |
| 1118 | default: |
| 1119 | printk(KERN_WARNING |
| 1120 | "Unknown ELSA subtype %d\n", cs->subtyp); |
| 1121 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1122 | } |
| 1123 | /* In case of the elsa pcmcia card, this region is in use, |
| 1124 | reserved for us by the card manager. So we do not check it |
| 1125 | here, it would fail. */ |
| 1126 | if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) { |
| 1127 | printk(KERN_WARNING |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1128 | "HiSax: ELSA config port %#lx-%#lx already in use\n", |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1129 | cs->hw.elsa.base, |
| 1130 | cs->hw.elsa.base + bytecnt); |
| 1131 | return (0); |
| 1132 | } |
| 1133 | if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { |
| 1134 | if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) { |
| 1135 | printk(KERN_WARNING |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1136 | "HiSax: ELSA pci port %x-%x already in use\n", |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1137 | cs->hw.elsa.cfg, |
| 1138 | cs->hw.elsa.cfg + 0x80); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1139 | release_region(cs->hw.elsa.base, bytecnt); |
| 1140 | return (0); |
| 1141 | } |
| 1142 | } |
| 1143 | #if ARCOFI_USE |
| 1144 | init_arcofi(cs); |
| 1145 | #endif |
| 1146 | setup_isac(cs); |
| 1147 | cs->hw.elsa.tl.function = (void *) elsa_led_handler; |
| 1148 | cs->hw.elsa.tl.data = (long) cs; |
| 1149 | init_timer(&cs->hw.elsa.tl); |
| 1150 | /* Teste Timer */ |
| 1151 | if (cs->hw.elsa.timer) { |
| 1152 | byteout(cs->hw.elsa.trig, 0xff); |
| 1153 | byteout(cs->hw.elsa.timer, 0); |
| 1154 | if (!TimerRun(cs)) { |
| 1155 | byteout(cs->hw.elsa.timer, 0); /* 2. Versuch */ |
| 1156 | if (!TimerRun(cs)) { |
| 1157 | printk(KERN_WARNING |
| 1158 | "Elsa: timer do not start\n"); |
| 1159 | release_io_elsa(cs); |
| 1160 | return (0); |
| 1161 | } |
| 1162 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1163 | HZDELAY((HZ / 100) + 1); /* wait >=10 ms */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1164 | if (TimerRun(cs)) { |
| 1165 | printk(KERN_WARNING "Elsa: timer do not run down\n"); |
| 1166 | release_io_elsa(cs); |
| 1167 | return (0); |
| 1168 | } |
| 1169 | printk(KERN_INFO "Elsa: timer OK; resetting card\n"); |
| 1170 | } |
| 1171 | cs->BC_Read_Reg = &ReadHSCX; |
| 1172 | cs->BC_Write_Reg = &WriteHSCX; |
| 1173 | cs->BC_Send_Data = &hscx_fill_fifo; |
| 1174 | cs->cardmsg = &Elsa_card_msg; |
| 1175 | if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) { |
| 1176 | cs->readisac = &ReadISAC_IPAC; |
| 1177 | cs->writeisac = &WriteISAC_IPAC; |
| 1178 | cs->readisacfifo = &ReadISACfifo_IPAC; |
| 1179 | cs->writeisacfifo = &WriteISACfifo_IPAC; |
| 1180 | cs->irq_func = &elsa_interrupt_ipac; |
| 1181 | val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID); |
| 1182 | printk(KERN_INFO "Elsa: IPAC version %x\n", val); |
| 1183 | } else { |
| 1184 | cs->readisac = &ReadISAC; |
| 1185 | cs->writeisac = &WriteISAC; |
| 1186 | cs->readisacfifo = &ReadISACfifo; |
| 1187 | cs->writeisacfifo = &WriteISACfifo; |
| 1188 | cs->irq_func = &elsa_interrupt; |
| 1189 | ISACVersion(cs, "Elsa:"); |
| 1190 | if (HscxVersion(cs, "Elsa:")) { |
| 1191 | printk(KERN_WARNING |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1192 | "Elsa: wrong HSCX versions check IO address\n"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1193 | release_io_elsa(cs); |
| 1194 | return (0); |
| 1195 | } |
| 1196 | } |
| 1197 | if (cs->subtyp == ELSA_PC) { |
| 1198 | val = readitac(cs, ITAC_SYS); |
| 1199 | printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]); |
| 1200 | writeitac(cs, ITAC_ISEN, 0); |
| 1201 | writeitac(cs, ITAC_RFIE, 0); |
| 1202 | writeitac(cs, ITAC_XFIE, 0); |
| 1203 | writeitac(cs, ITAC_SCIE, 0); |
| 1204 | writeitac(cs, ITAC_STIE, 0); |
| 1205 | } |
| 1206 | return (1); |
| 1207 | } |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1208 | |
Greg Kroah-Hartman | ed5a84c | 2012-12-21 13:13:05 -0800 | [diff] [blame] | 1209 | int setup_elsa(struct IsdnCard *card) |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1210 | { |
| 1211 | int rc; |
| 1212 | struct IsdnCardState *cs = card->cs; |
| 1213 | char tmp[64]; |
| 1214 | |
| 1215 | strcpy(tmp, Elsa_revision); |
| 1216 | printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); |
| 1217 | cs->hw.elsa.ctrl_reg = 0; |
| 1218 | cs->hw.elsa.status = 0; |
| 1219 | cs->hw.elsa.MFlag = 0; |
| 1220 | cs->subtyp = 0; |
| 1221 | |
| 1222 | if (cs->typ == ISDN_CTYPE_ELSA) { |
| 1223 | rc = setup_elsa_isa(card); |
| 1224 | if (!rc) |
| 1225 | return (0); |
| 1226 | |
| 1227 | } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { |
| 1228 | rc = setup_elsa_isapnp(card); |
| 1229 | if (!rc) |
| 1230 | return (0); |
| 1231 | |
| 1232 | } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) |
| 1233 | setup_elsa_pcmcia(card); |
| 1234 | |
| 1235 | else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { |
| 1236 | rc = setup_elsa_pci(card); |
| 1237 | if (!rc) |
| 1238 | return (0); |
| 1239 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1240 | } else |
Jeff Garzik | 1e5d82e | 2007-10-03 15:27:22 -0400 | [diff] [blame] | 1241 | return (0); |
| 1242 | |
| 1243 | return setup_elsa_common(card); |
| 1244 | } |