11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* $Id: c4.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
2475be4d85a274d0961593db41cf85689db1d583cJoe Perches *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Module for AVM C4 & C2 card.
4475be4d85a274d0961593db41cf85689db1d583cJoe Perches *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 1999 by Carsten Paeth <calle@calle.de>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
149a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan#include <linux/proc_fs.h>
159a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan#include <linux/seq_file.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/capi.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernelcapi.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
255a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/isdn/capicmd.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/isdn/capiutil.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/isdn/capilli.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "avmcard.h"
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3426fb5c5810afa0d8209ceff7cb267398be53829dRobert P. J. Day#undef AVM_C4_DEBUG
3526fb5c5810afa0d8209ceff7cb267398be53829dRobert P. J. Day#undef AVM_C4_POLLDEBUG
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *revision = "$Revision: 1.1.2.2 $";
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4390ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool suppress_pollack;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id c4_pci_tbl[] = {
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, 0, 0, (unsigned long)4 },
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C2, 0, 0, (unsigned long)2 },
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }			/* Terminating entry */
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, c4_pci_tbl);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("CAPI4Linux: Driver for AVM C2/C4 cards");
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Carsten Paeth");
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
558d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(suppress_pollack, bool, 0);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void c4_dispatch_tx(avmcard *card);
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DC21285_DRAM_A0MR	0x40000000
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DC21285_DRAM_A1MR	0x40004000
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DC21285_DRAM_A2MR	0x40008000
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DC21285_DRAM_A3MR	0x4000C000
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	CAS_OFFSET	0x88
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DC21285_ARMCSR_BASE	0x42000000
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	PCI_OUT_INT_STATUS	0x30
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	PCI_OUT_INT_MASK	0x34
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MAILBOX_0		0x50
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MAILBOX_1		0x54
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MAILBOX_2		0x58
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MAILBOX_3		0x5C
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DOORBELL		0x60
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DOORBELL_SETUP		0x64
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CHAN_1_CONTROL		0x90
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CHAN_2_CONTROL		0xB0
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRAM_TIMING		0x10C
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRAM_ADDR_SIZE_0	0x110
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRAM_ADDR_SIZE_1	0x114
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRAM_ADDR_SIZE_2	0x118
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRAM_ADDR_SIZE_3	0x11C
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	SA_CONTROL		0x13C
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	XBUS_CYCLE		0x148
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	XBUS_STROBE		0x14C
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DBELL_PCI_MASK		0x150
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBELL_SA_MASK		0x154
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SDRAM_SIZE		0x1000000
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MBOX_PEEK_POKE		MAILBOX_0
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBELL_ADDR		0x01
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBELL_DATA		0x02
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBELL_RNWR		0x40
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBELL_INIT		0x80
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MBOX_UP_ADDR		MAILBOX_0
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MBOX_UP_LEN		MAILBOX_1
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MBOX_DOWN_ADDR		MAILBOX_2
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MBOX_DOWN_LEN		MAILBOX_3
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DBELL_UP_HOST		0x00000100
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DBELL_UP_ARM		0x00000200
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DBELL_DOWN_HOST		0x00000400
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DBELL_DOWN_ARM		0x00000800
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DBELL_RESET_HOST	0x40000000
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DBELL_RESET_ARM		0x80000000
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DRAM_TIMING_DEF		0x001A01A5
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRAM_AD_SZ_DEF0		0x00000045
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRAM_AD_SZ_NULL		0x00000000
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SA_CTL_ALLRIGHT		0x64AA0271
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	INIT_XBUS_CYCLE		0x100016DB
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	INIT_XBUS_STROBE	0xF1F1F1F1
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
132475be4d85a274d0961593db41cf85689db1d583cJoe Perches#define	RESET_TIMEOUT		(15 * HZ)	/* 15 sec */
133475be4d85a274d0961593db41cf85689db1d583cJoe Perches#define	PEEK_POKE_TIMEOUT	(HZ / 10)	/* 0.1 sec */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define c4outmeml(addr, value)	writel(value, addr)
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define c4inmeml(addr)	readl(addr)
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define c4outmemw(addr, value)	writew(value, addr)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define c4inmemw(addr)	readw(addr)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define c4outmemb(addr, value)	writeb(value, addr)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define c4inmemb(addr)	readb(addr)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int wait_for_doorbell(avmcard *card, unsigned long t)
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long stop;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stop = jiffies + t;
151475be4d85a274d0961593db41cf85689db1d583cJoe Perches	while (c4inmeml(card->mbase + DOORBELL) != 0xffffffff) {
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!time_before(jiffies, stop))
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -1;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mb();
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int c4_poke(avmcard *card,  unsigned long off, unsigned long value)
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
162475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (wait_for_doorbell(card, HZ / 10) < 0)
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
165475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + MBOX_PEEK_POKE, off);
166475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + DOORBELL, DBELL_ADDR);
167475be4d85a274d0961593db41cf85689db1d583cJoe Perches
168475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (wait_for_doorbell(card, HZ / 10) < 0)
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + MBOX_PEEK_POKE, value);
172475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + DOORBELL, DBELL_DATA | DBELL_ADDR);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int c4_peek(avmcard *card,  unsigned long off, unsigned long *valuep)
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
179475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (wait_for_doorbell(card, HZ / 10) < 0)
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
182475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + MBOX_PEEK_POKE, off);
183475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + DOORBELL, DBELL_RNWR | DBELL_ADDR);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
185475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (wait_for_doorbell(card, HZ / 10) < 0)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
188475be4d85a274d0961593db41cf85689db1d583cJoe Perches	*valuep = c4inmeml(card->mbase + MBOX_PEEK_POKE);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
195475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic int c4_load_t4file(avmcard *card, capiloaddatapart *t4file)
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *dp;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int left;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 loadoff = 0;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dp = t4file->data;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	left = t4file->len;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (left >= sizeof(u32)) {
205475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (t4file->user) {
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (copy_from_user(&val, dp, sizeof(val)))
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EFAULT;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(&val, dp, sizeof(val));
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (c4_poke(card, loadoff, val)) {
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "%s: corrupted firmware file ?\n",
213475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       card->name);
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		left -= sizeof(u32);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dp += sizeof(u32);
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		loadoff += sizeof(u32);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (left) {
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = 0;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (t4file->user) {
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (copy_from_user(&val, dp, left))
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EFAULT;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(&val, dp, left);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (c4_poke(card, loadoff, val)) {
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "%s: corrupted firmware file ?\n",
230475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       card->name);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void _put_byte(void **pp, u8 val)
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 *s = *pp;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*s++ = val;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*pp = s;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void _put_word(void **pp, u32 val)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 *s = *pp;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*s++ = val & 0xff;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*s++ = (val >> 8) & 0xff;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*s++ = (val >> 16) & 0xff;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*s++ = (val >> 24) & 0xff;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*pp = s;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned i = len;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_word(pp, i);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (i-- > 0)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_byte(pp, *dp++);
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 _get_byte(void **pp)
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 *s = *pp;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 val;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = *s++;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*pp = s;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return val;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 _get_word(void **pp)
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 *s = *pp;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 val;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = *s++;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val |= (*s++ << 8);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val |= (*s++ << 16);
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val |= (*s++ << 24);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*pp = s;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return val;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 _get_slice(void **pp, unsigned char *dp)
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int len, i;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = i = _get_word(pp);
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (i-- > 0) *dp++ = _get_byte(pp);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void c4_reset(avmcard *card)
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long stop;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
300475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + DOORBELL, DBELL_RESET_ARM);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
302475be4d85a274d0961593db41cf85689db1d583cJoe Perches	stop = jiffies + HZ * 10;
303475be4d85a274d0961593db41cf85689db1d583cJoe Perches	while (c4inmeml(card->mbase + DOORBELL) != 0xffffffff) {
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!time_before(jiffies, stop))
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
306475be4d85a274d0961593db41cf85689db1d583cJoe Perches		c4outmeml(card->mbase + DOORBELL, DBELL_ADDR);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mb();
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int c4_detect(avmcard *card)
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long stop, dummy;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
320475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + PCI_OUT_INT_MASK, 0x0c);
321475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4inmeml(card->mbase + PCI_OUT_INT_MASK) != 0x0c)
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return	1;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
324475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + DOORBELL, DBELL_RESET_ARM);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
326475be4d85a274d0961593db41cf85689db1d583cJoe Perches	stop = jiffies + HZ * 10;
327475be4d85a274d0961593db41cf85689db1d583cJoe Perches	while (c4inmeml(card->mbase + DOORBELL) != 0xffffffff) {
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!time_before(jiffies, stop))
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 2;
330475be4d85a274d0961593db41cf85689db1d583cJoe Perches		c4outmeml(card->mbase + DOORBELL, DBELL_ADDR);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mb();
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
337475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + MAILBOX_0, 0x55aa55aa);
338475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4inmeml(card->mbase + MAILBOX_0) != 0x55aa55aa) return 3;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
340475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + MAILBOX_0, 0xaa55aa55);
341475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4inmeml(card->mbase + MAILBOX_0) != 0xaa55aa55) return 4;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
343475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_ARMCSR_BASE + DBELL_SA_MASK, 0)) return 5;
344475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_ARMCSR_BASE + DBELL_PCI_MASK, 0)) return 6;
345475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_ARMCSR_BASE + SA_CONTROL, SA_CTL_ALLRIGHT))
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 7;
347475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_ARMCSR_BASE + XBUS_CYCLE, INIT_XBUS_CYCLE))
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 8;
349475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_ARMCSR_BASE + XBUS_STROBE, INIT_XBUS_STROBE))
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 8;
351475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_TIMING, 0)) return 9;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
353475be4d85a274d0961593db41cf85689db1d583cJoe Perches	mdelay(1);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (c4_peek(card, DC21285_DRAM_A2MR, &dummy)) return 12;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (c4_peek(card, DC21285_DRAM_A3MR, &dummy)) return 13;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
360475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_DRAM_A0MR + CAS_OFFSET, 0)) return 14;
361475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_DRAM_A1MR + CAS_OFFSET, 0)) return 15;
362475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_DRAM_A2MR + CAS_OFFSET, 0)) return 16;
363475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_DRAM_A3MR + CAS_OFFSET, 0)) return 17;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
365475be4d85a274d0961593db41cf85689db1d583cJoe Perches	mdelay(1);
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
367475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_TIMING, DRAM_TIMING_DEF))
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 18;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
370475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_ADDR_SIZE_0, DRAM_AD_SZ_DEF0))
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 19;
372475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_ADDR_SIZE_1, DRAM_AD_SZ_NULL))
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 20;
374475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_ADDR_SIZE_2, DRAM_AD_SZ_NULL))
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 21;
376475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_ADDR_SIZE_3, DRAM_AD_SZ_NULL))
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 22;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Transputer test */
380475be4d85a274d0961593db41cf85689db1d583cJoe Perches
381475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, 0x000000, 0x11111111)
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    || c4_poke(card, 0x400000, 0x22222222)
383475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       || c4_poke(card, 0x800000, 0x33333333)
384475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       || c4_poke(card, 0xC00000, 0x44444444))
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 23;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
387475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_peek(card, 0x000000, &dummy) || dummy != 0x11111111
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    || c4_peek(card, 0x400000, &dummy) || dummy != 0x22222222
389475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       || c4_peek(card, 0x800000, &dummy) || dummy != 0x33333333
390475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       || c4_peek(card, 0xC00000, &dummy) || dummy != 0x44444444)
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 24;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
393475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_poke(card, 0x000000, 0x55555555)
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    || c4_poke(card, 0x400000, 0x66666666)
395475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       || c4_poke(card, 0x800000, 0x77777777)
396475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       || c4_poke(card, 0xC00000, 0x88888888))
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 25;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
399475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (c4_peek(card, 0x000000, &dummy) || dummy != 0x55555555
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    || c4_peek(card, 0x400000, &dummy) || dummy != 0x66666666
401475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       || c4_peek(card, 0x800000, &dummy) || dummy != 0x77777777
402475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       || c4_peek(card, 0xC00000, &dummy) || dummy != 0x88888888)
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 26;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void c4_dispatch_tx(avmcard *card)
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard_dmainfo *dma = card->dma;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 cmd, subcmd;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 len;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 txlen;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *p;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (card->csr & DBELL_DOWN_ARM) { /* tx busy */
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = skb_dequeue(&dma->send_queue);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb) {
42626fb5c5810afa0d8209ceff7cb267398be53829dRobert P. J. Day#ifdef AVM_C4_DEBUG
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_DEBUG "%s: tx underrun\n", card->name);
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = CAPIMSG_LEN(skb->data);
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len) {
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd = CAPIMSG_COMMAND(skb->data);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		subcmd = CAPIMSG_SUBCOMMAND(skb->data);
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p = dma->sendbuf.dmabuf;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u16 dlen = CAPIMSG_DATALEN(skb->data);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_put_byte(&p, SEND_DATA_B3_REQ);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_put_slice(&p, skb->data, len);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_put_slice(&p, skb->data + len, dlen);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_put_byte(&p, SEND_MESSAGE);
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_put_slice(&p, skb->data, len);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;
45026fb5c5810afa0d8209ceff7cb267398be53829dRobert P. J. Day#ifdef AVM_C4_DEBUG
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
454475be4d85a274d0961593db41cf85689db1d583cJoe Perches		txlen = skb->len - 2;
45526fb5c5810afa0d8209ceff7cb267398be53829dRobert P. J. Day#ifdef AVM_C4_POLLDEBUG
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb->data[2] == SEND_POLLACK)
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_INFO "%s: ack to c4\n", card->name);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
45926fb5c5810afa0d8209ceff7cb267398be53829dRobert P. J. Day#ifdef AVM_C4_DEBUG
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n",
461475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       card->name, skb->data[2], txlen);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
463d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo		skb_copy_from_linear_data_offset(skb, 2, dma->sendbuf.dmabuf,
464d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo						 skb->len - 2);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	txlen = (txlen + 3) & ~3;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
468475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + MBOX_DOWN_ADDR, dma->sendbuf.dmaaddr);
469475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + MBOX_DOWN_LEN, txlen);
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->csr |= DBELL_DOWN_ARM;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
473475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + DOORBELL, DBELL_DOWN_ARM);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb_any(skb);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void queue_pollack(avmcard *card)
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *p;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(3, GFP_ATOMIC);
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb) {
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "%s: no memory, lost poll ack\n",
488475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       card->name);
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p = skb->data;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, 0);
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, 0);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, SEND_POLLACK);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb, (u8 *)p - (u8 *)skb->data);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_tail(&card->dma->send_queue, skb);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c4_dispatch_tx(card);
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void c4_handle_rx(avmcard *card)
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard_dmainfo *dma = card->dma;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct capi_ctr *ctrl;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmctrl_info *cinfo;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *p = dma->recvbuf.dmabuf;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 b1cmd =  _get_byte(&p);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 cidx;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51526fb5c5810afa0d8209ceff7cb267398be53829dRobert P. J. Day#ifdef AVM_C4_DEBUG
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name,
517475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       b1cmd, (unsigned long)dma->recvlen);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
519475be4d85a274d0961593db41cf85689db1d583cJoe Perches
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (b1cmd) {
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RECEIVE_DATA_B3_IND:
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ApplId = (unsigned) _get_word(&p);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MsgLen = _get_slice(&p, card->msgbuf);
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DataB3Len = _get_slice(&p, card->databuf);
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cidx >= card->nlogcontr) cidx = 0;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctrl = &card->ctrlinfo[cidx].capi_ctrl;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (MsgLen < 30) { /* not CAPI 64Bit */
531475be4d85a274d0961593db41cf85689db1d583cJoe Perches			memset(card->msgbuf + MsgLen, 0, 30 - MsgLen);
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			MsgLen = 30;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			CAPIMSG_SETLEN(card->msgbuf, 30);
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
535475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) {
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "%s: incoming packet dropped\n",
537475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       card->name);
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			capi_ctr_handle_message(ctrl, ApplId, skb);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RECEIVE_MESSAGE:
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ApplId = (unsigned) _get_word(&p);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MsgLen = _get_slice(&p, card->msgbuf);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cidx >= card->nlogcontr) cidx = 0;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo = &card->ctrlinfo[cidx];
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctrl = &card->ctrlinfo[cidx].capi_ctrl;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "%s: incoming packet dropped\n",
556475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       card->name);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						     CAPIMSG_NCCI(skb->data),
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						     CAPIMSG_MSGID(skb->data));
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			capi_ctr_handle_message(ctrl, ApplId, skb);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RECEIVE_NEW_NCCI:
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ApplId = _get_word(&p);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		NCCI = _get_word(&p);
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		WindowSize = _get_word(&p);
573475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cidx = (NCCI & 0x7f) - card->cardnr;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cidx >= card->nlogcontr) cidx = 0;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		capilib_new_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI, WindowSize);
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RECEIVE_FREE_NCCI:
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ApplId = _get_word(&p);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		NCCI = _get_word(&p);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (NCCI != 0xffffffff) {
586475be4d85a274d0961593db41cf85689db1d583cJoe Perches			cidx = (NCCI & 0x7f) - card->cardnr;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cidx >= card->nlogcontr) cidx = 0;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			capilib_free_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RECEIVE_START:
59326fb5c5810afa0d8209ceff7cb267398be53829dRobert P. J. Day#ifdef AVM_C4_POLLDEBUG
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "%s: poll from c4\n", card->name);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!suppress_pollack)
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			queue_pollack(card);
598475be4d85a274d0961593db41cf85689db1d583cJoe Perches		for (cidx = 0; cidx < card->nr_controllers; cidx++) {
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ctrl = &card->ctrlinfo[cidx].capi_ctrl;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			capi_ctr_resume_output(ctrl);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RECEIVE_STOP:
605475be4d85a274d0961593db41cf85689db1d583cJoe Perches		for (cidx = 0; cidx < card->nr_controllers; cidx++) {
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ctrl = &card->ctrlinfo[cidx].capi_ctrl;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			capi_ctr_suspend_output(ctrl);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RECEIVE_INIT:
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
613475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cidx = card->nlogcontr;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cidx >= card->nr_controllers) {
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "%s: card with %d controllers ??\n",
616475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       card->name, cidx + 1);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
619475be4d85a274d0961593db41cf85689db1d583cJoe Perches		card->nlogcontr++;
620475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cinfo = &card->ctrlinfo[cidx];
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctrl = &cinfo->capi_ctrl;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		b1_parse_version(cinfo);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "%s: %s-card (%s) now active\n",
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       card->name,
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cinfo->version[VER_CARDTYPE],
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cinfo->version[VER_DRIVER]);
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		capi_ctr_ready(&cinfo->capi_ctrl);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RECEIVE_TASK_READY:
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ApplId = (unsigned) _get_word(&p);
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MsgLen = _get_slice(&p, card->msgbuf);
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		card->msgbuf[MsgLen] = 0;
635475be4d85a274d0961593db41cf85689db1d583cJoe Perches		while (MsgLen > 0
636475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       && (card->msgbuf[MsgLen - 1] == '\n'
637475be4d85a274d0961593db41cf85689db1d583cJoe Perches			   || card->msgbuf[MsgLen - 1] == '\r')) {
638475be4d85a274d0961593db41cf85689db1d583cJoe Perches			card->msgbuf[MsgLen - 1] = 0;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			MsgLen--;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
642475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       card->name, ApplId, card->msgbuf);
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RECEIVE_DEBUGMSG:
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MsgLen = _get_slice(&p, card->msgbuf);
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		card->msgbuf[MsgLen] = 0;
648475be4d85a274d0961593db41cf85689db1d583cJoe Perches		while (MsgLen > 0
649475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       && (card->msgbuf[MsgLen - 1] == '\n'
650475be4d85a274d0961593db41cf85689db1d583cJoe Perches			   || card->msgbuf[MsgLen - 1] == '\r')) {
651475be4d85a274d0961593db41cf85689db1d583cJoe Perches			card->msgbuf[MsgLen - 1] = 0;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			MsgLen--;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: c4_interrupt: 0x%x ???\n",
659475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       card->name, b1cmd);
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t c4_handle_interrupt(avmcard *card)
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 status;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&card->lock, flags);
672475be4d85a274d0961593db41cf85689db1d583cJoe Perches	status = c4inmeml(card->mbase + DOORBELL);
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & DBELL_RESET_HOST) {
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u_int i;
676475be4d85a274d0961593db41cf85689db1d583cJoe Perches		c4outmeml(card->mbase + PCI_OUT_INT_MASK, 0x0c);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&card->lock, flags);
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (card->nlogcontr == 0)
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return IRQ_HANDLED;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: unexpected reset\n", card->name);
681475be4d85a274d0961593db41cf85689db1d583cJoe Perches		for (i = 0; i < card->nr_controllers; i++) {
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			avmctrl_info *cinfo = &card->ctrlinfo[i];
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memset(cinfo->version, 0, sizeof(cinfo->version));
684eac141deb4f0136059372923ac3f0eab0bef5bceKarsten Keil			spin_lock_irqsave(&card->lock, flags);
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			capilib_release(&cinfo->ncci_head);
686eac141deb4f0136059372923ac3f0eab0bef5bceKarsten Keil			spin_unlock_irqrestore(&card->lock, flags);
6874e329972052c3649367b91de783f6293b8653cb2Tilman Schmidt			capi_ctr_down(&cinfo->capi_ctrl);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		card->nlogcontr = 0;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_HANDLED;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status &= (DBELL_UP_HOST | DBELL_DOWN_HOST);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!status) {
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&card->lock, flags);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_HANDLED;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
698475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + DOORBELL, status);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((status & DBELL_UP_HOST) != 0) {
701475be4d85a274d0961593db41cf85689db1d583cJoe Perches		card->dma->recvlen = c4inmeml(card->mbase + MBOX_UP_LEN);
702475be4d85a274d0961593db41cf85689db1d583cJoe Perches		c4outmeml(card->mbase + MBOX_UP_LEN, 0);
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		c4_handle_rx(card);
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		card->dma->recvlen = 0;
705475be4d85a274d0961593db41cf85689db1d583cJoe Perches		c4outmeml(card->mbase + MBOX_UP_LEN, card->dma->recvbuf.size);
706475be4d85a274d0961593db41cf85689db1d583cJoe Perches		c4outmeml(card->mbase + DOORBELL, DBELL_UP_ARM);
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((status & DBELL_DOWN_HOST) != 0) {
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		card->csr &= ~DBELL_DOWN_ARM;
711475be4d85a274d0961593db41cf85689db1d583cJoe Perches		c4_dispatch_tx(card);
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (card->csr & DBELL_DOWN_HOST) {
713475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (c4inmeml(card->mbase + MBOX_DOWN_LEN) == 0) {
714475be4d85a274d0961593db41cf85689db1d583cJoe Perches			card->csr &= ~DBELL_DOWN_ARM;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			c4_dispatch_tx(card);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&card->lock, flags);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7227d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t c4_interrupt(int interrupt, void *devptr)
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard *card = devptr;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return c4_handle_interrupt(card);
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void c4_send_init(avmcard *card)
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *p;
7351ccfd63367c1a6aaf8b33943f18856dde85f2f0bKarsten Keil	unsigned long flags;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = alloc_skb(15, GFP_ATOMIC);
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb) {
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "%s: no memory, lost register appl.\n",
740475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       card->name);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p = skb->data;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, 0);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, 0);
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, SEND_INIT);
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_word(&p, CAPI_MAXAPPL);
748475be4d85a274d0961593db41cf85689db1d583cJoe Perches	_put_word(&p, AVM_NCCI_PER_CHANNEL * 30);
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_word(&p, card->cardnr - 1);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb, (u8 *)p - (u8 *)skb->data);
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_tail(&card->dma->send_queue, skb);
7531ccfd63367c1a6aaf8b33943f18856dde85f2f0bKarsten Keil	spin_lock_irqsave(&card->lock, flags);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c4_dispatch_tx(card);
7551ccfd63367c1a6aaf8b33943f18856dde85f2f0bKarsten Keil	spin_unlock_irqrestore(&card->lock, flags);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int queue_sendconfigword(avmcard *card, u32 val)
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
7611ccfd63367c1a6aaf8b33943f18856dde85f2f0bKarsten Keil	unsigned long flags;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *p;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
764475be4d85a274d0961593db41cf85689db1d583cJoe Perches	skb = alloc_skb(3 + 4, GFP_ATOMIC);
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb) {
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "%s: no memory, send config\n",
767475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       card->name);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p = skb->data;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, 0);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, 0);
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, SEND_CONFIG);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_word(&p, val);
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb, (u8 *)p - (u8 *)skb->data);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_tail(&card->dma->send_queue, skb);
7781ccfd63367c1a6aaf8b33943f18856dde85f2f0bKarsten Keil	spin_lock_irqsave(&card->lock, flags);
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c4_dispatch_tx(card);
7801ccfd63367c1a6aaf8b33943f18856dde85f2f0bKarsten Keil	spin_unlock_irqrestore(&card->lock, flags);
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int queue_sendconfig(avmcard *card, char cval[4])
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *p;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
790475be4d85a274d0961593db41cf85689db1d583cJoe Perches	skb = alloc_skb(3 + 4, GFP_ATOMIC);
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb) {
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "%s: no memory, send config\n",
793475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       card->name);
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p = skb->data;
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, 0);
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, 0);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, SEND_CONFIG);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, cval[0]);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, cval[1]);
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, cval[2]);
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_put_byte(&p, cval[3]);
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb, (u8 *)p - (u8 *)skb->data);
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_tail(&card->dma->send_queue, skb);
807475be4d85a274d0961593db41cf85689db1d583cJoe Perches
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&card->lock, flags);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c4_dispatch_tx(card);
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&card->lock, flags);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
814475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic int c4_send_config(avmcard *card, capiloaddatapart *config)
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 val[4];
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *dp;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int left;
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
820475be4d85a274d0961593db41cf85689db1d583cJoe Perches
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((retval = queue_sendconfigword(card, 1)) != 0)
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((retval = queue_sendconfigword(card, config->len)) != 0)
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dp = config->data;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	left = config->len;
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (left >= sizeof(u32)) {
829475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (config->user) {
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (copy_from_user(val, dp, sizeof(val)))
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EFAULT;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(val, dp, sizeof(val));
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((retval = queue_sendconfig(card, val)) != 0)
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return retval;
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		left -= sizeof(val);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dp += sizeof(val);
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (left) {
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset(val, 0, sizeof(val));
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (config->user) {
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (copy_from_user(&val, dp, left))
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EFAULT;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(&val, dp, left);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((retval = queue_sendconfig(card, val)) != 0)
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return retval;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard *card = cinfo->card;
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((retval = c4_load_t4file(card, &data->firmware))) {
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: failed to load t4file!!\n",
863475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       card->name);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		c4_reset(card);
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->csr = 0;
869475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + MBOX_UP_LEN, 0);
870475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + MBOX_DOWN_LEN, 0);
871475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + DOORBELL, DBELL_INIT);
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mdelay(1);
873475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + DOORBELL,
874475be4d85a274d0961593db41cf85689db1d583cJoe Perches		  DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST);
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
876475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + PCI_OUT_INT_MASK, 0x08);
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->dma->recvlen = 0;
879475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + MBOX_UP_ADDR, card->dma->recvbuf.dmaaddr);
880475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + MBOX_UP_LEN, card->dma->recvbuf.size);
881475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4outmeml(card->mbase + DOORBELL, DBELL_UP_ARM);
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->configuration.len > 0 && data->configuration.data) {
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = c4_send_config(card, &data->configuration);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (retval) {
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "%s: failed to set config!!\n",
887475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       card->name);
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			c4_reset(card);
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return retval;
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
893475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4_send_init(card);
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
89908e51533a0a26c236879ad33b2798c16328051d9Adrian Bunkstatic void c4_reset_ctr(struct capi_ctr *ctrl)
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmctrl_info *cinfo;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int i;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&card->lock, flags);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
908475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4_reset(card);
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&card->lock, flags);
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
912475be4d85a274d0961593db41cf85689db1d583cJoe Perches	for (i = 0; i < card->nr_controllers; i++) {
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo = &card->ctrlinfo[i];
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset(cinfo->version, 0, sizeof(cinfo->version));
9154e329972052c3649367b91de783f6293b8653cb2Tilman Schmidt		capi_ctr_down(&cinfo->capi_ctrl);
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->nlogcontr = 0;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void c4_remove(struct pci_dev *pdev)
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard *card = pci_get_drvdata(pdev);
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmctrl_info *cinfo;
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int i;
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!card)
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
929475be4d85a274d0961593db41cf85689db1d583cJoe Perches	c4_reset(card);
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931475be4d85a274d0961593db41cf85689db1d583cJoe Perches	for (i = 0; i < card->nr_controllers; i++) {
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo = &card->ctrlinfo[i];
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		detach_capi_ctr(&cinfo->capi_ctrl);
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(card->irq, card);
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(card->mbase);
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(card->port, AVMB1_PORTLEN);
939475be4d85a274d0961593db41cf85689db1d583cJoe Perches	avmcard_dma_free(card->dma);
940475be4d85a274d0961593db41cf85689db1d583cJoe Perches	pci_set_drvdata(pdev, NULL);
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b1_free_card(card);
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
94708e51533a0a26c236879ad33b2798c16328051d9Adrian Bunkstatic void c4_register_appl(struct capi_ctr *ctrl,
948475be4d85a274d0961593db41cf85689db1d583cJoe Perches			     u16 appl,
949475be4d85a274d0961593db41cf85689db1d583cJoe Perches			     capi_register_params *rp)
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard *card = cinfo->card;
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int want = rp->level3cnt;
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int nconn;
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *p;
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ctrl->cnr == card->cardnr) {
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (want > 0) nconn = want;
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else nconn = ctrl->profile.nbchannel * 4 * -want;
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (nconn == 0) nconn = ctrl->profile.nbchannel * 4;
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = alloc_skb(23, GFP_ATOMIC);
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!skb) {
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_CRIT "%s: no memory, lost register appl.\n",
968475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       card->name);
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p = skb->data;
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_byte(&p, 0);
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_byte(&p, 0);
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_byte(&p, SEND_REGISTER);
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_word(&p, appl);
976475be4d85a274d0961593db41cf85689db1d583cJoe Perches		_put_word(&p, 1024 * (nconn + 1));
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_word(&p, nconn);
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_word(&p, rp->datablkcnt);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_word(&p, rp->datablklen);
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_put(skb, (u8 *)p - (u8 *)skb->data);
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_queue_tail(&card->dma->send_queue, skb);
983475be4d85a274d0961593db41cf85689db1d583cJoe Perches
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(&card->lock, flags);
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		c4_dispatch_tx(card);
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&card->lock, flags);
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
99208e51533a0a26c236879ad33b2798c16328051d9Adrian Bunkstatic void c4_release_appl(struct capi_ctr *ctrl, u16 appl)
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard *card = cinfo->card;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *p;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10001ccfd63367c1a6aaf8b33943f18856dde85f2f0bKarsten Keil	spin_lock_irqsave(&card->lock, flags);
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	capilib_release_appl(&cinfo->ncci_head, appl);
10021ccfd63367c1a6aaf8b33943f18856dde85f2f0bKarsten Keil	spin_unlock_irqrestore(&card->lock, flags);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ctrl->cnr == card->cardnr) {
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = alloc_skb(7, GFP_ATOMIC);
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!skb) {
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_CRIT "%s: no memory, lost release appl.\n",
1008475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       card->name);
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p = skb->data;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_byte(&p, 0);
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_byte(&p, 0);
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_byte(&p, SEND_RELEASE);
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_put_word(&p, appl);
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_put(skb, (u8 *)p - (u8 *)skb->data);
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_queue_tail(&card->dma->send_queue, skb);
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(&card->lock, flags);
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		c4_dispatch_tx(card);
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&card->lock, flags);
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard *card = cinfo->card;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 retval = CAPI_NOERROR;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10351ccfd63367c1a6aaf8b33943f18856dde85f2f0bKarsten Keil	spin_lock_irqsave(&card->lock, flags);
10361ccfd63367c1a6aaf8b33943f18856dde85f2f0bKarsten Keil	if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = capilib_data_b3_req(&cinfo->ncci_head,
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     CAPIMSG_APPID(skb->data),
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     CAPIMSG_NCCI(skb->data),
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     CAPIMSG_MSGID(skb->data));
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval == CAPI_NOERROR) {
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_queue_tail(&card->dma->send_queue, skb);
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		c4_dispatch_tx(card);
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10461ccfd63367c1a6aaf8b33943f18856dde85f2f0bKarsten Keil	spin_unlock_irqrestore(&card->lock, flags);
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *c4_procinfo(struct capi_ctr *ctrl)
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cinfo)
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return "";
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->cardname[0] ? cinfo->cardname : "-",
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->card ? cinfo->card->port : 0x0,
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->card ? cinfo->card->irq : 0,
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->card ? cinfo->card->membase : 0
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		);
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return cinfo->infobuf;
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10689a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyanstatic int c4_proc_show(struct seq_file *m, void *v)
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10709a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	struct capi_ctr *ctrl = m->private;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard *card = cinfo->card;
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 flag;
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *s;
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10769a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	seq_printf(m, "%-16s %s\n", "name", card->name);
10779a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	seq_printf(m, "%-16s 0x%x\n", "io", card->port);
10789a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	seq_printf(m, "%-16s %d\n", "irq", card->irq);
10799a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase);
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (card->cardtype) {
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case avm_b1isa: s = "B1 ISA"; break;
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case avm_b1pci: s = "B1 PCI"; break;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case avm_b1pcmcia: s = "B1 PCMCIA"; break;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case avm_m1: s = "M1"; break;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case avm_m2: s = "M2"; break;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case avm_t1isa: s = "T1 ISA (HEMA)"; break;
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case avm_t1pci: s = "T1 PCI"; break;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case avm_c4: s = "C4"; break;
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case avm_c2: s = "C2"; break;
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default: s = "???"; break;
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10929a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	seq_printf(m, "%-16s %s\n", "type", s);
10938e44b29da5300f4698c41b5fd2d1ce52c28e2148Harvey Harrison	if ((s = cinfo->version[VER_DRIVER]) != NULL)
10949a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan		seq_printf(m, "%-16s %s\n", "ver_driver", s);
10958e44b29da5300f4698c41b5fd2d1ce52c28e2148Harvey Harrison	if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
10969a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan		seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
10978e44b29da5300f4698c41b5fd2d1ce52c28e2148Harvey Harrison	if ((s = cinfo->version[VER_SERIAL]) != NULL)
10989a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan		seq_printf(m, "%-16s %s\n", "ver_serial", s);
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (card->cardtype != avm_m1) {
1101475be4d85a274d0961593db41cf85689db1d583cJoe Perches		flag = ((u8 *)(ctrl->profile.manu))[3];
1102475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (flag)
11039a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan			seq_printf(m, "%-16s%s%s%s%s%s%s%s\n",
1104475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   "protocol",
1105475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   (flag & 0x01) ? " DSS1" : "",
1106475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   (flag & 0x02) ? " CT1" : "",
1107475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   (flag & 0x04) ? " VN3" : "",
1108475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   (flag & 0x08) ? " NI1" : "",
1109475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   (flag & 0x10) ? " AUSTEL" : "",
1110475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   (flag & 0x20) ? " ESS" : "",
1111475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   (flag & 0x40) ? " 1TR6" : ""
1112475be4d85a274d0961593db41cf85689db1d583cJoe Perches				);
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (card->cardtype != avm_m1) {
1115475be4d85a274d0961593db41cf85689db1d583cJoe Perches		flag = ((u8 *)(ctrl->profile.manu))[5];
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (flag)
11179a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan			seq_printf(m, "%-16s%s%s%s%s\n",
1118475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   "linetype",
1119475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   (flag & 0x01) ? " point to point" : "",
1120475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   (flag & 0x02) ? " point to multipoint" : "",
1121475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   (flag & 0x08) ? " leased line without D-channel" : "",
1122475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   (flag & 0x04) ? " leased line with D-channel" : ""
1123475be4d85a274d0961593db41cf85689db1d583cJoe Perches				);
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11259a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
11269a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan
11279a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	return 0;
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11309a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyanstatic int c4_proc_open(struct inode *inode, struct file *file)
11319a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan{
11329a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	return single_open(file, c4_proc_show, PDE(inode)->data);
11339a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan}
11349a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan
11359a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyanstatic const struct file_operations c4_proc_fops = {
11369a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	.owner		= THIS_MODULE,
11379a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	.open		= c4_proc_open,
11389a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	.read		= seq_read,
11399a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	.llseek		= seq_lseek,
11409a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan	.release	= single_release,
11419a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan};
11429a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int c4_add_card(struct capicardparams *p, struct pci_dev *dev,
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       int nr_controllers)
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard *card;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmctrl_info *cinfo;
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card = b1_alloc_card(nr_controllers);
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!card) {
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "c4: no memory.\n");
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -ENOMEM;
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1159475be4d85a274d0961593db41cf85689db1d583cJoe Perches	card->dma = avmcard_dma_alloc("c4", dev, 2048 + 128, 2048 + 128);
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!card->dma) {
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "c4: no memory.\n");
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -ENOMEM;
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_free;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(card->name, "c%d-%x", nr_controllers, p->port);
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->port = p->port;
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->irq = p->irq;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->membase = p->membase;
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->cardtype = (nr_controllers == 4) ? avm_c4 : avm_c2;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "c4: ports 0x%03x-0x%03x in use.\n",
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       card->port, card->port + AVMB1_PORTLEN);
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EBUSY;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_free_dma;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	card->mbase = ioremap(card->membase, 128);
11808e44b29da5300f4698c41b5fd2d1ce52c28e2148Harvey Harrison	if (card->mbase == NULL) {
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_NOTICE "c4: can't remap memory at 0x%lx\n",
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       card->membase);
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_release_region;
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = c4_detect(card);
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval != 0) {
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_NOTICE "c4: NO card at 0x%x error(%d)\n",
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       card->port, retval);
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EIO;
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_unmap;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c4_reset(card);
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11969ba02bec3888d391bad0fb0a8dd584f88eed6c8dThomas Gleixner	retval = request_irq(card->irq, c4_interrupt, IRQF_SHARED, card->name, card);
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1198475be4d85a274d0961593db41cf85689db1d583cJoe Perches		printk(KERN_ERR "c4: unable to get IRQ %d.\n", card->irq);
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EBUSY;
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_unmap;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1203475be4d85a274d0961593db41cf85689db1d583cJoe Perches	for (i = 0; i < nr_controllers; i++) {
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo = &card->ctrlinfo[i];
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->capi_ctrl.owner = THIS_MODULE;
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->capi_ctrl.driver_name   = "c4";
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->capi_ctrl.driverdata    = cinfo;
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->capi_ctrl.register_appl = c4_register_appl;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->capi_ctrl.release_appl  = c4_release_appl;
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->capi_ctrl.send_message  = c4_send_message;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->capi_ctrl.load_firmware = c4_load_firmware;
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->capi_ctrl.reset_ctr     = c4_reset_ctr;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cinfo->capi_ctrl.procinfo      = c4_procinfo;
12149a58a80a701bdb2d220cdab4914218df5b48d781Alexey Dobriyan		cinfo->capi_ctrl.proc_fops = &c4_proc_fops;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(cinfo->capi_ctrl.name, card->name);
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = attach_capi_ctr(&cinfo->capi_ctrl);
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (retval) {
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "c4: attach controller failed (%d).\n", i);
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i--; i >= 0; i--) {
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cinfo = &card->ctrlinfo[i];
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				detach_capi_ctr(&cinfo->capi_ctrl);
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_free_irq;
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i == 0)
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			card->cardnr = cinfo->capi_ctrl.cnr;
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "c4: AVM C%d at i/o %#x, irq %d, mem %#lx\n",
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       nr_controllers, card->port, card->irq,
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       card->membase);
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_drvdata(dev, card);
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1236475be4d85a274d0961593db41cf85689db1d583cJoe Percheserr_free_irq:
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(card->irq, card);
1238475be4d85a274d0961593db41cf85689db1d583cJoe Percheserr_unmap:
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(card->mbase);
1240475be4d85a274d0961593db41cf85689db1d583cJoe Percheserr_release_region:
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(card->port, AVMB1_PORTLEN);
1242475be4d85a274d0961593db41cf85689db1d583cJoe Percheserr_free_dma:
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	avmcard_dma_free(card->dma);
1244475be4d85a274d0961593db41cf85689db1d583cJoe Percheserr_free:
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	b1_free_card(card);
1246475be4d85a274d0961593db41cf85689db1d583cJoe Percheserr:
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------- */
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit c4_probe(struct pci_dev *dev,
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      const struct pci_device_id *ent)
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int nr = ent->driver_data;
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct capicardparams param;
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pci_enable_device(dev) < 0) {
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "c4: failed to enable AVM-C%d\n", nr);
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_master(dev);
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	param.port = pci_resource_start(dev, 1);
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	param.irq = dev->irq;
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	param.membase = pci_resource_start(dev, 0);
1268475be4d85a274d0961593db41cf85689db1d583cJoe Perches
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "c4: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n",
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       nr, param.port, param.irq, param.membase);
1271475be4d85a274d0961593db41cf85689db1d583cJoe Perches
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = c4_add_card(&param, dev, nr);
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval != 0) {
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "c4: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n",
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       nr, param.port, param.irq, param.membase);
1276b69bcd9d9c3c47ed76da9cc0215c2eda0b7c16cfKulikov Vasiliy		pci_disable_device(dev);
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver c4_pci_driver = {
1283475be4d85a274d0961593db41cf85689db1d583cJoe Perches	.name           = "c4",
1284475be4d85a274d0961593db41cf85689db1d583cJoe Perches	.id_table       = c4_pci_tbl,
1285475be4d85a274d0961593db41cf85689db1d583cJoe Perches	.probe          = c4_probe,
1286475be4d85a274d0961593db41cf85689db1d583cJoe Perches	.remove         = c4_remove,
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct capi_driver capi_driver_c2 = {
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "c2",
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.revision	= "1.0",
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct capi_driver capi_driver_c4 = {
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "c4",
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.revision	= "1.0",
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init c4_init(void)
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *p;
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char rev[32];
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13058e44b29da5300f4698c41b5fd2d1ce52c28e2148Harvey Harrison	if ((p = strchr(revision, ':')) != NULL && p[1]) {
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strlcpy(rev, p + 2, 32);
13078e44b29da5300f4698c41b5fd2d1ce52c28e2148Harvey Harrison		if ((p = strchr(rev, '$')) != NULL && p > rev)
1308475be4d85a274d0961593db41cf85689db1d583cJoe Perches			*(p - 1) = 0;
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(rev, "1.0");
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = pci_register_driver(&c4_pci_driver);
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!err) {
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strlcpy(capi_driver_c2.revision, rev, 32);
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		register_capi_driver(&capi_driver_c2);
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strlcpy(capi_driver_c4.revision, rev, 32);
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		register_capi_driver(&capi_driver_c4);
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "c4: revision %s\n", rev);
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit c4_exit(void)
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_capi_driver(&capi_driver_c2);
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_capi_driver(&capi_driver_c4);
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_unregister_driver(&c4_pci_driver);
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(c4_init);
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(c4_exit);
1332