| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* $Id: avm_pci.c,v 1.29.2.4 2004/02/11 13:21:32 keil Exp $ | 
 | 2 |  * | 
 | 3 |  * low level stuff for AVM Fritz!PCI and ISA PnP isdn cards | 
 | 4 |  * | 
 | 5 |  * Author       Karsten Keil | 
 | 6 |  * Copyright    by Karsten Keil      <keil@isdn4linux.de> | 
 | 7 |  * | 
 | 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 |  * Thanks to AVM, Berlin for information | 
 | 12 |  * | 
 | 13 |  */ | 
 | 14 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | #include <linux/init.h> | 
 | 16 | #include "hisax.h" | 
 | 17 | #include "isac.h" | 
 | 18 | #include "isdnl1.h" | 
 | 19 | #include <linux/pci.h> | 
 | 20 | #include <linux/isapnp.h> | 
 | 21 | #include <linux/interrupt.h> | 
 | 22 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 | static const char *avm_pci_rev = "$Revision: 1.29.2.4 $"; | 
 | 24 |  | 
 | 25 | #define  AVM_FRITZ_PCI		1 | 
 | 26 | #define  AVM_FRITZ_PNP		2 | 
 | 27 |  | 
 | 28 | #define  HDLC_FIFO		0x0 | 
 | 29 | #define  HDLC_STATUS		0x4 | 
 | 30 |  | 
 | 31 | #define	 AVM_HDLC_1		0x00 | 
 | 32 | #define	 AVM_HDLC_2		0x01 | 
 | 33 | #define	 AVM_ISAC_FIFO		0x02 | 
 | 34 | #define	 AVM_ISAC_REG_LOW	0x04 | 
 | 35 | #define	 AVM_ISAC_REG_HIGH	0x06 | 
 | 36 |  | 
 | 37 | #define  AVM_STATUS0_IRQ_ISAC	0x01 | 
 | 38 | #define  AVM_STATUS0_IRQ_HDLC	0x02 | 
 | 39 | #define  AVM_STATUS0_IRQ_TIMER	0x04 | 
 | 40 | #define  AVM_STATUS0_IRQ_MASK	0x07 | 
 | 41 |  | 
 | 42 | #define  AVM_STATUS0_RESET	0x01 | 
 | 43 | #define  AVM_STATUS0_DIS_TIMER	0x02 | 
 | 44 | #define  AVM_STATUS0_RES_TIMER	0x04 | 
 | 45 | #define  AVM_STATUS0_ENA_IRQ	0x08 | 
 | 46 | #define  AVM_STATUS0_TESTBIT	0x10 | 
 | 47 |  | 
 | 48 | #define  AVM_STATUS1_INT_SEL	0x0f | 
 | 49 | #define  AVM_STATUS1_ENA_IOM	0x80 | 
 | 50 |  | 
 | 51 | #define  HDLC_MODE_ITF_FLG	0x01 | 
 | 52 | #define  HDLC_MODE_TRANS	0x02 | 
 | 53 | #define  HDLC_MODE_CCR_7	0x04 | 
 | 54 | #define  HDLC_MODE_CCR_16	0x08 | 
 | 55 | #define  HDLC_MODE_TESTLOOP	0x80 | 
 | 56 |  | 
 | 57 | #define  HDLC_INT_XPR		0x80 | 
 | 58 | #define  HDLC_INT_XDU		0x40 | 
 | 59 | #define  HDLC_INT_RPR		0x20 | 
 | 60 | #define  HDLC_INT_MASK		0xE0 | 
 | 61 |  | 
 | 62 | #define  HDLC_STAT_RME		0x01 | 
 | 63 | #define  HDLC_STAT_RDO		0x10 | 
 | 64 | #define  HDLC_STAT_CRCVFRRAB	0x0E | 
 | 65 | #define  HDLC_STAT_CRCVFR	0x06 | 
 | 66 | #define  HDLC_STAT_RML_MASK	0x3f00 | 
 | 67 |  | 
 | 68 | #define  HDLC_CMD_XRS		0x80 | 
 | 69 | #define  HDLC_CMD_XME		0x01 | 
 | 70 | #define  HDLC_CMD_RRS		0x20 | 
 | 71 | #define  HDLC_CMD_XML_MASK	0x3f00 | 
 | 72 |  | 
 | 73 |  | 
 | 74 | /* Interface functions */ | 
 | 75 |  | 
 | 76 | static u_char | 
 | 77 | ReadISAC(struct IsdnCardState *cs, u_char offset) | 
 | 78 | { | 
 | 79 | 	register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; | 
 | 80 | 	register u_char val; | 
 | 81 |  | 
 | 82 | 	outb(idx, cs->hw.avm.cfg_reg + 4); | 
 | 83 | 	val = inb(cs->hw.avm.isac + (offset & 0xf)); | 
 | 84 | 	return (val); | 
 | 85 | } | 
 | 86 |  | 
 | 87 | static void | 
 | 88 | WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) | 
 | 89 | { | 
 | 90 | 	register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; | 
 | 91 |  | 
 | 92 | 	outb(idx, cs->hw.avm.cfg_reg + 4); | 
 | 93 | 	outb(value, cs->hw.avm.isac + (offset & 0xf)); | 
 | 94 | } | 
 | 95 |  | 
 | 96 | static void | 
 | 97 | ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) | 
 | 98 | { | 
 | 99 | 	outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4); | 
 | 100 | 	insb(cs->hw.avm.isac, data, size); | 
 | 101 | } | 
 | 102 |  | 
 | 103 | static void | 
 | 104 | WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) | 
 | 105 | { | 
 | 106 | 	outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4); | 
 | 107 | 	outsb(cs->hw.avm.isac, data, size); | 
 | 108 | } | 
 | 109 |  | 
 | 110 | static inline u_int | 
 | 111 | ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset) | 
 | 112 | { | 
 | 113 | 	register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; | 
 | 114 | 	register u_int val; | 
 | 115 |  | 
 | 116 | 	outl(idx, cs->hw.avm.cfg_reg + 4); | 
 | 117 | 	val = inl(cs->hw.avm.isac + offset); | 
 | 118 | 	return (val); | 
 | 119 | } | 
 | 120 |  | 
 | 121 | static inline void | 
 | 122 | WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value) | 
 | 123 | { | 
 | 124 | 	register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; | 
 | 125 |  | 
 | 126 | 	outl(idx, cs->hw.avm.cfg_reg + 4); | 
 | 127 | 	outl(value, cs->hw.avm.isac + offset); | 
 | 128 | } | 
 | 129 |  | 
 | 130 | static inline u_char | 
 | 131 | ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset) | 
 | 132 | { | 
 | 133 | 	register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; | 
 | 134 | 	register u_char val; | 
 | 135 |  | 
 | 136 | 	outb(idx, cs->hw.avm.cfg_reg + 4); | 
 | 137 | 	val = inb(cs->hw.avm.isac + offset); | 
 | 138 | 	return (val); | 
 | 139 | } | 
 | 140 |  | 
 | 141 | static inline void | 
 | 142 | WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value) | 
 | 143 | { | 
 | 144 | 	register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; | 
 | 145 |  | 
 | 146 | 	outb(idx, cs->hw.avm.cfg_reg + 4); | 
 | 147 | 	outb(value, cs->hw.avm.isac + offset); | 
 | 148 | } | 
 | 149 |  | 
 | 150 | static u_char | 
 | 151 | ReadHDLC_s(struct IsdnCardState *cs, int chan, u_char offset) | 
 | 152 | { | 
 | 153 | 	return(0xff & ReadHDLCPCI(cs, chan, offset)); | 
 | 154 | } | 
 | 155 |  | 
 | 156 | static void | 
 | 157 | WriteHDLC_s(struct IsdnCardState *cs, int chan, u_char offset, u_char value) | 
 | 158 | { | 
 | 159 | 	WriteHDLCPCI(cs, chan, offset, value); | 
 | 160 | } | 
 | 161 |  | 
 | 162 | static inline | 
 | 163 | struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel) | 
 | 164 | { | 
 | 165 | 	if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) | 
 | 166 | 		return(&cs->bcs[0]); | 
 | 167 | 	else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) | 
 | 168 | 		return(&cs->bcs[1]); | 
 | 169 | 	else | 
 | 170 | 		return(NULL); | 
 | 171 | } | 
 | 172 |  | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 173 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 174 | write_ctrl(struct BCState *bcs, int which) { | 
 | 175 |  | 
 | 176 | 	if (bcs->cs->debug & L1_DEB_HSCX) | 
 | 177 | 		debugl1(bcs->cs, "hdlc %c wr%x ctrl %x", | 
 | 178 | 			'A' + bcs->channel, which, bcs->hw.hdlc.ctrl.ctrl); | 
 | 179 | 	if (bcs->cs->subtyp == AVM_FRITZ_PCI) { | 
 | 180 | 		WriteHDLCPCI(bcs->cs, bcs->channel, HDLC_STATUS, bcs->hw.hdlc.ctrl.ctrl); | 
 | 181 | 	} else { | 
 | 182 | 		if (which & 4) | 
 | 183 | 			WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 2, | 
 | 184 | 				bcs->hw.hdlc.ctrl.sr.mode); | 
 | 185 | 		if (which & 2) | 
 | 186 | 			WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 1, | 
 | 187 | 				bcs->hw.hdlc.ctrl.sr.xml); | 
 | 188 | 		if (which & 1) | 
 | 189 | 			WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS, | 
 | 190 | 				bcs->hw.hdlc.ctrl.sr.cmd); | 
 | 191 | 	} | 
 | 192 | } | 
 | 193 |  | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 194 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 195 | modehdlc(struct BCState *bcs, int mode, int bc) | 
 | 196 | { | 
 | 197 | 	struct IsdnCardState *cs = bcs->cs; | 
 | 198 | 	int hdlc = bcs->channel; | 
 | 199 |  | 
 | 200 | 	if (cs->debug & L1_DEB_HSCX) | 
 | 201 | 		debugl1(cs, "hdlc %c mode %d --> %d ichan %d --> %d", | 
 | 202 | 			'A' + hdlc, bcs->mode, mode, hdlc, bc); | 
 | 203 | 	bcs->hw.hdlc.ctrl.ctrl = 0; | 
 | 204 | 	switch (mode) { | 
 | 205 | 		case (-1): /* used for init */ | 
 | 206 | 			bcs->mode = 1; | 
 | 207 | 			bcs->channel = bc; | 
 | 208 | 			bc = 0; | 
 | 209 | 		case (L1_MODE_NULL): | 
 | 210 | 			if (bcs->mode == L1_MODE_NULL) | 
 | 211 | 				return; | 
 | 212 | 			bcs->hw.hdlc.ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS; | 
 | 213 | 			bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS; | 
 | 214 | 			write_ctrl(bcs, 5); | 
 | 215 | 			bcs->mode = L1_MODE_NULL; | 
 | 216 | 			bcs->channel = bc; | 
 | 217 | 			break; | 
 | 218 | 		case (L1_MODE_TRANS): | 
 | 219 | 			bcs->mode = mode; | 
 | 220 | 			bcs->channel = bc; | 
 | 221 | 			bcs->hw.hdlc.ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS; | 
 | 222 | 			bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS; | 
 | 223 | 			write_ctrl(bcs, 5); | 
 | 224 | 			bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS; | 
 | 225 | 			write_ctrl(bcs, 1); | 
 | 226 | 			bcs->hw.hdlc.ctrl.sr.cmd = 0; | 
 | 227 | 			schedule_event(bcs, B_XMTBUFREADY); | 
 | 228 | 			break; | 
 | 229 | 		case (L1_MODE_HDLC): | 
 | 230 | 			bcs->mode = mode; | 
 | 231 | 			bcs->channel = bc; | 
 | 232 | 			bcs->hw.hdlc.ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS; | 
 | 233 | 			bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG; | 
 | 234 | 			write_ctrl(bcs, 5); | 
 | 235 | 			bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS; | 
 | 236 | 			write_ctrl(bcs, 1); | 
 | 237 | 			bcs->hw.hdlc.ctrl.sr.cmd = 0; | 
 | 238 | 			schedule_event(bcs, B_XMTBUFREADY); | 
 | 239 | 			break; | 
 | 240 | 	} | 
 | 241 | } | 
 | 242 |  | 
 | 243 | static inline void | 
 | 244 | hdlc_empty_fifo(struct BCState *bcs, int count) | 
 | 245 | { | 
 | 246 | 	register u_int *ptr; | 
 | 247 | 	u_char *p; | 
 | 248 | 	u_char idx = bcs->channel ? AVM_HDLC_2 : AVM_HDLC_1; | 
 | 249 | 	int cnt=0; | 
 | 250 | 	struct IsdnCardState *cs = bcs->cs; | 
 | 251 |  | 
 | 252 | 	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) | 
 | 253 | 		debugl1(cs, "hdlc_empty_fifo %d", count); | 
 | 254 | 	if (bcs->hw.hdlc.rcvidx + count > HSCX_BUFMAX) { | 
 | 255 | 		if (cs->debug & L1_DEB_WARN) | 
 | 256 | 			debugl1(cs, "hdlc_empty_fifo: incoming packet too large"); | 
 | 257 | 		return; | 
 | 258 | 	} | 
 | 259 | 	p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx; | 
 | 260 | 	ptr = (u_int *)p; | 
 | 261 | 	bcs->hw.hdlc.rcvidx += count; | 
 | 262 | 	if (cs->subtyp == AVM_FRITZ_PCI) { | 
 | 263 | 		outl(idx, cs->hw.avm.cfg_reg + 4); | 
 | 264 | 		while (cnt < count) { | 
 | 265 | #ifdef __powerpc__ | 
 | 266 | #ifdef CONFIG_APUS | 
 | 267 | 			*ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); | 
 | 268 | #else | 
 | 269 | 			*ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); | 
 | 270 | #endif /* CONFIG_APUS */ | 
 | 271 | #else | 
 | 272 | 			*ptr++ = inl(cs->hw.avm.isac); | 
 | 273 | #endif /* __powerpc__ */ | 
 | 274 | 			cnt += 4; | 
 | 275 | 		} | 
 | 276 | 	} else { | 
 | 277 | 		outb(idx, cs->hw.avm.cfg_reg + 4); | 
 | 278 | 		while (cnt < count) { | 
 | 279 | 			*p++ = inb(cs->hw.avm.isac); | 
 | 280 | 			cnt++; | 
 | 281 | 		} | 
 | 282 | 	} | 
 | 283 | 	if (cs->debug & L1_DEB_HSCX_FIFO) { | 
 | 284 | 		char *t = bcs->blog; | 
 | 285 |  | 
 | 286 | 		if (cs->subtyp == AVM_FRITZ_PNP) | 
 | 287 | 			p = (u_char *) ptr; | 
 | 288 | 		t += sprintf(t, "hdlc_empty_fifo %c cnt %d", | 
 | 289 | 			     bcs->channel ? 'B' : 'A', count); | 
 | 290 | 		QuickHex(t, p, count); | 
 | 291 | 		debugl1(cs, bcs->blog); | 
 | 292 | 	} | 
 | 293 | } | 
 | 294 |  | 
 | 295 | static inline void | 
 | 296 | hdlc_fill_fifo(struct BCState *bcs) | 
 | 297 | { | 
 | 298 | 	struct IsdnCardState *cs = bcs->cs; | 
 | 299 | 	int count, cnt =0; | 
 | 300 | 	int fifo_size = 32; | 
 | 301 | 	u_char *p; | 
 | 302 | 	u_int *ptr; | 
 | 303 |  | 
 | 304 | 	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) | 
 | 305 | 		debugl1(cs, "hdlc_fill_fifo"); | 
 | 306 | 	if (!bcs->tx_skb) | 
 | 307 | 		return; | 
 | 308 | 	if (bcs->tx_skb->len <= 0) | 
 | 309 | 		return; | 
 | 310 |  | 
 | 311 | 	bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME; | 
 | 312 | 	if (bcs->tx_skb->len > fifo_size) { | 
 | 313 | 		count = fifo_size; | 
 | 314 | 	} else { | 
 | 315 | 		count = bcs->tx_skb->len; | 
 | 316 | 		if (bcs->mode != L1_MODE_TRANS) | 
 | 317 | 			bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME; | 
 | 318 | 	} | 
 | 319 | 	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) | 
 | 320 | 		debugl1(cs, "hdlc_fill_fifo %d/%ld", count, bcs->tx_skb->len); | 
 | 321 | 	p = bcs->tx_skb->data; | 
 | 322 | 	ptr = (u_int *)p; | 
 | 323 | 	skb_pull(bcs->tx_skb, count); | 
 | 324 | 	bcs->tx_cnt -= count; | 
 | 325 | 	bcs->hw.hdlc.count += count; | 
 | 326 | 	bcs->hw.hdlc.ctrl.sr.xml = ((count == fifo_size) ? 0 : count); | 
 | 327 | 	write_ctrl(bcs, 3);  /* sets the correct index too */ | 
 | 328 | 	if (cs->subtyp == AVM_FRITZ_PCI) { | 
 | 329 | 		while (cnt<count) { | 
 | 330 | #ifdef __powerpc__ | 
 | 331 | #ifdef CONFIG_APUS | 
 | 332 | 			out_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++); | 
 | 333 | #else | 
 | 334 | 			out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++); | 
 | 335 | #endif /* CONFIG_APUS */ | 
 | 336 | #else | 
 | 337 | 			outl(*ptr++, cs->hw.avm.isac); | 
 | 338 | #endif /* __powerpc__ */ | 
 | 339 | 			cnt += 4; | 
 | 340 | 		} | 
 | 341 | 	} else { | 
 | 342 | 		while (cnt<count) { | 
 | 343 | 			outb(*p++, cs->hw.avm.isac); | 
 | 344 | 			cnt++; | 
 | 345 | 		} | 
 | 346 | 	} | 
 | 347 | 	if (cs->debug & L1_DEB_HSCX_FIFO) { | 
 | 348 | 		char *t = bcs->blog; | 
 | 349 |  | 
 | 350 | 		if (cs->subtyp == AVM_FRITZ_PNP) | 
 | 351 | 			p = (u_char *) ptr; | 
 | 352 | 		t += sprintf(t, "hdlc_fill_fifo %c cnt %d", | 
 | 353 | 			     bcs->channel ? 'B' : 'A', count); | 
 | 354 | 		QuickHex(t, p, count); | 
 | 355 | 		debugl1(cs, bcs->blog); | 
 | 356 | 	} | 
 | 357 | } | 
 | 358 |  | 
