| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* $Id: b1dma.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ | 
 | 2 |  *  | 
 | 3 |  * Common module for AVM B1 cards that support dma with AMCC | 
 | 4 |  *  | 
 | 5 |  * Copyright 2000 by Carsten Paeth <calle@calle.de> | 
 | 6 |  *  | 
 | 7 |  * This software may be used and distributed according to the terms | 
 | 8 |  * of the GNU General Public License, incorporated herein by reference. | 
 | 9 |  * | 
 | 10 |  */ | 
 | 11 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 12 | #include <linux/module.h> | 
 | 13 | #include <linux/kernel.h> | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 14 | #include <linux/proc_fs.h> | 
 | 15 | #include <linux/seq_file.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 16 | #include <linux/skbuff.h> | 
 | 17 | #include <linux/delay.h> | 
 | 18 | #include <linux/mm.h> | 
 | 19 | #include <linux/interrupt.h> | 
 | 20 | #include <linux/ioport.h> | 
 | 21 | #include <linux/capi.h> | 
 | 22 | #include <linux/kernelcapi.h> | 
 | 23 | #include <asm/io.h> | 
 | 24 | #include <linux/init.h> | 
 | 25 | #include <asm/uaccess.h> | 
 | 26 | #include <linux/netdevice.h> | 
 | 27 | #include <linux/isdn/capilli.h> | 
 | 28 | #include "avmcard.h" | 
 | 29 | #include <linux/isdn/capicmd.h> | 
 | 30 | #include <linux/isdn/capiutil.h> | 
 | 31 |  | 
 | 32 | static char *revision = "$Revision: 1.1.2.3 $"; | 
 | 33 |  | 
| Robert P. J. Day | 26fb5c5 | 2007-02-12 00:53:20 -0800 | [diff] [blame] | 34 | #undef AVM_B1DMA_DEBUG | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 35 |  | 
 | 36 | /* ------------------------------------------------------------- */ | 
 | 37 |  | 
 | 38 | MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards"); | 
 | 39 | MODULE_AUTHOR("Carsten Paeth"); | 
 | 40 | MODULE_LICENSE("GPL"); | 
 | 41 |  | 
 | 42 | static int suppress_pollack = 0; | 
| Rusty Russell | 8d3b33f | 2006-03-25 03:07:05 -0800 | [diff] [blame] | 43 | module_param(suppress_pollack, bool, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 |  | 
 | 45 | /* ------------------------------------------------------------- */ | 
 | 46 |  | 
 | 47 | static void b1dma_dispatch_tx(avmcard *card); | 
 | 48 |  | 
 | 49 | /* ------------------------------------------------------------- */ | 
 | 50 |  | 
 | 51 | /* S5933 */ | 
 | 52 |  | 
 | 53 | #define	AMCC_RXPTR	0x24 | 
 | 54 | #define	AMCC_RXLEN	0x28 | 
 | 55 | #define	AMCC_TXPTR	0x2c | 
 | 56 | #define	AMCC_TXLEN	0x30 | 
 | 57 |  | 
 | 58 | #define	AMCC_INTCSR	0x38 | 
 | 59 | #	define EN_READ_TC_INT		0x00008000L | 
 | 60 | #	define EN_WRITE_TC_INT		0x00004000L | 
 | 61 | #	define EN_TX_TC_INT		EN_READ_TC_INT | 
 | 62 | #	define EN_RX_TC_INT		EN_WRITE_TC_INT | 
 | 63 | #	define AVM_FLAG			0x30000000L | 
 | 64 |  | 
 | 65 | #	define ANY_S5933_INT		0x00800000L | 
 | 66 | #	define READ_TC_INT		0x00080000L | 
 | 67 | #	define WRITE_TC_INT		0x00040000L | 
 | 68 | #	define	TX_TC_INT		READ_TC_INT | 
 | 69 | #	define	RX_TC_INT		WRITE_TC_INT | 
 | 70 | #	define MASTER_ABORT_INT		0x00100000L | 
 | 71 | #	define TARGET_ABORT_INT		0x00200000L | 
 | 72 | #	define BUS_MASTER_INT		0x00200000L | 
 | 73 | #	define ALL_INT			0x000C0000L | 
 | 74 |  | 
 | 75 | #define	AMCC_MCSR	0x3c | 
 | 76 | #	define A2P_HI_PRIORITY		0x00000100L | 
 | 77 | #	define EN_A2P_TRANSFERS		0x00000400L | 
 | 78 | #	define P2A_HI_PRIORITY		0x00001000L | 
 | 79 | #	define EN_P2A_TRANSFERS		0x00004000L | 
 | 80 | #	define RESET_A2P_FLAGS		0x04000000L | 
 | 81 | #	define RESET_P2A_FLAGS		0x02000000L | 
 | 82 |  | 
 | 83 | /* ------------------------------------------------------------- */ | 
 | 84 |  | 
 | 85 | static inline void b1dma_writel(avmcard *card, u32 value, int off) | 
 | 86 | { | 
 | 87 | 	writel(value, card->mbase + off); | 
 | 88 | } | 
 | 89 |  | 
 | 90 | static inline u32 b1dma_readl(avmcard *card, int off) | 
 | 91 | { | 
 | 92 | 	return readl(card->mbase + off); | 
 | 93 | } | 
 | 94 |  | 
 | 95 | /* ------------------------------------------------------------- */ | 
 | 96 |  | 
 | 97 | static inline int b1dma_tx_empty(unsigned int port) | 
 | 98 | { | 
 | 99 | 	return inb(port + 0x03) & 0x1; | 
 | 100 | } | 
 | 101 |  | 
 | 102 | static inline int b1dma_rx_full(unsigned int port) | 
 | 103 | { | 
 | 104 | 	return inb(port + 0x02) & 0x1; | 
 | 105 | } | 
 | 106 |  | 
 | 107 | static int b1dma_tolink(avmcard *card, void *buf, unsigned int len) | 
 | 108 | { | 
 | 109 | 	unsigned long stop = jiffies + 1 * HZ;	/* maximum wait time 1 sec */ | 
 | 110 | 	unsigned char *s = (unsigned char *)buf; | 
 | 111 | 	while (len--) { | 
 | 112 | 		while (   !b1dma_tx_empty(card->port) | 
 | 113 | 		       && time_before(jiffies, stop)); | 
 | 114 | 		if (!b1dma_tx_empty(card->port))  | 
 | 115 | 			return -1; | 
 | 116 | 	        t1outp(card->port, 0x01, *s++); | 
 | 117 | 	} | 
 | 118 | 	return 0; | 
 | 119 | } | 
 | 120 |  | 
 | 121 | static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len) | 
 | 122 | { | 
 | 123 | 	unsigned long stop = jiffies + 1 * HZ;	/* maximum wait time 1 sec */ | 
 | 124 | 	unsigned char *s = (unsigned char *)buf; | 
 | 125 | 	while (len--) { | 
 | 126 | 		while (   !b1dma_rx_full(card->port) | 
 | 127 | 		       && time_before(jiffies, stop)); | 
 | 128 | 		if (!b1dma_rx_full(card->port))  | 
 | 129 | 			return -1; | 
 | 130 | 	        *s++ = t1inp(card->port, 0x00); | 
 | 131 | 	} | 
 | 132 | 	return 0; | 
 | 133 | } | 
 | 134 |  | 
 | 135 | static int WriteReg(avmcard *card, u32 reg, u8 val) | 
 | 136 | { | 
 | 137 | 	u8 cmd = 0x00; | 
 | 138 | 	if (   b1dma_tolink(card, &cmd, 1) == 0 | 
 | 139 | 	    && b1dma_tolink(card, ®, 4) == 0) { | 
 | 140 | 		u32 tmp = val; | 
 | 141 | 		return b1dma_tolink(card, &tmp, 4); | 
 | 142 | 	} | 
 | 143 | 	return -1; | 
 | 144 | } | 
 | 145 |  | 
 | 146 | static u8 ReadReg(avmcard *card, u32 reg) | 
 | 147 | { | 
 | 148 | 	u8 cmd = 0x01; | 
 | 149 | 	if (   b1dma_tolink(card, &cmd, 1) == 0 | 
 | 150 | 	    && b1dma_tolink(card, ®, 4) == 0) { | 
 | 151 | 		u32 tmp; | 
 | 152 | 		if (b1dma_fromlink(card, &tmp, 4) == 0) | 
 | 153 | 			return (u8)tmp; | 
 | 154 | 	} | 
 | 155 | 	return 0xff; | 
 | 156 | } | 
 | 157 |  | 
 | 158 | /* ------------------------------------------------------------- */ | 
 | 159 |  | 
 | 160 | static inline void _put_byte(void **pp, u8 val) | 
 | 161 | { | 
 | 162 | 	u8 *s = *pp; | 
 | 163 | 	*s++ = val; | 
 | 164 | 	*pp = s; | 
 | 165 | } | 
 | 166 |  | 
 | 167 | static inline void _put_word(void **pp, u32 val) | 
 | 168 | { | 
 | 169 | 	u8 *s = *pp; | 
 | 170 | 	*s++ = val & 0xff; | 
 | 171 | 	*s++ = (val >> 8) & 0xff; | 
 | 172 | 	*s++ = (val >> 16) & 0xff; | 
 | 173 | 	*s++ = (val >> 24) & 0xff; | 
 | 174 | 	*pp = s; | 
 | 175 | } | 
 | 176 |  | 
 | 177 | static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len) | 
 | 178 | { | 
 | 179 | 	unsigned i = len; | 
 | 180 | 	_put_word(pp, i); | 
 | 181 | 	while (i-- > 0) | 
 | 182 | 		_put_byte(pp, *dp++); | 
 | 183 | } | 
 | 184 |  | 
 | 185 | static inline u8 _get_byte(void **pp) | 
 | 186 | { | 
 | 187 | 	u8 *s = *pp; | 
 | 188 | 	u8 val; | 
 | 189 | 	val = *s++; | 
 | 190 | 	*pp = s; | 
 | 191 | 	return val; | 
 | 192 | } | 
 | 193 |  | 
 | 194 | static inline u32 _get_word(void **pp) | 
 | 195 | { | 
 | 196 | 	u8 *s = *pp; | 
 | 197 | 	u32 val; | 
 | 198 | 	val = *s++; | 
 | 199 | 	val |= (*s++ << 8); | 
 | 200 | 	val |= (*s++ << 16); | 
 | 201 | 	val |= (*s++ << 24); | 
 | 202 | 	*pp = s; | 
 | 203 | 	return val; | 
 | 204 | } | 
 | 205 |  | 
 | 206 | static inline u32 _get_slice(void **pp, unsigned char *dp) | 
 | 207 | { | 
 | 208 | 	unsigned int len, i; | 
 | 209 |  | 
 | 210 | 	len = i = _get_word(pp); | 
 | 211 | 	while (i-- > 0) *dp++ = _get_byte(pp); | 
 | 212 | 	return len; | 
 | 213 | } | 
 | 214 |  | 
 | 215 | /* ------------------------------------------------------------- */ | 
 | 216 |  | 
 | 217 | void b1dma_reset(avmcard *card) | 
 | 218 | { | 
 | 219 | 	card->csr = 0x0; | 
 | 220 | 	b1dma_writel(card, card->csr, AMCC_INTCSR); | 
 | 221 | 	b1dma_writel(card, 0, AMCC_MCSR); | 
 | 222 | 	b1dma_writel(card, 0, AMCC_RXLEN); | 
 | 223 | 	b1dma_writel(card, 0, AMCC_TXLEN); | 
 | 224 |  | 
 | 225 | 	t1outp(card->port, 0x10, 0x00); | 
 | 226 | 	t1outp(card->port, 0x07, 0x00); | 
 | 227 |  | 
 | 228 | 	b1dma_writel(card, 0, AMCC_MCSR); | 
 | 229 | 	mdelay(10); | 
 | 230 | 	b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */ | 
 | 231 | 	mdelay(10); | 
 | 232 | 	b1dma_writel(card, 0, AMCC_MCSR); | 
 | 233 | 	if (card->cardtype == avm_t1pci) | 
 | 234 | 		mdelay(42); | 
 | 235 | 	else | 
 | 236 | 		mdelay(10); | 
 | 237 | } | 
 | 238 |  | 
 | 239 | /* ------------------------------------------------------------- */ | 
 | 240 |  | 
 | 241 | static int b1dma_detect(avmcard *card) | 
 | 242 | { | 
 | 243 | 	b1dma_writel(card, 0, AMCC_MCSR); | 
 | 244 | 	mdelay(10); | 
 | 245 | 	b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */ | 
 | 246 | 	mdelay(10); | 
 | 247 | 	b1dma_writel(card, 0, AMCC_MCSR); | 
 | 248 | 	mdelay(42); | 
 | 249 |  | 
 | 250 | 	b1dma_writel(card, 0, AMCC_RXLEN); | 
 | 251 | 	b1dma_writel(card, 0, AMCC_TXLEN); | 
 | 252 | 	card->csr = 0x0; | 
 | 253 | 	b1dma_writel(card, card->csr, AMCC_INTCSR); | 
 | 254 |  | 
 | 255 | 	if (b1dma_readl(card, AMCC_MCSR) != 0x000000E6) | 
 | 256 | 		return 1; | 
 | 257 |  | 
 | 258 | 	b1dma_writel(card, 0xffffffff, AMCC_RXPTR); | 
 | 259 | 	b1dma_writel(card, 0xffffffff, AMCC_TXPTR); | 
 | 260 | 	if (   b1dma_readl(card, AMCC_RXPTR) != 0xfffffffc | 
 | 261 | 	    || b1dma_readl(card, AMCC_TXPTR) != 0xfffffffc) | 
 | 262 | 		return 2; | 
 | 263 |  | 
 | 264 | 	b1dma_writel(card, 0x0, AMCC_RXPTR); | 
 | 265 | 	b1dma_writel(card, 0x0, AMCC_TXPTR); | 
 | 266 | 	if (   b1dma_readl(card, AMCC_RXPTR) != 0x0 | 
 | 267 | 	    || b1dma_readl(card, AMCC_TXPTR) != 0x0) | 
 | 268 | 		return 3; | 
 | 269 |  | 
 | 270 | 	t1outp(card->port, 0x10, 0x00); | 
 | 271 | 	t1outp(card->port, 0x07, 0x00); | 
 | 272 | 	 | 
 | 273 | 	t1outp(card->port, 0x02, 0x02); | 
 | 274 | 	t1outp(card->port, 0x03, 0x02); | 
 | 275 |  | 
 | 276 | 	if (   (t1inp(card->port, 0x02) & 0xFE) != 0x02 | 
 | 277 | 	    || t1inp(card->port, 0x3) != 0x03) | 
 | 278 | 		return 4; | 
 | 279 |  | 
 | 280 | 	t1outp(card->port, 0x02, 0x00); | 
 | 281 | 	t1outp(card->port, 0x03, 0x00); | 
 | 282 |  | 
 | 283 | 	if (   (t1inp(card->port, 0x02) & 0xFE) != 0x00 | 
 | 284 | 	    || t1inp(card->port, 0x3) != 0x01) | 
 | 285 | 		return 5; | 
 | 286 |  | 
 | 287 | 	return 0; | 
 | 288 | } | 
 | 289 |  | 
 | 290 | int t1pci_detect(avmcard *card) | 
 | 291 | { | 
 | 292 | 	int ret; | 
 | 293 |  | 
 | 294 | 	if ((ret = b1dma_detect(card)) != 0) | 
 | 295 | 		return ret; | 
 | 296 | 	 | 
 | 297 | 	/* Transputer test */ | 
 | 298 | 	 | 
 | 299 | 	if (   WriteReg(card, 0x80001000, 0x11) != 0 | 
 | 300 | 	    || WriteReg(card, 0x80101000, 0x22) != 0 | 
 | 301 | 	    || WriteReg(card, 0x80201000, 0x33) != 0 | 
 | 302 | 	    || WriteReg(card, 0x80301000, 0x44) != 0) | 
 | 303 | 		return 6; | 
 | 304 |  | 
 | 305 | 	if (   ReadReg(card, 0x80001000) != 0x11 | 
 | 306 | 	    || ReadReg(card, 0x80101000) != 0x22 | 
 | 307 | 	    || ReadReg(card, 0x80201000) != 0x33 | 
 | 308 | 	    || ReadReg(card, 0x80301000) != 0x44) | 
 | 309 | 		return 7; | 
 | 310 |  | 
 | 311 | 	if (   WriteReg(card, 0x80001000, 0x55) != 0 | 
 | 312 | 	    || WriteReg(card, 0x80101000, 0x66) != 0 | 
 | 313 | 	    || WriteReg(card, 0x80201000, 0x77) != 0 | 
 | 314 | 	    || WriteReg(card, 0x80301000, 0x88) != 0) | 
 | 315 | 		return 8; | 
 | 316 |  | 
 | 317 | 	if (   ReadReg(card, 0x80001000) != 0x55 | 
 | 318 | 	    || ReadReg(card, 0x80101000) != 0x66 | 
 | 319 | 	    || ReadReg(card, 0x80201000) != 0x77 | 
 | 320 | 	    || ReadReg(card, 0x80301000) != 0x88) | 
 | 321 | 		return 9; | 
 | 322 |  | 
 | 323 | 	return 0; | 
 | 324 | } | 
 | 325 |  | 
 | 326 | int b1pciv4_detect(avmcard *card) | 
 | 327 | { | 
 | 328 | 	int ret, i; | 
 | 329 |  | 
 | 330 | 	if ((ret = b1dma_detect(card)) != 0) | 
 | 331 | 		return ret; | 
 | 332 | 	 | 
 | 333 | 	for (i=0; i < 5 ; i++) { | 
 | 334 | 		if (WriteReg(card, 0x80A00000, 0x21) != 0) | 
 | 335 | 			return 6; | 
 | 336 | 		if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01) | 
 | 337 | 			return 7; | 
 | 338 | 	} | 
 | 339 | 	for (i=0; i < 5 ; i++) { | 
 | 340 | 		if (WriteReg(card, 0x80A00000, 0x20) != 0) | 
 | 341 | 			return 8; | 
 | 342 | 		if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00) | 
 | 343 | 			return 9; | 
 | 344 | 	} | 
 | 345 | 	 | 
 | 346 | 	return 0; | 
 | 347 | } | 
 | 348 |  | 
 | 349 | static void b1dma_queue_tx(avmcard *card, struct sk_buff *skb) | 
 | 350 | { | 
 | 351 | 	unsigned long flags; | 
 | 352 |  | 
 | 353 | 	spin_lock_irqsave(&card->lock, flags); | 
 | 354 |  | 
 | 355 | 	skb_queue_tail(&card->dma->send_queue, skb); | 
 | 356 |  | 
 | 357 | 	if (!(card->csr & EN_TX_TC_INT)) { | 
 | 358 | 		b1dma_dispatch_tx(card); | 
 | 359 | 		b1dma_writel(card, card->csr, AMCC_INTCSR); | 
 | 360 | 	} | 
 | 361 |  | 
 | 362 | 	spin_unlock_irqrestore(&card->lock, flags); | 
 | 363 | } | 
 | 364 |  | 
 | 365 | /* ------------------------------------------------------------- */ | 
 | 366 |  | 
 | 367 | static void b1dma_dispatch_tx(avmcard *card) | 
 | 368 | { | 
 | 369 | 	avmcard_dmainfo *dma = card->dma; | 
 | 370 | 	struct sk_buff *skb; | 
 | 371 | 	u8 cmd, subcmd; | 
 | 372 | 	u16 len; | 
 | 373 | 	u32 txlen; | 
 | 374 | 	void *p; | 
 | 375 | 	 | 
 | 376 | 	skb = skb_dequeue(&dma->send_queue); | 
 | 377 |  | 
 | 378 | 	len = CAPIMSG_LEN(skb->data); | 
 | 379 |  | 
 | 380 | 	if (len) { | 
 | 381 | 		cmd = CAPIMSG_COMMAND(skb->data); | 
 | 382 | 		subcmd = CAPIMSG_SUBCOMMAND(skb->data); | 
 | 383 |  | 
 | 384 | 		p = dma->sendbuf.dmabuf; | 
 | 385 |  | 
 | 386 | 		if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { | 
 | 387 | 			u16 dlen = CAPIMSG_DATALEN(skb->data); | 
 | 388 | 			_put_byte(&p, SEND_DATA_B3_REQ); | 
 | 389 | 			_put_slice(&p, skb->data, len); | 
 | 390 | 			_put_slice(&p, skb->data + len, dlen); | 
 | 391 | 		} else { | 
 | 392 | 			_put_byte(&p, SEND_MESSAGE); | 
 | 393 | 			_put_slice(&p, skb->data, len); | 
 | 394 | 		} | 
 | 395 | 		txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf; | 
| Robert P. J. Day | 26fb5c5 | 2007-02-12 00:53:20 -0800 | [diff] [blame] | 396 | #ifdef AVM_B1DMA_DEBUG | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 397 | 		printk(KERN_DEBUG "tx: put msg len=%d\n", txlen); | 
 | 398 | #endif | 
 | 399 | 	} else { | 
 | 400 | 		txlen = skb->len-2; | 
| Robert P. J. Day | 26fb5c5 | 2007-02-12 00:53:20 -0800 | [diff] [blame] | 401 | #ifdef AVM_B1DMA_POLLDEBUG | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 402 | 		if (skb->data[2] == SEND_POLLACK) | 
 | 403 | 			printk(KERN_INFO "%s: send ack\n", card->name); | 
 | 404 | #endif | 
| Robert P. J. Day | 26fb5c5 | 2007-02-12 00:53:20 -0800 | [diff] [blame] | 405 | #ifdef AVM_B1DMA_DEBUG | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 406 | 		printk(KERN_DEBUG "tx: put 0x%x len=%d\n",  | 
 | 407 | 		       skb->data[2], txlen); | 
 | 408 | #endif | 
| Arnaldo Carvalho de Melo | d626f62 | 2007-03-27 18:55:52 -0300 | [diff] [blame] | 409 | 		skb_copy_from_linear_data_offset(skb, 2, dma->sendbuf.dmabuf, | 
 | 410 | 						 skb->len - 2); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 411 | 	} | 
 | 412 | 	txlen = (txlen + 3) & ~3; | 
 | 413 |  | 
 | 414 | 	b1dma_writel(card, dma->sendbuf.dmaaddr, AMCC_TXPTR); | 
 | 415 | 	b1dma_writel(card, txlen, AMCC_TXLEN); | 
 | 416 |  | 
 | 417 | 	card->csr |= EN_TX_TC_INT; | 
 | 418 |  | 
 | 419 | 	dev_kfree_skb_any(skb); | 
 | 420 | } | 
 | 421 |  | 
 | 422 | /* ------------------------------------------------------------- */ | 
 | 423 |  | 
 | 424 | static void queue_pollack(avmcard *card) | 
 | 425 | { | 
 | 426 | 	struct sk_buff *skb; | 
 | 427 | 	void *p; | 
 | 428 |  | 
 | 429 | 	skb = alloc_skb(3, GFP_ATOMIC); | 
 | 430 | 	if (!skb) { | 
 | 431 | 		printk(KERN_CRIT "%s: no memory, lost poll ack\n", | 
 | 432 | 					card->name); | 
 | 433 | 		return; | 
 | 434 | 	} | 
 | 435 | 	p = skb->data; | 
 | 436 | 	_put_byte(&p, 0); | 
 | 437 | 	_put_byte(&p, 0); | 
 | 438 | 	_put_byte(&p, SEND_POLLACK); | 
 | 439 | 	skb_put(skb, (u8 *)p - (u8 *)skb->data); | 
 | 440 |  | 
 | 441 | 	b1dma_queue_tx(card, skb); | 
 | 442 | } | 
 | 443 |  | 
 | 444 | /* ------------------------------------------------------------- */ | 
 | 445 |  | 
 | 446 | static void b1dma_handle_rx(avmcard *card) | 
 | 447 | { | 
 | 448 | 	avmctrl_info *cinfo = &card->ctrlinfo[0]; | 
 | 449 | 	avmcard_dmainfo *dma = card->dma; | 
 | 450 | 	struct capi_ctr *ctrl = &cinfo->capi_ctrl; | 
 | 451 | 	struct sk_buff *skb; | 
 | 452 | 	void *p = dma->recvbuf.dmabuf+4; | 
 | 453 | 	u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; | 
 | 454 | 	u8 b1cmd =  _get_byte(&p); | 
 | 455 |  | 
| Robert P. J. Day | 26fb5c5 | 2007-02-12 00:53:20 -0800 | [diff] [blame] | 456 | #ifdef AVM_B1DMA_DEBUG | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 457 | 	printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen); | 
 | 458 | #endif | 
 | 459 | 	 | 
 | 460 | 	switch (b1cmd) { | 
 | 461 | 	case RECEIVE_DATA_B3_IND: | 
 | 462 |  | 
 | 463 | 		ApplId = (unsigned) _get_word(&p); | 
 | 464 | 		MsgLen = _get_slice(&p, card->msgbuf); | 
 | 465 | 		DataB3Len = _get_slice(&p, card->databuf); | 
 | 466 |  | 
 | 467 | 		if (MsgLen < 30) { /* not CAPI 64Bit */ | 
 | 468 | 			memset(card->msgbuf+MsgLen, 0, 30-MsgLen); | 
 | 469 | 			MsgLen = 30; | 
 | 470 | 			CAPIMSG_SETLEN(card->msgbuf, 30); | 
 | 471 | 		} | 
 | 472 | 		if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) { | 
 | 473 | 			printk(KERN_ERR "%s: incoming packet dropped\n", | 
 | 474 | 					card->name); | 
 | 475 | 		} else { | 
 | 476 | 			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); | 
 | 477 | 			memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); | 
 | 478 | 			capi_ctr_handle_message(ctrl, ApplId, skb); | 
 | 479 | 		} | 
 | 480 | 		break; | 
 | 481 |  | 
 | 482 | 	case RECEIVE_MESSAGE: | 
 | 483 |  | 
 | 484 | 		ApplId = (unsigned) _get_word(&p); | 
 | 485 | 		MsgLen = _get_slice(&p, card->msgbuf); | 
 | 486 | 		if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { | 
 | 487 | 			printk(KERN_ERR "%s: incoming packet dropped\n", | 
 | 488 | 					card->name); | 
 | 489 | 		} else { | 
 | 490 | 			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 491 | 			if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) { | 
 | 492 | 				spin_lock(&card->lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 493 | 				capilib_data_b3_conf(&cinfo->ncci_head, ApplId, | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 494 | 					CAPIMSG_NCCI(skb->data), | 
 | 495 | 					CAPIMSG_MSGID(skb->data)); | 
 | 496 | 				spin_unlock(&card->lock); | 
 | 497 | 			} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 498 | 			capi_ctr_handle_message(ctrl, ApplId, skb); | 
 | 499 | 		} | 
 | 500 | 		break; | 
 | 501 |  | 
 | 502 | 	case RECEIVE_NEW_NCCI: | 
 | 503 |  | 
 | 504 | 		ApplId = _get_word(&p); | 
 | 505 | 		NCCI = _get_word(&p); | 
 | 506 | 		WindowSize = _get_word(&p); | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 507 | 		spin_lock(&card->lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 508 | 		capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize); | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 509 | 		spin_unlock(&card->lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 510 | 		break; | 
 | 511 |  | 
 | 512 | 	case RECEIVE_FREE_NCCI: | 
 | 513 |  | 
 | 514 | 		ApplId = _get_word(&p); | 
 | 515 | 		NCCI = _get_word(&p); | 
 | 516 |  | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 517 | 		if (NCCI != 0xffffffff) { | 
 | 518 | 			spin_lock(&card->lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 519 | 			capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI); | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 520 | 			spin_unlock(&card->lock); | 
 | 521 | 		} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 522 | 		break; | 
 | 523 |  | 
 | 524 | 	case RECEIVE_START: | 
| Robert P. J. Day | 26fb5c5 | 2007-02-12 00:53:20 -0800 | [diff] [blame] | 525 | #ifdef AVM_B1DMA_POLLDEBUG | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 526 | 		printk(KERN_INFO "%s: receive poll\n", card->name); | 
 | 527 | #endif | 
 | 528 | 		if (!suppress_pollack) | 
 | 529 | 			queue_pollack(card); | 
 | 530 | 		capi_ctr_resume_output(ctrl); | 
 | 531 | 		break; | 
 | 532 |  | 
 | 533 | 	case RECEIVE_STOP: | 
 | 534 | 		capi_ctr_suspend_output(ctrl); | 
 | 535 | 		break; | 
 | 536 |  | 
 | 537 | 	case RECEIVE_INIT: | 
 | 538 |  | 
 | 539 | 		cinfo->versionlen = _get_slice(&p, cinfo->versionbuf); | 
 | 540 | 		b1_parse_version(cinfo); | 
 | 541 | 		printk(KERN_INFO "%s: %s-card (%s) now active\n", | 
 | 542 | 		       card->name, | 
 | 543 | 		       cinfo->version[VER_CARDTYPE], | 
 | 544 | 		       cinfo->version[VER_DRIVER]); | 
 | 545 | 		capi_ctr_ready(ctrl); | 
 | 546 | 		break; | 
 | 547 |  | 
 | 548 | 	case RECEIVE_TASK_READY: | 
 | 549 | 		ApplId = (unsigned) _get_word(&p); | 
 | 550 | 		MsgLen = _get_slice(&p, card->msgbuf); | 
 | 551 | 		card->msgbuf[MsgLen] = 0; | 
 | 552 | 		while (    MsgLen > 0 | 
 | 553 | 		       && (   card->msgbuf[MsgLen-1] == '\n' | 
 | 554 | 			   || card->msgbuf[MsgLen-1] == '\r')) { | 
 | 555 | 			card->msgbuf[MsgLen-1] = 0; | 
 | 556 | 			MsgLen--; | 
 | 557 | 		} | 
 | 558 | 		printk(KERN_INFO "%s: task %d \"%s\" ready.\n", | 
 | 559 | 				card->name, ApplId, card->msgbuf); | 
 | 560 | 		break; | 
 | 561 |  | 
 | 562 | 	case RECEIVE_DEBUGMSG: | 
 | 563 | 		MsgLen = _get_slice(&p, card->msgbuf); | 
 | 564 | 		card->msgbuf[MsgLen] = 0; | 
 | 565 | 		while (    MsgLen > 0 | 
 | 566 | 		       && (   card->msgbuf[MsgLen-1] == '\n' | 
 | 567 | 			   || card->msgbuf[MsgLen-1] == '\r')) { | 
 | 568 | 			card->msgbuf[MsgLen-1] = 0; | 
 | 569 | 			MsgLen--; | 
 | 570 | 		} | 
 | 571 | 		printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); | 
 | 572 | 		break; | 
 | 573 |  | 
 | 574 | 	default: | 
 | 575 | 		printk(KERN_ERR "%s: b1dma_interrupt: 0x%x ???\n", | 
 | 576 | 				card->name, b1cmd); | 
 | 577 | 		return; | 
 | 578 | 	} | 
 | 579 | } | 
 | 580 |  | 
 | 581 | /* ------------------------------------------------------------- */ | 
 | 582 |  | 
 | 583 | static void b1dma_handle_interrupt(avmcard *card) | 
 | 584 | { | 
 | 585 | 	u32 status; | 
 | 586 | 	u32 newcsr; | 
 | 587 |  | 
 | 588 | 	spin_lock(&card->lock); | 
 | 589 |  | 
 | 590 | 	status = b1dma_readl(card, AMCC_INTCSR); | 
 | 591 | 	if ((status & ANY_S5933_INT) == 0) { | 
 | 592 | 		spin_unlock(&card->lock); | 
 | 593 | 		return; | 
 | 594 | 	} | 
 | 595 |  | 
 | 596 |         newcsr = card->csr | (status & ALL_INT); | 
 | 597 | 	if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT; | 
 | 598 | 	if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT; | 
 | 599 | 	b1dma_writel(card, newcsr, AMCC_INTCSR); | 
 | 600 |  | 
 | 601 | 	if ((status & RX_TC_INT) != 0) { | 
 | 602 | 		struct avmcard_dmainfo *dma = card->dma; | 
 | 603 | 		u32 rxlen; | 
 | 604 | 	   	if (card->dma->recvlen == 0) { | 
 | 605 | 	        	rxlen = b1dma_readl(card, AMCC_RXLEN); | 
 | 606 | 			if (rxlen == 0) { | 
 | 607 | 				dma->recvlen = *((u32 *)dma->recvbuf.dmabuf); | 
 | 608 | 				rxlen = (dma->recvlen + 3) & ~3; | 
 | 609 | 				b1dma_writel(card, dma->recvbuf.dmaaddr+4, AMCC_RXPTR); | 
 | 610 | 				b1dma_writel(card, rxlen, AMCC_RXLEN); | 
| Robert P. J. Day | 26fb5c5 | 2007-02-12 00:53:20 -0800 | [diff] [blame] | 611 | #ifdef AVM_B1DMA_DEBUG | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 612 | 			} else { | 
 | 613 | 				printk(KERN_ERR "%s: rx not complete (%d).\n", | 
 | 614 | 					card->name, rxlen); | 
 | 615 | #endif | 
 | 616 | 			} | 
 | 617 | 		} else { | 
 | 618 | 			spin_unlock(&card->lock); | 
 | 619 | 			b1dma_handle_rx(card); | 
 | 620 | 	   		dma->recvlen = 0; | 
 | 621 | 			spin_lock(&card->lock); | 
 | 622 | 			b1dma_writel(card, dma->recvbuf.dmaaddr, AMCC_RXPTR); | 
 | 623 | 			b1dma_writel(card, 4, AMCC_RXLEN); | 
 | 624 | 		} | 
 | 625 | 	} | 
 | 626 |  | 
 | 627 | 	if ((status & TX_TC_INT) != 0) { | 
 | 628 | 		if (skb_queue_empty(&card->dma->send_queue)) | 
 | 629 | 			card->csr &= ~EN_TX_TC_INT; | 
 | 630 | 		else | 
 | 631 | 			b1dma_dispatch_tx(card); | 
 | 632 | 	} | 
 | 633 | 	b1dma_writel(card, card->csr, AMCC_INTCSR); | 
 | 634 |  | 
 | 635 | 	spin_unlock(&card->lock); | 
 | 636 | } | 
 | 637 |  | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 638 | irqreturn_t b1dma_interrupt(int interrupt, void *devptr) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 639 | { | 
 | 640 | 	avmcard *card = devptr; | 
 | 641 |  | 
 | 642 | 	b1dma_handle_interrupt(card); | 
 | 643 | 	return IRQ_HANDLED; | 
 | 644 | } | 
 | 645 |  | 
 | 646 | /* ------------------------------------------------------------- */ | 
 | 647 |  | 
 | 648 | static int b1dma_loaded(avmcard *card) | 
 | 649 | { | 
 | 650 | 	unsigned long stop; | 
 | 651 | 	unsigned char ans; | 
 | 652 | 	unsigned long tout = 2; | 
 | 653 | 	unsigned int base = card->port; | 
 | 654 |  | 
 | 655 | 	for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { | 
 | 656 | 		if (b1_tx_empty(base)) | 
 | 657 | 			break; | 
 | 658 | 	} | 
 | 659 | 	if (!b1_tx_empty(base)) { | 
 | 660 | 		printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n", | 
 | 661 | 				card->name); | 
 | 662 | 		return 0; | 
 | 663 | 	} | 
 | 664 | 	b1_put_byte(base, SEND_POLLACK); | 
 | 665 | 	for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { | 
 | 666 | 		if (b1_rx_full(base)) { | 
 | 667 | 			if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) { | 
 | 668 | 				return 1; | 
 | 669 | 			} | 
 | 670 | 			printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans); | 
 | 671 | 			return 0; | 
 | 672 | 		} | 
 | 673 | 	} | 
 | 674 | 	printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name); | 
 | 675 | 	return 0; | 
 | 676 | } | 
 | 677 |  | 
 | 678 | /* ------------------------------------------------------------- */ | 
 | 679 |  | 
 | 680 | static void b1dma_send_init(avmcard *card) | 
 | 681 | { | 
 | 682 | 	struct sk_buff *skb; | 
 | 683 | 	void *p; | 
 | 684 |  | 
 | 685 | 	skb = alloc_skb(15, GFP_ATOMIC); | 
 | 686 | 	if (!skb) { | 
 | 687 | 		printk(KERN_CRIT "%s: no memory, lost register appl.\n", | 
 | 688 | 					card->name); | 
 | 689 | 		return; | 
 | 690 | 	} | 
 | 691 | 	p = skb->data; | 
 | 692 | 	_put_byte(&p, 0); | 
 | 693 | 	_put_byte(&p, 0); | 
 | 694 | 	_put_byte(&p, SEND_INIT); | 
 | 695 | 	_put_word(&p, CAPI_MAXAPPL); | 
 | 696 | 	_put_word(&p, AVM_NCCI_PER_CHANNEL*30); | 
 | 697 | 	_put_word(&p, card->cardnr - 1); | 
 | 698 | 	skb_put(skb, (u8 *)p - (u8 *)skb->data); | 
 | 699 |  | 
 | 700 | 	b1dma_queue_tx(card, skb); | 
 | 701 | } | 
 | 702 |  | 
 | 703 | int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) | 
 | 704 | { | 
 | 705 | 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | 
 | 706 | 	avmcard *card = cinfo->card; | 
 | 707 | 	int retval; | 
 | 708 |  | 
 | 709 | 	b1dma_reset(card); | 
 | 710 |  | 
 | 711 | 	if ((retval = b1_load_t4file(card, &data->firmware))) { | 
 | 712 | 		b1dma_reset(card); | 
 | 713 | 		printk(KERN_ERR "%s: failed to load t4file!!\n", | 
 | 714 | 					card->name); | 
 | 715 | 		return retval; | 
 | 716 | 	} | 
 | 717 |  | 
 | 718 | 	if (data->configuration.len > 0 && data->configuration.data) { | 
 | 719 | 		if ((retval = b1_load_config(card, &data->configuration))) { | 
 | 720 | 			b1dma_reset(card); | 
 | 721 | 			printk(KERN_ERR "%s: failed to load config!!\n", | 
 | 722 | 					card->name); | 
 | 723 | 			return retval; | 
 | 724 | 		} | 
 | 725 | 	} | 
 | 726 |  | 
 | 727 | 	if (!b1dma_loaded(card)) { | 
 | 728 | 		b1dma_reset(card); | 
 | 729 | 		printk(KERN_ERR "%s: failed to load t4file.\n", card->name); | 
 | 730 | 		return -EIO; | 
 | 731 | 	} | 
 | 732 |  | 
 | 733 | 	card->csr = AVM_FLAG; | 
 | 734 | 	b1dma_writel(card, card->csr, AMCC_INTCSR); | 
 | 735 | 	b1dma_writel(card, EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|A2P_HI_PRIORITY| | 
 | 736 | 		     P2A_HI_PRIORITY|RESET_A2P_FLAGS|RESET_P2A_FLAGS,  | 
 | 737 | 		     AMCC_MCSR); | 
 | 738 | 	t1outp(card->port, 0x07, 0x30); | 
 | 739 | 	t1outp(card->port, 0x10, 0xF0); | 
 | 740 |  | 
 | 741 | 	card->dma->recvlen = 0; | 
 | 742 | 	b1dma_writel(card, card->dma->recvbuf.dmaaddr, AMCC_RXPTR); | 
 | 743 | 	b1dma_writel(card, 4, AMCC_RXLEN); | 
 | 744 | 	card->csr |= EN_RX_TC_INT; | 
 | 745 | 	b1dma_writel(card, card->csr, AMCC_INTCSR); | 
 | 746 |  | 
 | 747 |         b1dma_send_init(card); | 
 | 748 |  | 
 | 749 | 	return 0; | 
 | 750 | } | 
 | 751 |  | 
 | 752 | void b1dma_reset_ctr(struct capi_ctr *ctrl) | 
 | 753 | { | 
 | 754 | 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | 
 | 755 | 	avmcard *card = cinfo->card; | 
 | 756 | 	unsigned long flags; | 
 | 757 |  | 
 | 758 | 	spin_lock_irqsave(&card->lock, flags); | 
 | 759 |  	b1dma_reset(card); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 760 |  | 
 | 761 | 	memset(cinfo->version, 0, sizeof(cinfo->version)); | 
 | 762 | 	capilib_release(&cinfo->ncci_head); | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 763 | 	spin_unlock_irqrestore(&card->lock, flags); | 
| Tilman Schmidt | 4e32997 | 2009-06-07 09:09:23 +0000 | [diff] [blame] | 764 | 	capi_ctr_down(ctrl); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 765 | } | 
 | 766 |  | 
 | 767 | /* ------------------------------------------------------------- */ | 
 | 768 |  | 
 | 769 | void b1dma_register_appl(struct capi_ctr *ctrl, | 
 | 770 | 				u16 appl, | 
 | 771 | 				capi_register_params *rp) | 
 | 772 | { | 
 | 773 | 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | 
 | 774 | 	avmcard *card = cinfo->card; | 
 | 775 | 	struct sk_buff *skb; | 
 | 776 | 	int want = rp->level3cnt; | 
 | 777 | 	int nconn; | 
 | 778 | 	void *p; | 
 | 779 |  | 
 | 780 | 	if (want > 0) nconn = want; | 
 | 781 | 	else nconn = ctrl->profile.nbchannel * -want; | 
 | 782 | 	if (nconn == 0) nconn = ctrl->profile.nbchannel; | 
 | 783 |  | 
 | 784 | 	skb = alloc_skb(23, GFP_ATOMIC); | 
 | 785 | 	if (!skb) { | 
 | 786 | 		printk(KERN_CRIT "%s: no memory, lost register appl.\n", | 
 | 787 | 					card->name); | 
 | 788 | 		return; | 
 | 789 | 	} | 
 | 790 | 	p = skb->data; | 
 | 791 | 	_put_byte(&p, 0); | 
 | 792 | 	_put_byte(&p, 0); | 
 | 793 | 	_put_byte(&p, SEND_REGISTER); | 
 | 794 | 	_put_word(&p, appl); | 
 | 795 | 	_put_word(&p, 1024 * (nconn+1)); | 
 | 796 | 	_put_word(&p, nconn); | 
 | 797 | 	_put_word(&p, rp->datablkcnt); | 
 | 798 | 	_put_word(&p, rp->datablklen); | 
 | 799 | 	skb_put(skb, (u8 *)p - (u8 *)skb->data); | 
 | 800 |  | 
 | 801 | 	b1dma_queue_tx(card, skb); | 
 | 802 | } | 
 | 803 |  | 
 | 804 | /* ------------------------------------------------------------- */ | 
 | 805 |  | 
 | 806 | void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl) | 
 | 807 | { | 
 | 808 | 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | 
 | 809 | 	avmcard *card = cinfo->card; | 
 | 810 | 	struct sk_buff *skb; | 
 | 811 | 	void *p; | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 812 | 	unsigned long flags; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 813 |  | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 814 | 	spin_lock_irqsave(&card->lock, flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 815 | 	capilib_release_appl(&cinfo->ncci_head, appl); | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 816 | 	spin_unlock_irqrestore(&card->lock, flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 817 |  | 
 | 818 | 	skb = alloc_skb(7, GFP_ATOMIC); | 
 | 819 | 	if (!skb) { | 
 | 820 | 		printk(KERN_CRIT "%s: no memory, lost release appl.\n", | 
 | 821 | 					card->name); | 
 | 822 | 		return; | 
 | 823 | 	} | 
 | 824 | 	p = skb->data; | 
 | 825 | 	_put_byte(&p, 0); | 
 | 826 | 	_put_byte(&p, 0); | 
 | 827 | 	_put_byte(&p, SEND_RELEASE); | 
 | 828 | 	_put_word(&p, appl); | 
 | 829 |  | 
 | 830 | 	skb_put(skb, (u8 *)p - (u8 *)skb->data); | 
 | 831 |  | 
 | 832 | 	b1dma_queue_tx(card, skb); | 
 | 833 | } | 
 | 834 |  | 
 | 835 | /* ------------------------------------------------------------- */ | 
 | 836 |  | 
 | 837 | u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) | 
 | 838 | { | 
 | 839 | 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | 
 | 840 | 	avmcard *card = cinfo->card; | 
 | 841 | 	u16 retval = CAPI_NOERROR; | 
 | 842 |  | 
 | 843 |  	if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 844 | 		unsigned long flags; | 
 | 845 | 		spin_lock_irqsave(&card->lock, flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 846 | 		retval = capilib_data_b3_req(&cinfo->ncci_head, | 
 | 847 | 					     CAPIMSG_APPID(skb->data), | 
 | 848 | 					     CAPIMSG_NCCI(skb->data), | 
 | 849 | 					     CAPIMSG_MSGID(skb->data)); | 
| Karsten Keil | 1e9c7813 | 2007-10-18 23:39:19 -0700 | [diff] [blame] | 850 | 		spin_unlock_irqrestore(&card->lock, flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 851 | 	} | 
 | 852 | 	if (retval == CAPI_NOERROR)  | 
 | 853 | 		b1dma_queue_tx(card, skb); | 
 | 854 |  | 
 | 855 | 	return retval; | 
 | 856 | } | 
 | 857 |  | 
 | 858 | /* ------------------------------------------------------------- */ | 
 | 859 |  | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 860 | static int b1dmactl_proc_show(struct seq_file *m, void *v) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 861 | { | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 862 | 	struct capi_ctr *ctrl = m->private; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 863 | 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | 
 | 864 | 	avmcard *card = cinfo->card; | 
 | 865 | 	u8 flag; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 866 | 	char *s; | 
 | 867 | 	u32 txoff, txlen, rxoff, rxlen, csr; | 
 | 868 | 	unsigned long flags; | 
 | 869 |  | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 870 | 	seq_printf(m, "%-16s %s\n", "name", card->name); | 
 | 871 | 	seq_printf(m, "%-16s 0x%x\n", "io", card->port); | 
 | 872 | 	seq_printf(m, "%-16s %d\n", "irq", card->irq); | 
 | 873 | 	seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 874 | 	switch (card->cardtype) { | 
 | 875 | 	case avm_b1isa: s = "B1 ISA"; break; | 
 | 876 | 	case avm_b1pci: s = "B1 PCI"; break; | 
 | 877 | 	case avm_b1pcmcia: s = "B1 PCMCIA"; break; | 
 | 878 | 	case avm_m1: s = "M1"; break; | 
 | 879 | 	case avm_m2: s = "M2"; break; | 
 | 880 | 	case avm_t1isa: s = "T1 ISA (HEMA)"; break; | 
 | 881 | 	case avm_t1pci: s = "T1 PCI"; break; | 
 | 882 | 	case avm_c4: s = "C4"; break; | 
 | 883 | 	case avm_c2: s = "C2"; break; | 
 | 884 | 	default: s = "???"; break; | 
 | 885 | 	} | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 886 | 	seq_printf(m, "%-16s %s\n", "type", s); | 
| Harvey Harrison | 8e44b29 | 2008-04-28 02:14:38 -0700 | [diff] [blame] | 887 | 	if ((s = cinfo->version[VER_DRIVER]) != NULL) | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 888 | 		seq_printf(m, "%-16s %s\n", "ver_driver", s); | 
| Harvey Harrison | 8e44b29 | 2008-04-28 02:14:38 -0700 | [diff] [blame] | 889 | 	if ((s = cinfo->version[VER_CARDTYPE]) != NULL) | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 890 | 		seq_printf(m, "%-16s %s\n", "ver_cardtype", s); | 
| Harvey Harrison | 8e44b29 | 2008-04-28 02:14:38 -0700 | [diff] [blame] | 891 | 	if ((s = cinfo->version[VER_SERIAL]) != NULL) | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 892 | 		seq_printf(m, "%-16s %s\n", "ver_serial", s); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 893 |  | 
 | 894 | 	if (card->cardtype != avm_m1) { | 
 | 895 |         	flag = ((u8 *)(ctrl->profile.manu))[3]; | 
 | 896 |         	if (flag) | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 897 | 			seq_printf(m, "%-16s%s%s%s%s%s%s%s\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 898 | 			"protocol", | 
 | 899 | 			(flag & 0x01) ? " DSS1" : "", | 
 | 900 | 			(flag & 0x02) ? " CT1" : "", | 
 | 901 | 			(flag & 0x04) ? " VN3" : "", | 
 | 902 | 			(flag & 0x08) ? " NI1" : "", | 
 | 903 | 			(flag & 0x10) ? " AUSTEL" : "", | 
 | 904 | 			(flag & 0x20) ? " ESS" : "", | 
 | 905 | 			(flag & 0x40) ? " 1TR6" : "" | 
 | 906 | 			); | 
 | 907 | 	} | 
 | 908 | 	if (card->cardtype != avm_m1) { | 
 | 909 |         	flag = ((u8 *)(ctrl->profile.manu))[5]; | 
 | 910 | 		if (flag) | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 911 | 			seq_printf(m, "%-16s%s%s%s%s\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 912 | 			"linetype", | 
 | 913 | 			(flag & 0x01) ? " point to point" : "", | 
 | 914 | 			(flag & 0x02) ? " point to multipoint" : "", | 
 | 915 | 			(flag & 0x08) ? " leased line without D-channel" : "", | 
 | 916 | 			(flag & 0x04) ? " leased line with D-channel" : "" | 
 | 917 | 			); | 
 | 918 | 	} | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 919 | 	seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 920 |  | 
 | 921 |  | 
 | 922 | 	spin_lock_irqsave(&card->lock, flags); | 
 | 923 |  | 
 | 924 | 	txoff = (dma_addr_t)b1dma_readl(card, AMCC_TXPTR)-card->dma->sendbuf.dmaaddr; | 
 | 925 | 	txlen = b1dma_readl(card, AMCC_TXLEN); | 
 | 926 |  | 
 | 927 | 	rxoff = (dma_addr_t)b1dma_readl(card, AMCC_RXPTR)-card->dma->recvbuf.dmaaddr; | 
 | 928 | 	rxlen = b1dma_readl(card, AMCC_RXLEN); | 
 | 929 |  | 
 | 930 | 	csr  = b1dma_readl(card, AMCC_INTCSR); | 
 | 931 |  | 
 | 932 | 	spin_unlock_irqrestore(&card->lock, flags); | 
 | 933 |  | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 934 | 	seq_printf(m, "%-16s 0x%lx\n", "csr (cached)", (unsigned long)card->csr); | 
 | 935 | 	seq_printf(m, "%-16s 0x%lx\n", "csr", (unsigned long)csr); | 
 | 936 | 	seq_printf(m, "%-16s %lu\n", "txoff", (unsigned long)txoff); | 
 | 937 | 	seq_printf(m, "%-16s %lu\n", "txlen", (unsigned long)txlen); | 
 | 938 | 	seq_printf(m, "%-16s %lu\n", "rxoff", (unsigned long)rxoff); | 
 | 939 | 	seq_printf(m, "%-16s %lu\n", "rxlen", (unsigned long)rxlen); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 940 |  | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 941 | 	return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 942 | } | 
 | 943 |  | 
| Alexey Dobriyan | 9a58a80 | 2010-01-14 03:10:54 -0800 | [diff] [blame] | 944 | static int b1dmactl_proc_open(struct inode *inode, struct file *file) | 
 | 945 | { | 
 | 946 | 	return single_open(file, b1dmactl_proc_show, PDE(inode)->data); | 
 | 947 | } | 
 | 948 |  | 
 | 949 | const struct file_operations b1dmactl_proc_fops = { | 
 | 950 | 	.owner		= THIS_MODULE, | 
 | 951 | 	.open		= b1dmactl_proc_open, | 
 | 952 | 	.read		= seq_read, | 
 | 953 | 	.llseek		= seq_lseek, | 
 | 954 | 	.release	= single_release, | 
 | 955 | }; | 
 | 956 | EXPORT_SYMBOL(b1dmactl_proc_fops); | 
 | 957 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 958 | /* ------------------------------------------------------------- */ | 
 | 959 |  | 
 | 960 | EXPORT_SYMBOL(b1dma_reset); | 
 | 961 | EXPORT_SYMBOL(t1pci_detect); | 
 | 962 | EXPORT_SYMBOL(b1pciv4_detect); | 
 | 963 | EXPORT_SYMBOL(b1dma_interrupt); | 
 | 964 |  | 
 | 965 | EXPORT_SYMBOL(b1dma_load_firmware); | 
 | 966 | EXPORT_SYMBOL(b1dma_reset_ctr); | 
 | 967 | EXPORT_SYMBOL(b1dma_register_appl); | 
 | 968 | EXPORT_SYMBOL(b1dma_release_appl); | 
 | 969 | EXPORT_SYMBOL(b1dma_send_message); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 970 |  | 
| Adrian Bunk | 08e5153 | 2005-06-25 14:58:37 -0700 | [diff] [blame] | 971 | static int __init b1dma_init(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 972 | { | 
 | 973 | 	char *p; | 
 | 974 | 	char rev[32]; | 
 | 975 |  | 
| Harvey Harrison | 8e44b29 | 2008-04-28 02:14:38 -0700 | [diff] [blame] | 976 | 	if ((p = strchr(revision, ':')) != NULL && p[1]) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 977 | 		strlcpy(rev, p + 2, sizeof(rev)); | 
| Harvey Harrison | 8e44b29 | 2008-04-28 02:14:38 -0700 | [diff] [blame] | 978 | 		if ((p = strchr(rev, '$')) != NULL && p > rev) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 979 | 		   *(p-1) = 0; | 
 | 980 | 	} else | 
 | 981 | 		strcpy(rev, "1.0"); | 
 | 982 |  | 
 | 983 | 	printk(KERN_INFO "b1dma: revision %s\n", rev); | 
 | 984 |  | 
 | 985 | 	return 0; | 
 | 986 | } | 
 | 987 |  | 
| Adrian Bunk | 08e5153 | 2005-06-25 14:58:37 -0700 | [diff] [blame] | 988 | static void __exit b1dma_exit(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 989 | { | 
 | 990 | } | 
 | 991 |  | 
 | 992 | module_init(b1dma_init); | 
 | 993 | module_exit(b1dma_exit); |