| Arjan van de Ven | 858119e | 2006-01-14 13:20:43 -0800 | [diff] [blame] | 359 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 360 | HDLC_irq(struct BCState *bcs, u_int stat) { | 
 | 361 | 	int len; | 
 | 362 | 	struct sk_buff *skb; | 
 | 363 |  | 
 | 364 | 	if (bcs->cs->debug & L1_DEB_HSCX) | 
 | 365 | 		debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat); | 
 | 366 | 	if (stat & HDLC_INT_RPR) { | 
 | 367 | 		if (stat & HDLC_STAT_RDO) { | 
 | 368 | 			if (bcs->cs->debug & L1_DEB_HSCX) | 
 | 369 | 				debugl1(bcs->cs, "RDO"); | 
 | 370 | 			else | 
 | 371 | 				debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat); | 
 | 372 | 			bcs->hw.hdlc.ctrl.sr.xml = 0; | 
 | 373 | 			bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_RRS; | 
 | 374 | 			write_ctrl(bcs, 1); | 
 | 375 | 			bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS; | 
 | 376 | 			write_ctrl(bcs, 1); | 
 | 377 | 			bcs->hw.hdlc.rcvidx = 0; | 
 | 378 | 		} else { | 
 | 379 | 			if (!(len = (stat & HDLC_STAT_RML_MASK)>>8)) | 
 | 380 | 				len = 32; | 
 | 381 | 			hdlc_empty_fifo(bcs, len); | 
 | 382 | 			if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) { | 
 | 383 | 				if (((stat & HDLC_STAT_CRCVFRRAB)==HDLC_STAT_CRCVFR) || | 
 | 384 | 					(bcs->mode == L1_MODE_TRANS)) { | 
 | 385 | 					if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx))) | 
 | 386 | 						printk(KERN_WARNING "HDLC: receive out of memory\n"); | 
 | 387 | 					else { | 
 | 388 | 						memcpy(skb_put(skb, bcs->hw.hdlc.rcvidx), | 
 | 389 | 							bcs->hw.hdlc.rcvbuf, bcs->hw.hdlc.rcvidx); | 
 | 390 | 						skb_queue_tail(&bcs->rqueue, skb); | 
 | 391 | 					} | 
 | 392 | 					bcs->hw.hdlc.rcvidx = 0; | 
 | 393 | 					schedule_event(bcs, B_RCVBUFREADY); | 
 | 394 | 				} else { | 
 | 395 | 					if (bcs->cs->debug & L1_DEB_HSCX) | 
 | 396 | 						debugl1(bcs->cs, "invalid frame"); | 
 | 397 | 					else | 
 | 398 | 						debugl1(bcs->cs, "ch%d invalid frame %#x", bcs->channel, stat); | 
 | 399 | 					bcs->hw.hdlc.rcvidx = 0; | 
 | 400 | 				} | 
 | 401 | 			} | 
 | 402 | 		} | 
 | 403 | 	} | 
 | 404 | 	if (stat & HDLC_INT_XDU) { | 
 | 405 | 		/* Here we lost an TX interrupt, so | 
 | 406 | 		 * restart transmitting the whole frame. | 
 | 407 | 		 */ | 
 | 408 | 		if (bcs->tx_skb) { | 
 | 409 | 			skb_push(bcs->tx_skb, bcs->hw.hdlc.count); | 
 | 410 | 			bcs->tx_cnt += bcs->hw.hdlc.count; | 
 | 411 | 			bcs->hw.hdlc.count = 0; | 
 | 412 | 			if (bcs->cs->debug & L1_DEB_WARN) | 
 | 413 | 				debugl1(bcs->cs, "ch%d XDU", bcs->channel); | 
 | 414 | 		} else if (bcs->cs->debug & L1_DEB_WARN) | 
 | 415 | 			debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel); | 
 | 416 | 		bcs->hw.hdlc.ctrl.sr.xml = 0; | 
 | 417 | 		bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS; | 
 | 418 | 		write_ctrl(bcs, 1); | 
 | 419 | 		bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS; | 
 | 420 | 		write_ctrl(bcs, 1); | 
 | 421 | 		hdlc_fill_fifo(bcs); | 
 | 422 | 	} else if (stat & HDLC_INT_XPR) { | 
 | 423 | 		if (bcs->tx_skb) { | 
 | 424 | 			if (bcs->tx_skb->len) { | 
 | 425 | 				hdlc_fill_fifo(bcs); | 
 | 426 | 				return; | 
 | 427 | 			} else { | 
 | 428 | 				if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && | 
 | 429 | 					(PACKET_NOACK != bcs->tx_skb->pkt_type)) { | 
 | 430 | 					u_long	flags; | 
 | 431 | 					spin_lock_irqsave(&bcs->aclock, flags); | 
 | 432 | 					bcs->ackcnt += bcs->hw.hdlc.count; | 
 | 433 | 					spin_unlock_irqrestore(&bcs->aclock, flags); | 
 | 434 | 					schedule_event(bcs, B_ACKPENDING); | 
 | 435 | 				} | 
 | 436 | 				dev_kfree_skb_irq(bcs->tx_skb); | 
 | 437 | 				bcs->hw.hdlc.count = 0; | 
 | 438 | 				bcs->tx_skb = NULL; | 
 | 439 | 			} | 
 | 440 | 		} | 
 | 441 | 		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { | 
 | 442 | 			bcs->hw.hdlc.count = 0; | 
 | 443 | 			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); | 
 | 444 | 			hdlc_fill_fifo(bcs); | 
 | 445 | 		} else { | 
 | 446 | 			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | 
 | 447 | 			schedule_event(bcs, B_XMTBUFREADY); | 
 | 448 | 		} | 
 | 449 | 	} | 
 | 450 | } | 
 | 451 |  | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 452 | static inline void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 453 | HDLC_irq_main(struct IsdnCardState *cs) | 
 | 454 | { | 
 | 455 | 	u_int stat; | 
 | 456 | 	struct BCState *bcs; | 
 | 457 |  | 
 | 458 | 	if (cs->subtyp == AVM_FRITZ_PCI) { | 
 | 459 | 		stat = ReadHDLCPCI(cs, 0, HDLC_STATUS); | 
 | 460 | 	} else { | 
 | 461 | 		stat = ReadHDLCPnP(cs, 0, HDLC_STATUS); | 
 | 462 | 		if (stat & HDLC_INT_RPR) | 
 | 463 | 			stat |= (ReadHDLCPnP(cs, 0, HDLC_STATUS+1))<<8; | 
 | 464 | 	} | 
 | 465 | 	if (stat & HDLC_INT_MASK) { | 
 | 466 | 		if (!(bcs = Sel_BCS(cs, 0))) { | 
 | 467 | 			if (cs->debug) | 
 | 468 | 				debugl1(cs, "hdlc spurious channel 0 IRQ"); | 
 | 469 | 		} else | 
 | 470 | 			HDLC_irq(bcs, stat); | 
 | 471 | 	} | 
 | 472 | 	if (cs->subtyp == AVM_FRITZ_PCI) { | 
 | 473 | 		stat = ReadHDLCPCI(cs, 1, HDLC_STATUS); | 
 | 474 | 	} else { | 
 | 475 | 		stat = ReadHDLCPnP(cs, 1, HDLC_STATUS); | 
 | 476 | 		if (stat & HDLC_INT_RPR) | 
 | 477 | 			stat |= (ReadHDLCPnP(cs, 1, HDLC_STATUS+1))<<8; | 
 | 478 | 	} | 
 | 479 | 	if (stat & HDLC_INT_MASK) { | 
 | 480 | 		if (!(bcs = Sel_BCS(cs, 1))) { | 
 | 481 | 			if (cs->debug) | 
 | 482 | 				debugl1(cs, "hdlc spurious channel 1 IRQ"); | 
 | 483 | 		} else | 
 | 484 | 			HDLC_irq(bcs, stat); | 
 | 485 | 	} | 
 | 486 | } | 
 | 487 |  | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 488 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 489 | hdlc_l2l1(struct PStack *st, int pr, void *arg) | 
 | 490 | { | 
 | 491 | 	struct BCState *bcs = st->l1.bcs; | 
 | 492 | 	struct sk_buff *skb = arg; | 
 | 493 | 	u_long flags; | 
 | 494 |  | 
 | 495 | 	switch (pr) { | 
 | 496 | 		case (PH_DATA | REQUEST): | 
 | 497 | 			spin_lock_irqsave(&bcs->cs->lock, flags); | 
 | 498 | 			if (bcs->tx_skb) { | 
 | 499 | 				skb_queue_tail(&bcs->squeue, skb); | 
 | 500 | 			} else { | 
 | 501 | 				bcs->tx_skb = skb; | 
 | 502 | 				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); | 
 | 503 | 				bcs->hw.hdlc.count = 0; | 
 | 504 | 				bcs->cs->BC_Send_Data(bcs); | 
 | 505 | 			} | 
 | 506 | 			spin_unlock_irqrestore(&bcs->cs->lock, flags); | 
 | 507 | 			break; | 
 | 508 | 		case (PH_PULL | INDICATION): | 
 | 509 | 			spin_lock_irqsave(&bcs->cs->lock, flags); | 
 | 510 | 			if (bcs->tx_skb) { | 
 | 511 | 				printk(KERN_WARNING "hdlc_l2l1: this shouldn't happen\n"); | 
 | 512 | 			} else { | 
 | 513 | 				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); | 
 | 514 | 				bcs->tx_skb = skb; | 
 | 515 | 				bcs->hw.hdlc.count = 0; | 
 | 516 | 				bcs->cs->BC_Send_Data(bcs); | 
 | 517 | 			} | 
 | 518 | 			spin_unlock_irqrestore(&bcs->cs->lock, flags); | 
 | 519 | 			break; | 
 | 520 | 		case (PH_PULL | REQUEST): | 
 | 521 | 			if (!bcs->tx_skb) { | 
 | 522 | 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | 
 | 523 | 				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); | 
 | 524 | 			} else | 
 | 525 | 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | 
 | 526 | 			break; | 
 | 527 | 		case (PH_ACTIVATE | REQUEST): | 
 | 528 | 			spin_lock_irqsave(&bcs->cs->lock, flags); | 
 | 529 | 			test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); | 
 | 530 | 			modehdlc(bcs, st->l1.mode, st->l1.bc); | 
 | 531 | 			spin_unlock_irqrestore(&bcs->cs->lock, flags); | 
 | 532 | 			l1_msg_b(st, pr, arg); | 
 | 533 | 			break; | 
 | 534 | 		case (PH_DEACTIVATE | REQUEST): | 
 | 535 | 			l1_msg_b(st, pr, arg); | 
 | 536 | 			break; | 
 | 537 | 		case (PH_DEACTIVATE | CONFIRM): | 
 | 538 | 			spin_lock_irqsave(&bcs->cs->lock, flags); | 
 | 539 | 			test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); | 
 | 540 | 			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | 
 | 541 | 			modehdlc(bcs, 0, st->l1.bc); | 
 | 542 | 			spin_unlock_irqrestore(&bcs->cs->lock, flags); | 
 | 543 | 			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); | 
 | 544 | 			break; | 
 | 545 | 	} | 
 | 546 | } | 
 | 547 |  | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 548 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 549 | close_hdlcstate(struct BCState *bcs) | 
 | 550 | { | 
 | 551 | 	modehdlc(bcs, 0, 0); | 
 | 552 | 	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { | 
| Jesper Juhl | 3c7208f | 2005-11-07 01:01:29 -0800 | [diff] [blame] | 553 | 		kfree(bcs->hw.hdlc.rcvbuf); | 
 | 554 | 		bcs->hw.hdlc.rcvbuf = NULL; | 
 | 555 | 		kfree(bcs->blog); | 
 | 556 | 		bcs->blog = NULL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 557 | 		skb_queue_purge(&bcs->rqueue); | 
 | 558 | 		skb_queue_purge(&bcs->squeue); | 
 | 559 | 		if (bcs->tx_skb) { | 
 | 560 | 			dev_kfree_skb_any(bcs->tx_skb); | 
 | 561 | 			bcs->tx_skb = NULL; | 
 | 562 | 			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | 
 | 563 | 		} | 
 | 564 | 	} | 
 | 565 | } | 
 | 566 |  | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 567 | static int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 568 | open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs) | 
 | 569 | { | 
 | 570 | 	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { | 
 | 571 | 		if (!(bcs->hw.hdlc.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { | 
 | 572 | 			printk(KERN_WARNING | 
 | 573 | 			       "HiSax: No memory for hdlc.rcvbuf\n"); | 
 | 574 | 			return (1); | 
 | 575 | 		} | 
 | 576 | 		if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { | 
 | 577 | 			printk(KERN_WARNING | 
 | 578 | 				"HiSax: No memory for bcs->blog\n"); | 
 | 579 | 			test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); | 
 | 580 | 			kfree(bcs->hw.hdlc.rcvbuf); | 
 | 581 | 			bcs->hw.hdlc.rcvbuf = NULL; | 
 | 582 | 			return (2); | 
 | 583 | 		} | 
 | 584 | 		skb_queue_head_init(&bcs->rqueue); | 
 | 585 | 		skb_queue_head_init(&bcs->squeue); | 
 | 586 | 	} | 
 | 587 | 	bcs->tx_skb = NULL; | 
 | 588 | 	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | 
 | 589 | 	bcs->event = 0; | 
 | 590 | 	bcs->hw.hdlc.rcvidx = 0; | 
 | 591 | 	bcs->tx_cnt = 0; | 
 | 592 | 	return (0); | 
 | 593 | } | 
 | 594 |  | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 595 | static int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 596 | setstack_hdlc(struct PStack *st, struct BCState *bcs) | 
 | 597 | { | 
 | 598 | 	bcs->channel = st->l1.bc; | 
 | 599 | 	if (open_hdlcstate(st->l1.hardware, bcs)) | 
 | 600 | 		return (-1); | 
 | 601 | 	st->l1.bcs = bcs; | 
 | 602 | 	st->l2.l2l1 = hdlc_l2l1; | 
 | 603 | 	setstack_manager(st); | 
 | 604 | 	bcs->st = st; | 
 | 605 | 	setstack_l1_B(st); | 
 | 606 | 	return (0); | 
 | 607 | } | 
 | 608 |  | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 609 | #if 0 | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 610 | void __init | 
 | 611 | clear_pending_hdlc_ints(struct IsdnCardState *cs) | 
 | 612 | { | 
 | 613 | 	u_int val; | 
 | 614 |  | 
 | 615 | 	if (cs->subtyp == AVM_FRITZ_PCI) { | 
 | 616 | 		val = ReadHDLCPCI(cs, 0, HDLC_STATUS); | 
 | 617 | 		debugl1(cs, "HDLC 1 STA %x", val); | 
 | 618 | 		val = ReadHDLCPCI(cs, 1, HDLC_STATUS); | 
 | 619 | 		debugl1(cs, "HDLC 2 STA %x", val); | 
 | 620 | 	} else { | 
 | 621 | 		val = ReadHDLCPnP(cs, 0, HDLC_STATUS); | 
 | 622 | 		debugl1(cs, "HDLC 1 STA %x", val); | 
 | 623 | 		val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 1); | 
 | 624 | 		debugl1(cs, "HDLC 1 RML %x", val); | 
 | 625 | 		val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 2); | 
 | 626 | 		debugl1(cs, "HDLC 1 MODE %x", val); | 
 | 627 | 		val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 3); | 
 | 628 | 		debugl1(cs, "HDLC 1 VIN %x", val); | 
 | 629 | 		val = ReadHDLCPnP(cs, 1, HDLC_STATUS); | 
 | 630 | 		debugl1(cs, "HDLC 2 STA %x", val); | 
 | 631 | 		val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 1); | 
 | 632 | 		debugl1(cs, "HDLC 2 RML %x", val); | 
 | 633 | 		val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 2); | 
 | 634 | 		debugl1(cs, "HDLC 2 MODE %x", val); | 
 | 635 | 		val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 3); | 
 | 636 | 		debugl1(cs, "HDLC 2 VIN %x", val); | 
 | 637 | 	} | 
 | 638 | } | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 639 | #endif  /*  0  */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 640 |  | 
| Karsten Keil | 67eb5db | 2006-07-10 04:44:11 -0700 | [diff] [blame] | 641 | static void | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 642 | inithdlc(struct IsdnCardState *cs) | 
 | 643 | { | 
 | 644 | 	cs->bcs[0].BC_SetStack = setstack_hdlc; | 
 | 645 | 	cs->bcs[1].BC_SetStack = setstack_hdlc; | 
 | 646 | 	cs->bcs[0].BC_Close = close_hdlcstate; | 
 | 647 | 	cs->bcs[1].BC_Close = close_hdlcstate; | 
 | 648 | 	modehdlc(cs->bcs, -1, 0); | 
 | 649 | 	modehdlc(cs->bcs + 1, -1, 1); | 
 | 650 | } | 
 | 651 |  | 
 | 652 | static irqreturn_t | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 653 | avm_pcipnp_interrupt(int intno, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 654 | { | 
 | 655 | 	struct IsdnCardState *cs = dev_id; | 
 | 656 | 	u_long flags; | 
 | 657 | 	u_char val; | 
 | 658 | 	u_char sval; | 
 | 659 |  | 
 | 660 | 	spin_lock_irqsave(&cs->lock, flags); | 
 | 661 | 	sval = inb(cs->hw.avm.cfg_reg + 2); | 
 | 662 | 	if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) { | 
 | 663 | 		/* possible a shared  IRQ reqest */ | 
 | 664 | 		spin_unlock_irqrestore(&cs->lock, flags); | 
 | 665 | 		return IRQ_NONE; | 
 | 666 | 	} | 
 | 667 | 	if (!(sval & AVM_STATUS0_IRQ_ISAC)) { | 
 | 668 | 		val = ReadISAC(cs, ISAC_ISTA); | 
 | 669 | 		isac_interrupt(cs, val); | 
 | 670 | 	} | 
 | 671 | 	if (!(sval & AVM_STATUS0_IRQ_HDLC)) { | 
 | 672 | 		HDLC_irq_main(cs); | 
 | 673 | 	} | 
 | 674 | 	WriteISAC(cs, ISAC_MASK, 0xFF); | 
 | 675 | 	WriteISAC(cs, ISAC_MASK, 0x0); | 
 | 676 | 	spin_unlock_irqrestore(&cs->lock, flags); | 
 | 677 | 	return IRQ_HANDLED; | 
 | 678 | } | 
 | 679 |  | 
 | 680 | static void | 
 | 681 | reset_avmpcipnp(struct IsdnCardState *cs) | 
 | 682 | { | 
 | 683 | 	printk(KERN_INFO "AVM PCI/PnP: reset\n"); | 
 | 684 | 	outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2); | 
 | 685 | 	mdelay(10); | 
 | 686 | 	outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); | 
 | 687 | 	outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3); | 
 | 688 | 	mdelay(10); | 
 | 689 | 	printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3)); | 
 | 690 | } | 
 | 691 |  | 
 | 692 | static int | 
 | 693 | AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) | 
 | 694 | { | 
 | 695 | 	u_long flags; | 
 | 696 |  | 
 | 697 | 	switch (mt) { | 
 | 698 | 		case CARD_RESET: | 
 | 699 | 			spin_lock_irqsave(&cs->lock, flags); | 
 | 700 | 			reset_avmpcipnp(cs); | 
 | 701 | 			spin_unlock_irqrestore(&cs->lock, flags); | 
 | 702 | 			return(0); | 
 | 703 | 		case CARD_RELEASE: | 
 | 704 | 			outb(0, cs->hw.avm.cfg_reg + 2); | 
 | 705 | 			release_region(cs->hw.avm.cfg_reg, 32); | 
 | 706 | 			return(0); | 
 | 707 | 		case CARD_INIT: | 
 | 708 | 			spin_lock_irqsave(&cs->lock, flags); | 
 | 709 | 			reset_avmpcipnp(cs); | 
 | 710 | 			clear_pending_isac_ints(cs); | 
 | 711 | 			initisac(cs); | 
 | 712 | 			inithdlc(cs); | 
 | 713 | 			outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER, | 
 | 714 | 				cs->hw.avm.cfg_reg + 2); | 
 | 715 | 			WriteISAC(cs, ISAC_MASK, 0); | 
 | 716 | 			outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | | 
 | 717 | 				AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); | 
 | 718 | 			/* RESET Receiver and Transmitter */ | 
 | 719 | 			WriteISAC(cs, ISAC_CMDR, 0x41); | 
 | 720 | 			spin_unlock_irqrestore(&cs->lock, flags); | 
 | 721 | 			return(0); | 
 | 722 | 		case CARD_TEST: | 
 | 723 | 			return(0); | 
 | 724 | 	} | 
 | 725 | 	return(0); | 
 | 726 | } | 
 | 727 |  | 
| Jeff Garzik | 2fbde4c | 2007-10-03 15:23:49 -0400 | [diff] [blame] | 728 | static int __devinit avm_setup_rest(struct IsdnCardState *cs) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 729 | { | 
 | 730 | 	u_int val, ver; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 731 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 732 | 	cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; | 
 | 733 | 	if (!request_region(cs->hw.avm.cfg_reg, 32, | 
 | 734 | 		(cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) { | 
 | 735 | 		printk(KERN_WARNING | 
| Jeff Garzik | 2fbde4c | 2007-10-03 15:23:49 -0400 | [diff] [blame] | 736 | 		       "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 737 | 		       cs->hw.avm.cfg_reg, | 
 | 738 | 		       cs->hw.avm.cfg_reg + 31); | 
 | 739 | 		return (0); | 
 | 740 | 	} | 
 | 741 | 	switch (cs->subtyp) { | 
 | 742 | 	  case AVM_FRITZ_PCI: | 
 | 743 | 		val = inl(cs->hw.avm.cfg_reg); | 
 | 744 | 		printk(KERN_INFO "AVM PCI: stat %#x\n", val); | 
 | 745 | 		printk(KERN_INFO "AVM PCI: Class %X Rev %d\n", | 
 | 746 | 			val & 0xff, (val>>8) & 0xff); | 
 | 747 | 		cs->BC_Read_Reg = &ReadHDLC_s; | 
 | 748 | 		cs->BC_Write_Reg = &WriteHDLC_s; | 
 | 749 | 		break; | 
 | 750 | 	  case AVM_FRITZ_PNP: | 
 | 751 | 		val = inb(cs->hw.avm.cfg_reg); | 
 | 752 | 		ver = inb(cs->hw.avm.cfg_reg + 1); | 
 | 753 | 		printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver); | 
 | 754 | 		cs->BC_Read_Reg = &ReadHDLCPnP; | 
 | 755 | 		cs->BC_Write_Reg = &WriteHDLCPnP; | 
 | 756 | 		break; | 
 | 757 | 	  default: | 
 | 758 | 	  	printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp); | 
 | 759 | 	  	return(0); | 
 | 760 | 	} | 
 | 761 | 	printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n", | 
 | 762 | 		(cs->subtyp == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" : "AVM Fritz!PnP", | 
 | 763 | 		cs->irq, cs->hw.avm.cfg_reg); | 
 | 764 |  | 
 | 765 | 	setup_isac(cs); | 
 | 766 | 	cs->readisac = &ReadISAC; | 
 | 767 | 	cs->writeisac = &WriteISAC; | 
 | 768 | 	cs->readisacfifo = &ReadISACfifo; | 
 | 769 | 	cs->writeisacfifo = &WriteISACfifo; | 
 | 770 | 	cs->BC_Send_Data = &hdlc_fill_fifo; | 
 | 771 | 	cs->cardmsg = &AVM_card_msg; | 
 | 772 | 	cs->irq_func = &avm_pcipnp_interrupt; | 
 | 773 | 	cs->writeisac(cs, ISAC_MASK, 0xFF); | 
 | 774 | 	ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:"); | 
 | 775 | 	return (1); | 
 | 776 | } | 
| Jeff Garzik | 2fbde4c | 2007-10-03 15:23:49 -0400 | [diff] [blame] | 777 |  | 
 | 778 | #ifndef __ISAPNP__ | 
 | 779 |  | 
 | 780 | static int __devinit avm_pnp_setup(struct IsdnCardState *cs) | 
 | 781 | { | 
 | 782 | 	return(1);	/* no-op: success */ | 
 | 783 | } | 
 | 784 |  | 
 | 785 | #else | 
 | 786 |  | 
 | 787 | static struct pnp_card *pnp_avm_c __devinitdata = NULL; | 
 | 788 |  | 
 | 789 | static int __devinit avm_pnp_setup(struct IsdnCardState *cs) | 
 | 790 | { | 
 | 791 | 	struct pnp_dev *pnp_avm_d = NULL; | 
 | 792 |  | 
 | 793 | 	if (!isapnp_present()) | 
 | 794 | 		return(1);	/* no-op: success */ | 
 | 795 |  | 
 | 796 | 	if ((pnp_avm_c = pnp_find_card( | 
 | 797 | 		ISAPNP_VENDOR('A', 'V', 'M'), | 
 | 798 | 		ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { | 
 | 799 | 		if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, | 
 | 800 | 			ISAPNP_VENDOR('A', 'V', 'M'), | 
 | 801 | 			ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { | 
 | 802 | 			int err; | 
 | 803 |  | 
 | 804 | 			pnp_disable_dev(pnp_avm_d); | 
 | 805 | 			err = pnp_activate_dev(pnp_avm_d); | 
 | 806 | 			if (err<0) { | 
 | 807 | 				printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", | 
 | 808 | 					__FUNCTION__, err); | 
 | 809 | 				return(0); | 
 | 810 | 			} | 
 | 811 | 			cs->hw.avm.cfg_reg = | 
 | 812 | 				pnp_port_start(pnp_avm_d, 0); | 
 | 813 | 			cs->irq = pnp_irq(pnp_avm_d, 0); | 
 | 814 | 			if (!cs->irq) { | 
 | 815 | 				printk(KERN_ERR "FritzPnP:No IRQ\n"); | 
 | 816 | 				return(0); | 
 | 817 | 			} | 
 | 818 | 			if (!cs->hw.avm.cfg_reg) { | 
 | 819 | 				printk(KERN_ERR "FritzPnP:No IO address\n"); | 
 | 820 | 				return(0); | 
 | 821 | 			} | 
 | 822 | 			cs->subtyp = AVM_FRITZ_PNP; | 
 | 823 |  | 
 | 824 | 			return (2);	/* goto 'ready' label */ | 
 | 825 | 		} | 
 | 826 | 	} | 
 | 827 |  | 
 | 828 | 	return (1); | 
 | 829 | } | 
 | 830 |  | 
 | 831 | #endif /* __ISAPNP__ */ | 
 | 832 |  | 
| Jeff Garzik | bd3989e | 2007-10-29 09:48:09 -0400 | [diff] [blame] | 833 | #ifndef CONFIG_PCI_LEGACY | 
| Jeff Garzik | 2fbde4c | 2007-10-03 15:23:49 -0400 | [diff] [blame] | 834 |  | 
 | 835 | static int __devinit avm_pci_setup(struct IsdnCardState *cs) | 
 | 836 | { | 
 | 837 | 	return(1);	/* no-op: success */ | 
 | 838 | } | 
 | 839 |  | 
 | 840 | #else | 
 | 841 |  | 
 | 842 | static struct pci_dev *dev_avm __devinitdata = NULL; | 
 | 843 |  | 
 | 844 | static int __devinit avm_pci_setup(struct IsdnCardState *cs) | 
 | 845 | { | 
 | 846 | 	if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, | 
 | 847 | 		PCI_DEVICE_ID_AVM_A1, dev_avm))) { | 
 | 848 |  | 
 | 849 | 		if (pci_enable_device(dev_avm)) | 
 | 850 | 			return(0); | 
 | 851 |  | 
 | 852 | 		cs->irq = dev_avm->irq; | 
 | 853 | 		if (!cs->irq) { | 
 | 854 | 			printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); | 
 | 855 | 			return(0); | 
 | 856 | 		} | 
 | 857 |  | 
 | 858 | 		cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); | 
 | 859 | 		if (!cs->hw.avm.cfg_reg) { | 
 | 860 | 			printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); | 
 | 861 | 			return(0); | 
 | 862 | 		} | 
 | 863 |  | 
 | 864 | 		cs->subtyp = AVM_FRITZ_PCI; | 
 | 865 | 	} else { | 
 | 866 | 		printk(KERN_WARNING "FritzPCI: No PCI card found\n"); | 
 | 867 | 		return(0); | 
 | 868 | 	} | 
 | 869 |  | 
 | 870 | 	cs->irq_flags |= IRQF_SHARED; | 
 | 871 |  | 
 | 872 | 	return (1); | 
 | 873 | } | 
 | 874 |  | 
| Jeff Garzik | bd3989e | 2007-10-29 09:48:09 -0400 | [diff] [blame] | 875 | #endif /* CONFIG_PCI_LEGACY */ | 
| Jeff Garzik | 2fbde4c | 2007-10-03 15:23:49 -0400 | [diff] [blame] | 876 |  | 
 | 877 | int __devinit | 
 | 878 | setup_avm_pcipnp(struct IsdnCard *card) | 
 | 879 | { | 
 | 880 | 	struct IsdnCardState *cs = card->cs; | 
 | 881 | 	char tmp[64]; | 
 | 882 | 	int rc; | 
 | 883 |  | 
 | 884 | 	strcpy(tmp, avm_pci_rev); | 
 | 885 | 	printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); | 
 | 886 |  | 
 | 887 | 	if (cs->typ != ISDN_CTYPE_FRITZPCI) | 
 | 888 | 		return (0); | 
 | 889 |  | 
 | 890 | 	if (card->para[1]) { | 
 | 891 | 		/* old manual method */ | 
 | 892 | 		cs->hw.avm.cfg_reg = card->para[1]; | 
 | 893 | 		cs->irq = card->para[0]; | 
 | 894 | 		cs->subtyp = AVM_FRITZ_PNP; | 
 | 895 | 		goto ready; | 
 | 896 | 	} | 
 | 897 |  | 
 | 898 | 	rc = avm_pnp_setup(cs); | 
 | 899 | 	if (rc < 1) | 
 | 900 | 		return (0); | 
 | 901 | 	if (rc == 2) | 
 | 902 | 		goto ready; | 
 | 903 |  | 
 | 904 | 	rc = avm_pci_setup(cs); | 
 | 905 | 	if (rc < 1) | 
 | 906 | 		return (0); | 
 | 907 |  | 
 | 908 | ready: | 
 | 909 | 	return avm_setup_rest(cs); | 
 | 910 | } |