diff options
Diffstat (limited to 'drivers/isdn/avmb1')
-rw-r--r-- | drivers/isdn/avmb1/Makefile | 11 | ||||
-rw-r--r-- | drivers/isdn/avmb1/avmcard.h | 31 | ||||
-rw-r--r-- | drivers/isdn/avmb1/b1.c | 16 | ||||
-rw-r--r-- | drivers/isdn/avmb1/b1dma.c | 984 | ||||
-rw-r--r-- | drivers/isdn/avmb1/b1isa.c | 41 | ||||
-rw-r--r-- | drivers/isdn/avmb1/b1pci.c | 295 | ||||
-rw-r--r-- | drivers/isdn/avmb1/b1pcmcia.c | 36 | ||||
-rw-r--r-- | drivers/isdn/avmb1/c4.c | 1326 | ||||
-rw-r--r-- | drivers/isdn/avmb1/capi.c | 58 | ||||
-rw-r--r-- | drivers/isdn/avmb1/capidrv.c | 47 | ||||
-rw-r--r-- | drivers/isdn/avmb1/kcapi.c | 120 | ||||
-rw-r--r-- | drivers/isdn/avmb1/t1isa.c | 28 | ||||
-rw-r--r-- | drivers/isdn/avmb1/t1pci.c | 964 |
13 files changed, 2965 insertions, 992 deletions
diff --git a/drivers/isdn/avmb1/Makefile b/drivers/isdn/avmb1/Makefile index 111c39466..bfeb81939 100644 --- a/drivers/isdn/avmb1/Makefile +++ b/drivers/isdn/avmb1/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.7 1999/09/15 08:16:03 calle Exp $ +# $Id: Makefile,v 1.8 2000/01/25 14:33:38 calle Exp $ # # Makefile for the CAPI and AVM-B1 device drivers. # @@ -11,6 +11,11 @@ # parent makes.. # # $Log: Makefile,v $ +# Revision 1.8 2000/01/25 14:33:38 calle +# - Added Support AVM B1 PCI V4.0 (tested with prototype) +# - splitted up t1pci.c into b1dma.c for common function with b1pciv4 +# - support for revision register +# # Revision 1.7 1999/09/15 08:16:03 calle # Implementation of 64Bit extention complete. # @@ -99,7 +104,7 @@ ifeq ($(CONFIG_ISDN_DRV_AVMB1),y) ifdef CONFIG_ISDN_DRV_AVMB1_C4 O_OBJS += c4.o endif - OX_OBJS += capiutil.o capidrv.o b1.o + OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o else ifeq ($(CONFIG_ISDN_DRV_AVMB1),m) O_TARGET += kernelcapi.o @@ -123,7 +128,7 @@ else ifdef CONFIG_ISDN_DRV_AVMB1_C4 M_OBJS += c4.o endif - MX_OBJS += capiutil.o capidrv.o b1.o + MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o endif endif diff --git a/drivers/isdn/avmb1/avmcard.h b/drivers/isdn/avmb1/avmcard.h index f4b5df689..56fa0fba6 100644 --- a/drivers/isdn/avmb1/avmcard.h +++ b/drivers/isdn/avmb1/avmcard.h @@ -1,9 +1,14 @@ /* - * $Id: avmcard.h,v 1.6 1999/11/05 16:38:01 calle Exp $ + * $Id: avmcard.h,v 1.7 2000/01/25 14:33:38 calle Exp $ * * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: avmcard.h,v $ + * Revision 1.7 2000/01/25 14:33:38 calle + * - Added Support AVM B1 PCI V4.0 (tested with prototype) + * - splitted up t1pci.c into b1dma.c for common function with b1pciv4 + * - support for revision register + * * Revision 1.6 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -92,6 +97,8 @@ typedef struct avmcard { unsigned irq; unsigned long membase; enum avmcardtype cardtype; + unsigned char revision; + unsigned char class; int cardnr; /* for t1isa */ char msgbuf[128]; /* capimsg msg part */ @@ -228,8 +235,9 @@ extern int b1_irq_table[16]; #define B1_WRITE 0x01 #define B1_INSTAT 0x02 #define B1_OUTSTAT 0x03 -#define B1_RESET 0x10 #define B1_ANALYSE 0x04 +#define B1_REVISION 0x05 +#define B1_RESET 0x10 #define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l) @@ -561,10 +569,13 @@ static inline void b1_setinterrupt(unsigned int base, unsigned irq, } } +/* b1.c */ int b1_detect(unsigned int base, enum avmcardtype cardtype); +void b1_getrevision(avmcard *card); int b1_load_t4file(avmcard *card, capiloaddatapart * t4file); int b1_load_config(avmcard *card, capiloaddatapart * config); int b1_loaded(avmcard *card); + int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data); void b1_reset_ctr(struct capi_ctr *ctrl); void b1_register_appl(struct capi_ctr *ctrl, __u16 appl, @@ -577,5 +588,21 @@ void b1_handle_interrupt(avmcard * card); int b1ctl_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl); +/* b1dma.c */ +int b1pciv4_detect(avmcard *card); +int t1pci_detect(avmcard *card); +void b1dma_reset(avmcard *card); +void b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs); + +int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data); +void b1dma_reset_ctr(struct capi_ctr *ctrl); +void b1dma_remove_ctr(struct capi_ctr *ctrl); +void b1dma_register_appl(struct capi_ctr *ctrl, + __u16 appl, + capi_register_params *rp); +void b1dma_release_appl(struct capi_ctr *ctrl, __u16 appl); +void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); +int b1dmactl_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl); #endif /* _AVMCARD_H_ */ diff --git a/drivers/isdn/avmb1/b1.c b/drivers/isdn/avmb1/b1.c index 900b31c8c..65c4368cd 100644 --- a/drivers/isdn/avmb1/b1.c +++ b/drivers/isdn/avmb1/b1.c @@ -1,11 +1,16 @@ /* - * $Id: b1.c,v 1.12 1999/11/05 16:38:01 calle Exp $ + * $Id: b1.c,v 1.13 2000/01/25 14:33:38 calle Exp $ * * Common module for AVM B1 cards. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1.c,v $ + * Revision 1.13 2000/01/25 14:33:38 calle + * - Added Support AVM B1 PCI V4.0 (tested with prototype) + * - splitted up t1pci.c into b1dma.c for common function with b1pciv4 + * - support for revision register + * * Revision 1.12 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -86,7 +91,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.12 $"; +static char *revision = "$Revision: 1.13 $"; /* ------------------------------------------------------------- */ @@ -158,6 +163,12 @@ int b1_detect(unsigned int base, enum avmcardtype cardtype) return 0; } +void b1_getrevision(avmcard *card) +{ + card->class = inb(card->port + B1_ANALYSE); + card->revision = inb(card->port + B1_REVISION); +} + int b1_load_t4file(avmcard *card, capiloaddatapart * t4file) { unsigned char buf[256]; @@ -688,6 +699,7 @@ int b1ctl_read_proc(char *page, char **start, off_t off, EXPORT_SYMBOL(b1_irq_table); EXPORT_SYMBOL(b1_detect); +EXPORT_SYMBOL(b1_getrevision); EXPORT_SYMBOL(b1_load_t4file); EXPORT_SYMBOL(b1_load_config); EXPORT_SYMBOL(b1_loaded); diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c new file mode 100644 index 000000000..8bf595282 --- /dev/null +++ b/drivers/isdn/avmb1/b1dma.c @@ -0,0 +1,984 @@ +/* + * $Id: b1dma.c,v 1.2 2000/01/25 14:44:47 calle Exp $ + * + * Common module for AVM B1 cards that support dma with AMCC + * + * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: b1dma.c,v $ + * Revision 1.2 2000/01/25 14:44:47 calle + * typo in b1pciv4_detect(). + * + * Revision 1.1 2000/01/25 14:36:43 calle + * common function for T1 PCI and B1 PCI V4. + * + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/capi.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include "capilli.h" +#include "avmcard.h" +#include "capicmd.h" +#include "capiutil.h" + +static char *revision = "$Revision: 1.2 $"; + +/* ------------------------------------------------------------- */ + +MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>"); + +int suppress_pollack = 0; +MODULE_PARM(suppress_pollack, "0-1i"); + +/* ------------------------------------------------------------- */ + +static void b1dma_dispatch_tx(avmcard *card); + +/* ------------------------------------------------------------- */ + +/* S5933 */ + +#define AMCC_RXPTR 0x24 +#define AMCC_RXLEN 0x28 +#define AMCC_TXPTR 0x2c +#define AMCC_TXLEN 0x30 + +#define AMCC_INTCSR 0x38 +# define EN_READ_TC_INT 0x00008000L +# define EN_WRITE_TC_INT 0x00004000L +# define EN_TX_TC_INT EN_READ_TC_INT +# define EN_RX_TC_INT EN_WRITE_TC_INT +# define AVM_FLAG 0x30000000L + +# define ANY_S5933_INT 0x00800000L +# define READ_TC_INT 0x00080000L +# define WRITE_TC_INT 0x00040000L +# define TX_TC_INT READ_TC_INT +# define RX_TC_INT WRITE_TC_INT +# define MASTER_ABORT_INT 0x00100000L +# define TARGET_ABORT_INT 0x00200000L +# define BUS_MASTER_INT 0x00200000L +# define ALL_INT 0x000C0000L + +#define AMCC_MCSR 0x3c +# define A2P_HI_PRIORITY 0x00000100L +# define EN_A2P_TRANSFERS 0x00000400L +# define P2A_HI_PRIORITY 0x00001000L +# define EN_P2A_TRANSFERS 0x00004000L +# define RESET_A2P_FLAGS 0x04000000L +# define RESET_P2A_FLAGS 0x02000000L + +/* ------------------------------------------------------------- */ + +#define b1dmaoutmeml(addr, value) writel(value, addr) +#define b1dmainmeml(addr) readl(addr) +#define b1dmaoutmemw(addr, value) writew(value, addr) +#define b1dmainmemw(addr) readw(addr) +#define b1dmaoutmemb(addr, value) writeb(value, addr) +#define b1dmainmemb(addr) readb(addr) + +/* ------------------------------------------------------------- */ + +static inline int b1dma_tx_empty(unsigned int port) +{ + return inb(port + 0x03) & 0x1; +} + +static inline int b1dma_rx_full(unsigned int port) +{ + return inb(port + 0x02) & 0x1; +} + +static int b1dma_tolink(avmcard *card, void *buf, unsigned int len) +{ + unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ + unsigned char *s = (unsigned char *)buf; + while (len--) { + while ( !b1dma_tx_empty(card->port) + && time_before(jiffies, stop)); + if (!b1dma_tx_empty(card->port)) + return -1; + t1outp(card->port, 0x01, *s++); + } + return 0; +} + +static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len) +{ + unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ + unsigned char *s = (unsigned char *)buf; + while (len--) { + while ( !b1dma_rx_full(card->port) + && time_before(jiffies, stop)); + if (!b1dma_rx_full(card->port)) + return -1; + *s++ = t1inp(card->port, 0x00); + } + return 0; +} + +static int WriteReg(avmcard *card, __u32 reg, __u8 val) +{ + __u8 cmd = 0x00; + if ( b1dma_tolink(card, &cmd, 1) == 0 + && b1dma_tolink(card, ®, 4) == 0) { + __u32 tmp = val; + return b1dma_tolink(card, &tmp, 4); + } + return -1; +} + +static __u8 ReadReg(avmcard *card, __u32 reg) +{ + __u8 cmd = 0x01; + if ( b1dma_tolink(card, &cmd, 1) == 0 + && b1dma_tolink(card, ®, 4) == 0) { + __u32 tmp; + if (b1dma_fromlink(card, &tmp, 4) == 0) + return (__u8)tmp; + } + return 0xff; +} + +/* ------------------------------------------------------------- */ + +static inline void _put_byte(void **pp, __u8 val) +{ + __u8 *s = *pp; + *s++ = val; + *pp = s; +} + +static inline void _put_word(void **pp, __u32 val) +{ + __u8 *s = *pp; + *s++ = val & 0xff; + *s++ = (val >> 8) & 0xff; + *s++ = (val >> 16) & 0xff; + *s++ = (val >> 24) & 0xff; + *pp = s; +} + +static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len) +{ + unsigned i = len; + _put_word(pp, i); + while (i-- > 0) + _put_byte(pp, *dp++); +} + +static inline __u8 _get_byte(void **pp) +{ + __u8 *s = *pp; + __u8 val; + val = *s++; + *pp = s; + return val; +} + +static inline __u32 _get_word(void **pp) +{ + __u8 *s = *pp; + __u32 val; + val = *s++; + val |= (*s++ << 8); + val |= (*s++ << 16); + val |= (*s++ << 24); + *pp = s; + return val; +} + +static inline __u32 _get_slice(void **pp, unsigned char *dp) +{ + unsigned int len, i; + + len = i = _get_word(pp); + while (i-- > 0) *dp++ = _get_byte(pp); + return len; +} + +/* ------------------------------------------------------------- */ + +void b1dma_reset(avmcard *card) +{ + unsigned long flags; + + save_flags(flags); + cli(); + card->csr = 0x0; + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); + b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0); + b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0); + + t1outp(card->port, 0x10, 0x00); + t1outp(card->port, 0x07, 0x00); + + restore_flags(flags); + + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); + udelay(10 * 1000); + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */ + udelay(10 * 1000); + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); + if (card->cardtype == avm_t1pci) + udelay(42 * 1000); + else + udelay(10 * 1000); +} + +/* ------------------------------------------------------------- */ + +int b1dma_detect(avmcard *card) +{ + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); + udelay(10 * 1000); + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */ + udelay(10 * 1000); + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); + udelay(42 * 1000); + + b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0); + b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0); + card->csr = 0x0; + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); + + if (b1dmainmeml(card->mbase+AMCC_MCSR) != 0x000000E6) + return 1; + + b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0xffffffff); + b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0xffffffff); + if ( b1dmainmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc + || b1dmainmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc) + return 2; + + b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0x0); + b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0x0); + if ( b1dmainmeml(card->mbase+AMCC_RXPTR) != 0x0 + || b1dmainmeml(card->mbase+AMCC_TXPTR) != 0x0) + return 3; + + t1outp(card->port, 0x10, 0x00); + t1outp(card->port, 0x07, 0x00); + + t1outp(card->port, 0x02, 0x02); + t1outp(card->port, 0x03, 0x02); + + if ( (t1inp(card->port, 0x02) & 0xFE) != 0x02 + || t1inp(card->port, 0x3) != 0x03) + return 4; + + t1outp(card->port, 0x02, 0x00); + t1outp(card->port, 0x03, 0x00); + + if ( (t1inp(card->port, 0x02) & 0xFE) != 0x00 + || t1inp(card->port, 0x3) != 0x01) + return 5; + + return 0; +} + +int t1pci_detect(avmcard *card) +{ + int ret; + + if ((ret = b1dma_detect(card)) != 0) + return ret; + + /* Transputer test */ + + if ( WriteReg(card, 0x80001000, 0x11) != 0 + || WriteReg(card, 0x80101000, 0x22) != 0 + || WriteReg(card, 0x80201000, 0x33) != 0 + || WriteReg(card, 0x80301000, 0x44) != 0) + return 6; + + if ( ReadReg(card, 0x80001000) != 0x11 + || ReadReg(card, 0x80101000) != 0x22 + || ReadReg(card, 0x80201000) != 0x33 + || ReadReg(card, 0x80301000) != 0x44) + return 7; + + if ( WriteReg(card, 0x80001000, 0x55) != 0 + || WriteReg(card, 0x80101000, 0x66) != 0 + || WriteReg(card, 0x80201000, 0x77) != 0 + || WriteReg(card, 0x80301000, 0x88) != 0) + return 8; + + if ( ReadReg(card, 0x80001000) != 0x55 + || ReadReg(card, 0x80101000) != 0x66 + || ReadReg(card, 0x80201000) != 0x77 + || ReadReg(card, 0x80301000) != 0x88) + return 9; + + return 0; +} + +int b1pciv4_detect(avmcard *card) +{ + int ret, i; + + if ((ret = b1dma_detect(card)) != 0) + return ret; + + for (i=0; i < 5 ; i++) { + if (WriteReg(card, 0x80A00000, 0x21) != 0) + return 6; + if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01) + return 7; + } + for (i=0; i < 5 ; i++) { + if (WriteReg(card, 0x80A00000, 0x20) != 0) + return 8; + if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00) + return 9; + } + + return 0; +} + +/* ------------------------------------------------------------- */ + +static void b1dma_dispatch_tx(avmcard *card) +{ + avmcard_dmainfo *dma = card->dma; + unsigned long flags; + struct sk_buff *skb; + __u8 cmd, subcmd; + __u16 len; + __u32 txlen; + int inint; + void *p; + + save_flags(flags); + cli(); + + inint = card->interrupt; + + if (card->csr & EN_TX_TC_INT) { /* tx busy */ + restore_flags(flags); + return; + } + + skb = skb_dequeue(&dma->send_queue); + if (!skb) { +#ifdef CONFIG_B1DMA_DEBUG + printk(KERN_DEBUG "tx(%d): underrun\n", inint); +#endif + restore_flags(flags); + return; + } + + len = CAPIMSG_LEN(skb->data); + + if (len) { + cmd = CAPIMSG_COMMAND(skb->data); + subcmd = CAPIMSG_SUBCOMMAND(skb->data); + + p = dma->sendbuf; + + if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { + __u16 dlen = CAPIMSG_DATALEN(skb->data); + _put_byte(&p, SEND_DATA_B3_REQ); + _put_slice(&p, skb->data, len); + _put_slice(&p, skb->data + len, dlen); + } else { + _put_byte(&p, SEND_MESSAGE); + _put_slice(&p, skb->data, len); + } + txlen = (__u8 *)p - (__u8 *)dma->sendbuf; +#ifdef CONFIG_B1DMA_DEBUG + printk(KERN_DEBUG "tx(%d): put msg len=%d\n", + inint, txlen); +#endif + } else { + txlen = skb->len-2; +#ifdef CONFIG_B1DMA_POLLDEBUG + if (skb->data[2] == SEND_POLLACK) + printk(KERN_INFO "%s: send ack\n", card->name); +#endif +#ifdef CONFIG_B1DMA_DEBUG + printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n", + inint, skb->data[2], txlen); +#endif + memcpy(dma->sendbuf, skb->data+2, skb->len-2); + } + txlen = (txlen + 3) & ~3; + + b1dmaoutmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf)); + b1dmaoutmeml(card->mbase+AMCC_TXLEN, txlen); + + card->csr |= EN_TX_TC_INT; + + if (!inint) + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); + + restore_flags(flags); + dev_kfree_skb(skb); +} + +/* ------------------------------------------------------------- */ + +static void queue_pollack(avmcard *card) +{ + struct sk_buff *skb; + void *p; + + skb = alloc_skb(3, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost poll ack\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_POLLACK); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + b1dma_dispatch_tx(card); +} + +/* ------------------------------------------------------------- */ + +static void b1dma_handle_rx(avmcard *card) +{ + avmctrl_info *cinfo = &card->ctrlinfo[0]; + avmcard_dmainfo *dma = card->dma; + struct capi_ctr *ctrl = cinfo->capi_ctrl; + struct sk_buff *skb; + void *p = dma->recvbuf+4; + __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; + __u8 b1cmd = _get_byte(&p); + +#ifdef CONFIG_B1DMA_DEBUG + printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen); +#endif + + switch (b1cmd) { + case RECEIVE_DATA_B3_IND: + + ApplId = (unsigned) _get_word(&p); + MsgLen = _get_slice(&p, card->msgbuf); + DataB3Len = _get_slice(&p, card->databuf); + + if (MsgLen < 30) { /* not CAPI 64Bit */ + memset(card->msgbuf+MsgLen, 0, 30-MsgLen); + MsgLen = 30; + CAPIMSG_SETLEN(card->msgbuf, 30); + } + if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) { + printk(KERN_ERR "%s: incoming packet dropped\n", + card->name); + } else { + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); + ctrl->handle_capimsg(ctrl, ApplId, skb); + } + break; + + case RECEIVE_MESSAGE: + + ApplId = (unsigned) _get_word(&p); + MsgLen = _get_slice(&p, card->msgbuf); + if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { + printk(KERN_ERR "%s: incoming packet dropped\n", + card->name); + } else { + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + ctrl->handle_capimsg(ctrl, ApplId, skb); + } + break; + + case RECEIVE_NEW_NCCI: + + ApplId = _get_word(&p); + NCCI = _get_word(&p); + WindowSize = _get_word(&p); + + ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize); + + break; + + case RECEIVE_FREE_NCCI: + + ApplId = _get_word(&p); + NCCI = _get_word(&p); + + if (NCCI != 0xffffffff) + ctrl->free_ncci(ctrl, ApplId, NCCI); + else ctrl->appl_released(ctrl, ApplId); + break; + + case RECEIVE_START: +#ifdef CONFIG_B1DMA_POLLDEBUG + printk(KERN_INFO "%s: receive poll\n", card->name); +#endif + if (!suppress_pollack) + queue_pollack(card); + ctrl->resume_output(ctrl); + break; + + case RECEIVE_STOP: + ctrl->suspend_output(ctrl); + break; + + case RECEIVE_INIT: + + cinfo->versionlen = _get_slice(&p, cinfo->versionbuf); + b1_parse_version(cinfo); + printk(KERN_INFO "%s: %s-card (%s) now active\n", + card->name, + cinfo->version[VER_CARDTYPE], + cinfo->version[VER_DRIVER]); + ctrl->ready(ctrl); + break; + + case RECEIVE_TASK_READY: + ApplId = (unsigned) _get_word(&p); + MsgLen = _get_slice(&p, card->msgbuf); + card->msgbuf[MsgLen--] = 0; + while ( MsgLen >= 0 + && ( card->msgbuf[MsgLen] == '\n' + || card->msgbuf[MsgLen] == '\r')) + card->msgbuf[MsgLen--] = 0; + printk(KERN_INFO "%s: task %d \"%s\" ready.\n", + card->name, ApplId, card->msgbuf); + break; + + case RECEIVE_DEBUGMSG: + MsgLen = _get_slice(&p, card->msgbuf); + card->msgbuf[MsgLen--] = 0; + while ( MsgLen >= 0 + && ( card->msgbuf[MsgLen] == '\n' + || card->msgbuf[MsgLen] == '\r')) + card->msgbuf[MsgLen--] = 0; + printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); + break; + + default: + printk(KERN_ERR "%s: b1dma_interrupt: 0x%x ???\n", + card->name, b1cmd); + return; + } +} + +/* ------------------------------------------------------------- */ + +static void b1dma_handle_interrupt(avmcard *card) +{ + __u32 status = b1dmainmeml(card->mbase+AMCC_INTCSR); + __u32 newcsr; + + if ((status & ANY_S5933_INT) == 0) + return; + + newcsr = card->csr | (status & ALL_INT); + if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT; + if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT; + b1dmaoutmeml(card->mbase+AMCC_INTCSR, newcsr); + + if ((status & RX_TC_INT) != 0) { + __u8 *recvbuf = card->dma->recvbuf; + __u32 rxlen; + if (card->dma->recvlen == 0) { + card->dma->recvlen = *((__u32 *)recvbuf); + rxlen = (card->dma->recvlen + 3) & ~3; + b1dmaoutmeml(card->mbase+AMCC_RXPTR, + virt_to_phys(recvbuf+4)); + b1dmaoutmeml(card->mbase+AMCC_RXLEN, rxlen); + } else { + b1dma_handle_rx(card); + card->dma->recvlen = 0; + b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf)); + b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4); + } + } + + if ((status & TX_TC_INT) != 0) { + card->csr &= ~EN_TX_TC_INT; + b1dma_dispatch_tx(card); + } else if (card->csr & EN_TX_TC_INT) { + if (b1dmainmeml(card->mbase+AMCC_TXLEN) == 0) { + card->csr &= ~EN_TX_TC_INT; + b1dma_dispatch_tx(card); + } + } + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); +} + +void b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +{ + avmcard *card; + + card = (avmcard *) devptr; + + if (!card) { + printk(KERN_WARNING "b1dma: interrupt: wrong device\n"); + return; + } + if (card->interrupt) { + printk(KERN_ERR "%s: reentering interrupt hander\n", card->name); + return; + } + + card->interrupt = 1; + + b1dma_handle_interrupt(card); + + card->interrupt = 0; +} + +/* ------------------------------------------------------------- */ + +static int b1dma_loaded(avmcard *card) +{ + unsigned long stop; + unsigned char ans; + unsigned long tout = 2; + unsigned int base = card->port; + + for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { + if (b1_tx_empty(base)) + break; + } + if (!b1_tx_empty(base)) { + printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n", + card->name); + return 0; + } + b1_put_byte(base, SEND_POLLACK); + for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { + if (b1_rx_full(base)) { + if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) { + return 1; + } + printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans); + return 0; + } + } + printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name); + return 0; +} + +/* ------------------------------------------------------------- */ + +static void b1dma_send_init(avmcard *card) +{ + struct sk_buff *skb; + void *p; + + skb = alloc_skb(15, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost register appl.\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_INIT); + _put_word(&p, AVM_NAPPS); + _put_word(&p, AVM_NCCI_PER_CHANNEL*30); + _put_word(&p, card->cardnr - 1); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + b1dma_dispatch_tx(card); +} + +int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + unsigned long flags; + int retval; + + b1dma_reset(card); + + if ((retval = b1_load_t4file(card, &data->firmware))) { + b1dma_reset(card); + printk(KERN_ERR "%s: failed to load t4file!!\n", + card->name); + return retval; + } + + if (data->configuration.len > 0 && data->configuration.data) { + if ((retval = b1_load_config(card, &data->configuration))) { + b1dma_reset(card); + printk(KERN_ERR "%s: failed to load config!!\n", + card->name); + return retval; + } + } + + if (!b1dma_loaded(card)) { + b1dma_reset(card); + printk(KERN_ERR "%s: failed to load t4file.\n", card->name); + return -EIO; + } + + save_flags(flags); + cli(); + + card->csr = AVM_FLAG; + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); + b1dmaoutmeml(card->mbase+AMCC_MCSR, + EN_A2P_TRANSFERS|EN_P2A_TRANSFERS + |A2P_HI_PRIORITY|P2A_HI_PRIORITY + |RESET_A2P_FLAGS|RESET_P2A_FLAGS); + t1outp(card->port, 0x07, 0x30); + t1outp(card->port, 0x10, 0xF0); + + card->dma->recvlen = 0; + b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf)); + b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4); + card->csr |= EN_RX_TC_INT; + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); + restore_flags(flags); + + b1dma_send_init(card); + + return 0; +} + +void b1dma_reset_ctr(struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + + b1dma_reset(card); + + memset(cinfo->version, 0, sizeof(cinfo->version)); + ctrl->reseted(ctrl); +} + + +/* ------------------------------------------------------------- */ + + +void b1dma_register_appl(struct capi_ctr *ctrl, + __u16 appl, + capi_register_params *rp) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + struct sk_buff *skb; + int want = rp->level3cnt; + int nconn; + void *p; + + if (want > 0) nconn = want; + else nconn = ctrl->profile.nbchannel * -want; + if (nconn == 0) nconn = ctrl->profile.nbchannel; + + skb = alloc_skb(23, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost register appl.\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_REGISTER); + _put_word(&p, appl); + _put_word(&p, 1024 * (nconn+1)); + _put_word(&p, nconn); + _put_word(&p, rp->datablkcnt); + _put_word(&p, rp->datablklen); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + b1dma_dispatch_tx(card); + + ctrl->appl_registered(ctrl, appl); +} + +/* ------------------------------------------------------------- */ + +void b1dma_release_appl(struct capi_ctr *ctrl, __u16 appl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + struct sk_buff *skb; + void *p; + + skb = alloc_skb(7, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost release appl.\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_RELEASE); + _put_word(&p, appl); + + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + skb_queue_tail(&card->dma->send_queue, skb); + b1dma_dispatch_tx(card); +} + +/* ------------------------------------------------------------- */ + +void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + skb_queue_tail(&card->dma->send_queue, skb); + b1dma_dispatch_tx(card); +} + +/* ------------------------------------------------------------- */ + +int b1dmactl_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + unsigned long flags; + __u8 flag; + int len = 0; + char *s; + __u32 txaddr, txlen, rxaddr, rxlen, csr; + + len += sprintf(page+len, "%-16s %s\n", "name", card->name); + len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); + len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); + len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase); + switch (card->cardtype) { + case avm_b1isa: s = "B1 ISA"; break; + case avm_b1pci: s = "B1 PCI"; break; + case avm_b1pcmcia: s = "B1 PCMCIA"; break; + case avm_m1: s = "M1"; break; + case avm_m2: s = "M2"; break; + case avm_t1isa: s = "T1 ISA (HEMA)"; break; + case avm_t1pci: s = "T1 PCI"; break; + case avm_c4: s = "C4"; break; + default: s = "???"; break; + } + len += sprintf(page+len, "%-16s %s\n", "type", s); + if ((s = cinfo->version[VER_DRIVER]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + if ((s = cinfo->version[VER_CARDTYPE]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + if ((s = cinfo->version[VER_SERIAL]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + + if (card->cardtype != avm_m1) { + flag = ((__u8 *)(ctrl->profile.manu))[3]; + if (flag) + len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n", + "protocol", + (flag & 0x01) ? " DSS1" : "", + (flag & 0x02) ? " CT1" : "", + (flag & 0x04) ? " VN3" : "", + (flag & 0x08) ? " NI1" : "", + (flag & 0x10) ? " AUSTEL" : "", + (flag & 0x20) ? " ESS" : "", + (flag & 0x40) ? " 1TR6" : "" + ); + } + if (card->cardtype != avm_m1) { + flag = ((__u8 *)(ctrl->profile.manu))[5]; + if (flag) + len += sprintf(page+len, "%-16s%s%s%s%s\n", + "linetype", + (flag & 0x01) ? " point to point" : "", + (flag & 0x02) ? " point to multipoint" : "", + (flag & 0x08) ? " leased line without D-channel" : "", + (flag & 0x04) ? " leased line with D-channel" : "" + ); + } + len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); + + save_flags(flags); + cli(); + + txaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x2c)); + txaddr -= (__u32)card->dma->sendbuf; + txlen = b1dmainmeml(card->mbase+0x30); + + rxaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x24)); + rxaddr -= (__u32)card->dma->recvbuf; + rxlen = b1dmainmeml(card->mbase+0x28); + + csr = b1dmainmeml(card->mbase+AMCC_INTCSR); + + restore_flags(flags); + + len += sprintf(page+len, "%-16s 0x%lx\n", + "csr (cached)", (unsigned long)card->csr); + len += sprintf(page+len, "%-16s 0x%lx\n", + "csr", (unsigned long)csr); + len += sprintf(page+len, "%-16s %lu\n", + "txoff", (unsigned long)txaddr); + len += sprintf(page+len, "%-16s %lu\n", + "txlen", (unsigned long)txlen); + len += sprintf(page+len, "%-16s %lu\n", + "rxoff", (unsigned long)rxaddr); + len += sprintf(page+len, "%-16s %lu\n", + "rxlen", (unsigned long)rxlen); + + if (off+count >= len) + *eof = 1; + if (len < off) + return 0; + *start = page + off; + return ((count < len-off) ? count : len-off); +} + +/* ------------------------------------------------------------- */ + +EXPORT_SYMBOL(b1dma_reset); +EXPORT_SYMBOL(t1pci_detect); +EXPORT_SYMBOL(b1pciv4_detect); +EXPORT_SYMBOL(b1dma_interrupt); + +EXPORT_SYMBOL(b1dma_load_firmware); +EXPORT_SYMBOL(b1dma_reset_ctr); +EXPORT_SYMBOL(b1dma_register_appl); +EXPORT_SYMBOL(b1dma_release_appl); +EXPORT_SYMBOL(b1dma_send_message); +EXPORT_SYMBOL(b1dmactl_read_proc); + +#ifdef MODULE +#define b1dma_init init_module +void cleanup_module(void); +#endif + +int b1dma_init(void) +{ + char *p; + char rev[10]; + + if ((p = strchr(revision, ':'))) { + strncpy(rev, p + 1, sizeof(rev)); + p = strchr(rev, '$'); + *p = 0; + } else + strcpy(rev, "1.0"); + + printk(KERN_INFO "b1dma: revision %s\n", rev); + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ +} +#endif diff --git a/drivers/isdn/avmb1/b1isa.c b/drivers/isdn/avmb1/b1isa.c index 01972b2d2..590e825b6 100644 --- a/drivers/isdn/avmb1/b1isa.c +++ b/drivers/isdn/avmb1/b1isa.c @@ -1,11 +1,19 @@ /* - * $Id: b1isa.c,v 1.5 1999/11/05 16:38:01 calle Exp $ + * $Id: b1isa.c,v 1.7 2000/02/02 18:36:03 calle Exp $ * * Module for AVM B1 ISA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1isa.c,v $ + * Revision 1.7 2000/02/02 18:36:03 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.6 2000/01/25 14:37:39 calle + * new message after successfull detection including card revision and + * used resources. + * * Revision 1.5 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -61,7 +69,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.5 $"; +static char *revision = "$Revision: 1.7 $"; /* ------------------------------------------------------------- */ @@ -69,10 +77,6 @@ MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>"); /* ------------------------------------------------------------- */ -static struct capi_driver_interface *di; - -/* ------------------------------------------------------------- */ - static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs) { avmcard *card; @@ -96,6 +100,10 @@ static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs) } /* ------------------------------------------------------------- */ +static struct capi_driver_interface *di; + +/* ------------------------------------------------------------- */ + static void b1isa_remove_ctr(struct capi_ctr *ctrl) { avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); @@ -122,10 +130,13 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) avmcard *card; int retval; + MOD_INC_USE_COUNT; + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "b1isa: no memory.\n"); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card, 0, sizeof(avmcard)); @@ -133,6 +144,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) if (!cinfo) { printk(KERN_WARNING "b1isa: no memory.\n"); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(cinfo, 0, sizeof(avmctrl_info)); @@ -149,12 +161,14 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) card->port, card->port + AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } if (b1_irq_table[card->irq & 0xf] == 0) { printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EINVAL; } if ( card->port != 0x150 && card->port != 0x250 @@ -162,6 +176,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EINVAL; } b1_reset(card->port); @@ -170,9 +185,11 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) card->port, retval); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } b1_reset(card->port); + b1_getrevision(card); request_region(p->port, AVMB1_PORTLEN, card->name); @@ -182,6 +199,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -192,10 +210,14 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } - MOD_INC_USE_COUNT; + printk(KERN_INFO + "%s: AVM B1 ISA at i/o %#x, irq %d, revision %d\n", + driver->name, card->port, card->irq, card->revision); + return 0; } @@ -205,11 +227,12 @@ static char *b1isa_procinfo(struct capi_ctr *ctrl) if (!cinfo) return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d", + sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", cinfo->cardname[0] ? cinfo->cardname : "-", cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", cinfo->card ? cinfo->card->port : 0x0, - cinfo->card ? cinfo->card->irq : 0 + cinfo->card ? cinfo->card->irq : 0, + cinfo->card ? cinfo->card->revision : 0 ); return cinfo->infobuf; } diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c index f4e87b12f..f7affea0d 100644 --- a/drivers/isdn/avmb1/b1pci.c +++ b/drivers/isdn/avmb1/b1pci.c @@ -1,11 +1,20 @@ /* - * $Id: b1pci.c,v 1.18 1999/11/05 16:38:01 calle Exp $ + * $Id: b1pci.c,v 1.20 2000/02/02 18:36:03 calle Exp $ * * Module for AVM B1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pci.c,v $ + * Revision 1.20 2000/02/02 18:36:03 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.19 2000/01/25 14:33:38 calle + * - Added Support AVM B1 PCI V4.0 (tested with prototype) + * - splitted up t1pci.c into b1dma.c for common function with b1pciv4 + * - support for revision register + * * Revision 1.18 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -66,7 +75,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.18 $"; +static char *revision = "$Revision: 1.20 $"; /* ------------------------------------------------------------- */ @@ -138,11 +147,12 @@ static char *b1pci_procinfo(struct capi_ctr *ctrl) if (!cinfo) return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d", + sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", cinfo->cardname[0] ? cinfo->cardname : "-", cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", cinfo->card ? cinfo->card->port : 0x0, - cinfo->card ? cinfo->card->irq : 0 + cinfo->card ? cinfo->card->irq : 0, + cinfo->card ? cinfo->card->revision : 0 ); return cinfo->infobuf; } @@ -155,10 +165,13 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) avmctrl_info *cinfo; int retval; + MOD_INC_USE_COUNT; + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card, 0, sizeof(avmcard)); @@ -166,6 +179,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(cinfo, 0, sizeof(avmctrl_info)); @@ -182,6 +196,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->port, card->port + AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } b1_reset(card->port); @@ -190,9 +205,11 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->port, retval); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } b1_reset(card->port); + b1_getrevision(card); request_region(p->port, AVMB1_PORTLEN, card->name); @@ -203,6 +220,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -214,10 +232,19 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } - MOD_INC_USE_COUNT; + if (card->revision >= 4) { + printk(KERN_INFO + "%s: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n", + driver->name, card->port, card->irq, card->revision); + } else { + printk(KERN_INFO + "%s: AVM B1 PCI at i/o %#x, irq %d, revision %d\n", + driver->name, card->port, card->irq, card->revision); + } return 0; } @@ -241,6 +268,187 @@ static struct capi_driver b1pci_driver = { 0, /* no add_card function */ }; +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 +/* ------------------------------------------------------------- */ + +static struct capi_driver_interface *div4; + +/* ------------------------------------------------------------- */ + +static void b1pciv4_remove_ctr(struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + + b1dma_reset(card); + + div4->detach_ctr(ctrl); + free_irq(card->irq, card); + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + release_region(card->port, AVMB1_PORTLEN); + ctrl->driverdata = 0; + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + + MOD_DEC_USE_COUNT; +} + +static char *b1pciv4_procinfo(struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + + if (!cinfo) + return ""; + sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx r%d", + cinfo->cardname[0] ? cinfo->cardname : "-", + cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", + cinfo->card ? cinfo->card->port : 0x0, + cinfo->card ? cinfo->card->irq : 0, + cinfo->card ? cinfo->card->membase : 0, + cinfo->card ? cinfo->card->revision : 0 + ); + return cinfo->infobuf; +} + +/* ------------------------------------------------------------- */ + +static int b1pciv4_add_card(struct capi_driver *driver, struct capicardparams *p) +{ + unsigned long base, page_offset; + avmcard *card; + avmctrl_info *cinfo; + int retval; + + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); + + if (!card) { + printk(KERN_WARNING "%s: no memory.\n", driver->name); + return -ENOMEM; + } + memset(card, 0, sizeof(avmcard)); + card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC); + if (!card->dma) { + printk(KERN_WARNING "%s: no memory.\n", driver->name); + kfree(card); + return -ENOMEM; + } + memset(card->dma, 0, sizeof(avmcard_dmainfo)); + cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC); + if (!cinfo) { + printk(KERN_WARNING "%s: no memory.\n", driver->name); + kfree(card->dma); + kfree(card); + return -ENOMEM; + } + memset(cinfo, 0, sizeof(avmctrl_info)); + card->ctrlinfo = cinfo; + cinfo->card = card; + sprintf(card->name, "b1pciv4-%x", p->port); + card->port = p->port; + card->irq = p->irq; + card->membase = p->membase; + card->cardtype = avm_b1pci; + + if (check_region(card->port, AVMB1_PORTLEN)) { + printk(KERN_WARNING + "%s: ports 0x%03x-0x%03x in use.\n", + driver->name, card->port, card->port + AVMB1_PORTLEN); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + return -EBUSY; + } + + base = card->membase & PAGE_MASK; + page_offset = card->membase - base; + card->mbase = ioremap_nocache(base, page_offset + 64); + if (card->mbase) { + card->mbase += page_offset; + } else { + printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", + driver->name, card->membase); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + return -EIO; + } + + b1dma_reset(card); + + if ((retval = b1pciv4_detect(card)) != 0) { + printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", + driver->name, card->port, retval); + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + return -EIO; + } + b1dma_reset(card); + b1_getrevision(card); + + request_region(p->port, AVMB1_PORTLEN, card->name); + + retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card); + if (retval) { + printk(KERN_ERR "%s: unable to get IRQ %d.\n", + driver->name, card->irq); + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + release_region(card->port, AVMB1_PORTLEN); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + return -EBUSY; + } + + cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo); + if (!cinfo->capi_ctrl) { + printk(KERN_ERR "%s: attach controller failed.\n", driver->name); + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + free_irq(card->irq, card); + release_region(card->port, AVMB1_PORTLEN); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + return -EBUSY; + } + card->cardnr = cinfo->capi_ctrl->cnr; + + skb_queue_head_init(&card->dma->send_queue); + + printk(KERN_INFO + "%s: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n", + driver->name, card->port, card->irq, + card->membase, card->revision); + + MOD_INC_USE_COUNT; + + return 0; +} + +/* ------------------------------------------------------------- */ + + +static struct capi_driver b1pciv4_driver = { + "b1pciv4", + "0.0", + b1dma_load_firmware, + b1dma_reset_ctr, + b1pciv4_remove_ctr, + b1dma_register_appl, + b1dma_release_appl, + b1dma_send_message, + + b1pciv4_procinfo, + b1dmactl_read_proc, + 0, /* use standard driver_read_proc */ + + 0, /* no add_card function */ +}; + +#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */ + #ifdef MODULE #define b1pci_init init_module void cleanup_module(void); @@ -248,9 +456,55 @@ void cleanup_module(void); static int ncards = 0; +static int add_card(struct pci_dev *dev) +{ + struct capi_driver *driver = &b1pci_driver; + struct capicardparams param; + int retval; + + if (dev->resource[ 2].start & PCI_BASE_ADDRESS_IO_MASK) { /* B1 PCI V4 */ +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + driver = &b1pciv4_driver; +#endif + param.membase = dev->resource[ 0].start & PCI_BASE_ADDRESS_MEM_MASK; + param.port = dev->resource[ 2].start & PCI_BASE_ADDRESS_IO_MASK; + param.irq = dev->irq; + printk(KERN_INFO + "%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n", + driver->name, param.port, param.irq, param.membase); +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + retval = b1pciv4_add_card(driver, ¶m); +#else + retval = b1pci_add_card(driver, ¶m); +#endif + if (retval != 0) { + printk(KERN_ERR + "%s: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n", + driver->name, param.port, param.irq, param.membase); + } + } else { + param.membase = 0; + param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK; + param.irq = dev->irq; + printk(KERN_INFO + "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", + driver->name, param.port, param.irq); + retval = b1pci_add_card(driver, ¶m); + if (retval != 0) { + printk(KERN_ERR + "%s: no AVM-B1 at i/o %#x, irq %d detected\n", + driver->name, param.port, param.irq); + } + } + return retval; +} + int b1pci_init(void) { struct capi_driver *driver = &b1pci_driver; +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + struct capi_driver *driverv4 = &b1pciv4_driver; +#endif struct pci_dev *dev = NULL; char *p; int retval; @@ -271,26 +525,32 @@ int b1pci_init(void) return -EIO; } +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + printk(KERN_INFO "%s: revision %s\n", driverv4->name, driverv4->revision); + + div4 = attach_capi_driver(driverv4); + + if (!div4) { + detach_capi_driver(driver); + printk(KERN_ERR "%s: failed to attach capi_driver\n", + driverv4->name); + return -EIO; + } +#endif + #ifdef CONFIG_PCI if (!pci_present()) { printk(KERN_ERR "%s: no PCI bus present\n", driver->name); detach_capi_driver(driver); +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + detach_capi_driver(driverv4); +#endif return -EIO; } while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev))) { - struct capicardparams param; - - param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK; - param.irq = dev->irq; - printk(KERN_INFO - "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", - driver->name, param.port, param.irq); - retval = b1pci_add_card(driver, ¶m); + retval = add_card(dev); if (retval != 0) { - printk(KERN_ERR - "%s: no AVM-B1 at i/o %#x, irq %d detected\n", - driver->name, param.port, param.irq); #ifdef MODULE cleanup_module(); #endif @@ -315,5 +575,8 @@ int b1pci_init(void) void cleanup_module(void) { detach_capi_driver(&b1pci_driver); +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + detach_capi_driver(&b1pciv4_driver); +#endif } #endif diff --git a/drivers/isdn/avmb1/b1pcmcia.c b/drivers/isdn/avmb1/b1pcmcia.c index 79e343164..6e39c43d2 100644 --- a/drivers/isdn/avmb1/b1pcmcia.c +++ b/drivers/isdn/avmb1/b1pcmcia.c @@ -1,11 +1,19 @@ /* - * $Id: b1pcmcia.c,v 1.5 1999/11/05 16:38:01 calle Exp $ + * $Id: b1pcmcia.c,v 1.7 2000/02/02 18:36:03 calle Exp $ * * Module for AVM B1/M1/M2 PCMCIA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pcmcia.c,v $ + * Revision 1.7 2000/02/02 18:36:03 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.6 2000/01/25 14:37:39 calle + * new message after successfull detection including card revision and + * used resources. + * * Revision 1.5 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -62,7 +70,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.5 $"; +static char *revision = "$Revision: 1.7 $"; /* ------------------------------------------------------------- */ @@ -126,12 +134,16 @@ static int b1pcmcia_add_card(struct capi_driver *driver, { avmctrl_info *cinfo; avmcard *card; + char *cardname; int retval; + MOD_INC_USE_COUNT; + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card, 0, sizeof(avmcard)); @@ -139,6 +151,7 @@ static int b1pcmcia_add_card(struct capi_driver *driver, if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(cinfo, 0, sizeof(avmctrl_info)); @@ -159,9 +172,11 @@ static int b1pcmcia_add_card(struct capi_driver *driver, driver->name, card->port, retval); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } b1_reset(card->port); + b1_getrevision(card); retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card); if (retval) { @@ -169,6 +184,7 @@ static int b1pcmcia_add_card(struct capi_driver *driver, driver->name, card->irq); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -179,10 +195,19 @@ static int b1pcmcia_add_card(struct capi_driver *driver, free_irq(card->irq, card); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } + switch (cardtype) { + case avm_m1: cardname = "M1"; break; + case avm_m2: cardname = "M2"; break; + default : cardname = "B1 PCMCIA"; break; + } + + printk(KERN_INFO + "%s: AVM %s at i/o %#x, irq %d, revision %d\n", + driver->name, cardname, card->port, card->irq, card->revision); - MOD_INC_USE_COUNT; return cinfo->capi_ctrl->cnr; } @@ -194,11 +219,12 @@ static char *b1pcmcia_procinfo(struct capi_ctr *ctrl) if (!cinfo) return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d", + sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", cinfo->cardname[0] ? cinfo->cardname : "-", cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", cinfo->card ? cinfo->card->port : 0x0, - cinfo->card ? cinfo->card->irq : 0 + cinfo->card ? cinfo->card->irq : 0, + cinfo->card ? cinfo->card->revision : 0 ); return cinfo->infobuf; } diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c new file mode 100644 index 000000000..7483370cf --- /dev/null +++ b/drivers/isdn/avmb1/c4.c @@ -0,0 +1,1326 @@ +/* + * $Id: c4.c,v 1.4 2000/02/02 18:36:03 calle Exp $ + * + * Module for AVM C4 card. + * + * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: c4.c,v $ + * Revision 1.4 2000/02/02 18:36:03 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.3 2000/01/25 14:37:39 calle + * new message after successfull detection including card revision and + * used resources. + * + * Revision 1.2 2000/01/21 20:52:58 keil + * pci_find_subsys as local function for 2.2.X kernel + * + * Revision 1.1 2000/01/20 10:51:37 calle + * Added driver for C4. + * + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/capi.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include "capicmd.h" +#include "capiutil.h" +#include "capilli.h" +#include "avmcard.h" + +static char *revision = "$Revision: 1.4 $"; + +#undef CONFIG_C4_DEBUG +#undef CONFIG_C4_POLLDEBUG + +/* ------------------------------------------------------------- */ + +#ifndef PCI_VENDOR_ID_DEC +#define PCI_VENDOR_ID_DEC 0x1011 +#endif + +#ifndef PCI_DEVICE_ID_DEC_21285 +#define PCI_DEVICE_ID_DEC_21285 0x1065 +#endif + +#ifndef PCI_VENDOR_ID_AVM +#define PCI_VENDOR_ID_AVM 0x1244 +#endif + +#ifndef PCI_DEVICE_ID_AVM_C4 +#define PCI_DEVICE_ID_AVM_C4 0x0800 +#endif + +/* ------------------------------------------------------------- */ + +int suppress_pollack = 0; + +MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>"); + +MODULE_PARM(suppress_pollack, "0-1i"); + +/* ------------------------------------------------------------- */ + +static struct capi_driver_interface *di; + +/* ------------------------------------------------------------- */ + +static void c4_dispatch_tx(avmcard *card); + +/* ------------------------------------------------------------- */ + +#define DC21285_DRAM_A0MR 0x40000000 +#define DC21285_DRAM_A1MR 0x40004000 +#define DC21285_DRAM_A2MR 0x40008000 +#define DC21285_DRAM_A3MR 0x4000C000 + +#define CAS_OFFSET 0x88 + +#define DC21285_ARMCSR_BASE 0x42000000 + +#define PCI_OUT_INT_STATUS 0x30 +#define PCI_OUT_INT_MASK 0x34 +#define MAILBOX_0 0x50 +#define MAILBOX_1 0x54 +#define MAILBOX_2 0x58 +#define MAILBOX_3 0x5C +#define DOORBELL 0x60 +#define DOORBELL_SETUP 0x64 + +#define CHAN_1_CONTROL 0x90 +#define CHAN_2_CONTROL 0xB0 +#define DRAM_TIMING 0x10C +#define DRAM_ADDR_SIZE_0 0x110 +#define DRAM_ADDR_SIZE_1 0x114 +#define DRAM_ADDR_SIZE_2 0x118 +#define DRAM_ADDR_SIZE_3 0x11C +#define SA_CONTROL 0x13C +#define XBUS_CYCLE 0x148 +#define XBUS_STROBE 0x14C +#define DBELL_PCI_MASK 0x150 +#define DBELL_SA_MASK 0x154 + +#define SDRAM_SIZE 0x1000000 + +/* ------------------------------------------------------------- */ + +#define MBOX_PEEK_POKE MAILBOX_0 + +#define DBELL_ADDR 0x01 +#define DBELL_DATA 0x02 +#define DBELL_RNWR 0x40 +#define DBELL_INIT 0x80 + +/* ------------------------------------------------------------- */ + +#define MBOX_UP_ADDR MAILBOX_0 +#define MBOX_UP_LEN MAILBOX_1 +#define MBOX_DOWN_ADDR MAILBOX_2 +#define MBOX_DOWN_LEN MAILBOX_3 + +#define DBELL_UP_HOST 0x00000100 +#define DBELL_UP_ARM 0x00000200 +#define DBELL_DOWN_HOST 0x00000400 +#define DBELL_DOWN_ARM 0x00000800 +#define DBELL_RESET_HOST 0x40000000 +#define DBELL_RESET_ARM 0x80000000 + +/* ------------------------------------------------------------- */ + +#define DRAM_TIMING_DEF 0x001A01A5 +#define DRAM_AD_SZ_DEF0 0x00000045 +#define DRAM_AD_SZ_NULL 0x00000000 + +#define SA_CTL_ALLRIGHT 0x64AA0271 + +#define INIT_XBUS_CYCLE 0x100016DB +#define INIT_XBUS_STROBE 0xF1F1F1F1 + +/* ------------------------------------------------------------- */ + +#define RESET_TIMEOUT (15*HZ) /* 15 sec */ +#define PEEK_POKE_TIMEOUT (HZ/10) /* 0.1 sec */ + +/* ------------------------------------------------------------- */ + +#define c4outmeml(addr, value) writel(value, addr) +#define c4inmeml(addr) readl(addr) +#define c4outmemw(addr, value) writew(value, addr) +#define c4inmemw(addr) readw(addr) +#define c4outmemb(addr, value) writeb(value, addr) +#define c4inmemb(addr) readb(addr) + +/* ------------------------------------------------------------- */ + +static inline int wait_for_doorbell(avmcard *card, unsigned long t) +{ + unsigned long stop; + + stop = jiffies + t; + while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) { + if (!time_before(jiffies, stop)) + return -1; + } + return 0; +} + +static int c4_poke(avmcard *card, unsigned long off, unsigned long value) +{ + + if (wait_for_doorbell(card, HZ/10) < 0) + return -1; + + c4outmeml(card->mbase+MBOX_PEEK_POKE, off); + c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); + + if (wait_for_doorbell(card, HZ/10) < 0) + return -1; + + c4outmeml(card->mbase+MBOX_PEEK_POKE, value); + c4outmeml(card->mbase+DOORBELL, DBELL_DATA | DBELL_ADDR); + + return 0; +} + +static int c4_peek(avmcard *card, unsigned long off, unsigned long *valuep) +{ + if (wait_for_doorbell(card, HZ/10) < 0) + return -1; + + c4outmeml(card->mbase+MBOX_PEEK_POKE, off); + c4outmeml(card->mbase+DOORBELL, DBELL_RNWR | DBELL_ADDR); + + if (wait_for_doorbell(card, HZ/10) < 0) + return -1; + + *valuep = c4inmeml(card->mbase+MBOX_PEEK_POKE); + + return 0; +} + +/* ------------------------------------------------------------- */ + +static int c4_load_t4file(avmcard *card, capiloaddatapart * t4file) +{ + __u32 val; + unsigned char *dp; + int left, retval; + __u32 loadoff = 0; + + dp = t4file->data; + left = t4file->len; + while (left >= sizeof(__u32)) { + if (t4file->user) { + retval = copy_from_user(&val, dp, sizeof(val)); + if (retval) + return -EFAULT; + } else { + memcpy(&val, dp, sizeof(val)); + } + if (c4_poke(card, loadoff, val)) { + printk(KERN_ERR "%s: corrupted firmware file ?\n", + card->name); + return -EIO; + } + left -= sizeof(__u32); + dp += sizeof(__u32); + loadoff += sizeof(__u32); + } + if (left) { + val = 0; + if (t4file->user) { + retval = copy_from_user(&val, dp, left); + if (retval) + return -EFAULT; + } else { + memcpy(&val, dp, left); + } + if (c4_poke(card, loadoff, val)) { + printk(KERN_ERR "%s: corrupted firmware file ?\n", + card->name); + return -EIO; + } + } + return 0; +} + +/* ------------------------------------------------------------- */ + +static inline void _put_byte(void **pp, __u8 val) +{ + __u8 *s = *pp; + *s++ = val; + *pp = s; +} + +static inline void _put_word(void **pp, __u32 val) +{ + __u8 *s = *pp; + *s++ = val & 0xff; + *s++ = (val >> 8) & 0xff; + *s++ = (val >> 16) & 0xff; + *s++ = (val >> 24) & 0xff; + *pp = s; +} + +static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len) +{ + unsigned i = len; + _put_word(pp, i); + while (i-- > 0) + _put_byte(pp, *dp++); +} + +static inline __u8 _get_byte(void **pp) +{ + __u8 *s = *pp; + __u8 val; + val = *s++; + *pp = s; + return val; +} + +static inline __u32 _get_word(void **pp) +{ + __u8 *s = *pp; + __u32 val; + val = *s++; + val |= (*s++ << 8); + val |= (*s++ << 16); + val |= (*s++ << 24); + *pp = s; + return val; +} + +static inline __u32 _get_slice(void **pp, unsigned char *dp) +{ + unsigned int len, i; + + len = i = _get_word(pp); + while (i-- > 0) *dp++ = _get_byte(pp); + return len; +} + +/* ------------------------------------------------------------- */ + +static void c4_reset(avmcard *card) +{ + unsigned long stop; + + c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM); + + stop = jiffies + HZ*10; + while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) { + if (!time_before(jiffies, stop)) + return; + c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); + } + + c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0); + c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0); +} + +/* ------------------------------------------------------------- */ + +static int c4_detect(avmcard *card) +{ + unsigned long stop, dummy; + + c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c); + if (c4inmeml(card->mbase+PCI_OUT_INT_MASK) != 0x0c) + return 1; + + c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM); + + stop = jiffies + HZ*10; + while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) { + if (!time_before(jiffies, stop)) + return 2; + c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); + } + + c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0); + c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0); + + c4outmeml(card->mbase+MAILBOX_0, 0x55aa55aa); + if (c4inmeml(card->mbase+MAILBOX_0) != 0x55aa55aa) return 3; + + c4outmeml(card->mbase+MAILBOX_0, 0xaa55aa55); + if (c4inmeml(card->mbase+MAILBOX_0) != 0xaa55aa55) return 4; + + if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_SA_MASK, 0)) return 5; + if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_PCI_MASK, 0)) return 6; + if (c4_poke(card, DC21285_ARMCSR_BASE+SA_CONTROL, SA_CTL_ALLRIGHT)) + return 7; + if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_CYCLE, INIT_XBUS_CYCLE)) + return 8; + if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_STROBE, INIT_XBUS_STROBE)) + return 8; + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, 0)) return 9; + + udelay(1000); + + if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10; + if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11; + if (c4_peek(card, DC21285_DRAM_A2MR, &dummy)) return 12; + if (c4_peek(card, DC21285_DRAM_A3MR, &dummy)) return 13; + + if (c4_poke(card, DC21285_DRAM_A0MR+CAS_OFFSET, 0)) return 14; + if (c4_poke(card, DC21285_DRAM_A1MR+CAS_OFFSET, 0)) return 15; + if (c4_poke(card, DC21285_DRAM_A2MR+CAS_OFFSET, 0)) return 16; + if (c4_poke(card, DC21285_DRAM_A3MR+CAS_OFFSET, 0)) return 17; + + udelay(1000); + + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, DRAM_TIMING_DEF)) + return 18; + + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_0,DRAM_AD_SZ_DEF0)) + return 19; + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_1,DRAM_AD_SZ_NULL)) + return 20; + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_2,DRAM_AD_SZ_NULL)) + return 21; + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_3,DRAM_AD_SZ_NULL)) + return 22; + + /* Transputer test */ + + if ( c4_poke(card, 0x000000, 0x11111111) + || c4_poke(card, 0x400000, 0x22222222) + || c4_poke(card, 0x800000, 0x33333333) + || c4_poke(card, 0xC00000, 0x44444444)) + return 23; + + if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x11111111 + || c4_peek(card, 0x400000, &dummy) || dummy != 0x22222222 + || c4_peek(card, 0x800000, &dummy) || dummy != 0x33333333 + || c4_peek(card, 0xC00000, &dummy) || dummy != 0x44444444) + return 24; + + if ( c4_poke(card, 0x000000, 0x55555555) + || c4_poke(card, 0x400000, 0x66666666) + || c4_poke(card, 0x800000, 0x77777777) + || c4_poke(card, 0xC00000, 0x88888888)) + return 25; + + if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x55555555 + || c4_peek(card, 0x400000, &dummy) || dummy != 0x66666666 + || c4_peek(card, 0x800000, &dummy) || dummy != 0x77777777 + || c4_peek(card, 0xC00000, &dummy) || dummy != 0x88888888) + return 26; + + return 0; +} + +/* ------------------------------------------------------------- */ + +static void c4_dispatch_tx(avmcard *card) +{ + avmcard_dmainfo *dma = card->dma; + unsigned long flags; + struct sk_buff *skb; + __u8 cmd, subcmd; + __u16 len; + __u32 txlen; + void *p; + + save_flags(flags); + cli(); + + if (card->csr & DBELL_DOWN_ARM) { /* tx busy */ + restore_flags(flags); + return; + } + + skb = skb_dequeue(&dma->send_queue); + if (!skb) { +#ifdef CONFIG_C4_DEBUG + printk(KERN_DEBUG "%s: tx underrun\n", card->name); +#endif + restore_flags(flags); + return; + } + + len = CAPIMSG_LEN(skb->data); + + if (len) { + cmd = CAPIMSG_COMMAND(skb->data); + subcmd = CAPIMSG_SUBCOMMAND(skb->data); + + p = dma->sendbuf; + + if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { + __u16 dlen = CAPIMSG_DATALEN(skb->data); + _put_byte(&p, SEND_DATA_B3_REQ); + _put_slice(&p, skb->data, len); + _put_slice(&p, skb->data + len, dlen); + } else { + _put_byte(&p, SEND_MESSAGE); + _put_slice(&p, skb->data, len); + } + txlen = (__u8 *)p - (__u8 *)dma->sendbuf; +#ifdef CONFIG_C4_DEBUG + printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen); +#endif + } else { + txlen = skb->len-2; +#ifdef CONFIG_C4_POLLDEBUG + if (skb->data[2] == SEND_POLLACK) + printk(KERN_INFO "%s: ack to c4\n", card->name); +#endif +#ifdef CONFIG_C4_DEBUG + printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n", + card->name, skb->data[2], txlen); +#endif + memcpy(dma->sendbuf, skb->data+2, skb->len-2); + } + txlen = (txlen + 3) & ~3; + + c4outmeml(card->mbase+MBOX_DOWN_ADDR, virt_to_phys(dma->sendbuf)); + c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen); + + card->csr |= DBELL_DOWN_ARM; + + c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM); + + restore_flags(flags); + dev_kfree_skb(skb); +} + +/* ------------------------------------------------------------- */ + +static void queue_pollack(avmcard *card) +{ + struct sk_buff *skb; + void *p; + + skb = alloc_skb(3, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost poll ack\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_POLLACK); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); +} + +/* ------------------------------------------------------------- */ + +static void c4_handle_rx(avmcard *card) +{ + avmcard_dmainfo *dma = card->dma; + struct capi_ctr *ctrl; + avmctrl_info *cinfo; + struct sk_buff *skb; + void *p = dma->recvbuf; + __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; + __u8 b1cmd = _get_byte(&p); + __u32 cidx; + + +#ifdef CONFIG_C4_DEBUG + printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name, + b1cmd, (unsigned long)dma->recvlen); +#endif + + switch (b1cmd) { + case RECEIVE_DATA_B3_IND: + + ApplId = (unsigned) _get_word(&p); + MsgLen = _get_slice(&p, card->msgbuf); + DataB3Len = _get_slice(&p, card->databuf); + cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr; + if (cidx > 3) cidx = 0; + ctrl = card->ctrlinfo[cidx].capi_ctrl; + + if (MsgLen < 30) { /* not CAPI 64Bit */ + memset(card->msgbuf+MsgLen, 0, 30-MsgLen); + MsgLen = 30; + CAPIMSG_SETLEN(card->msgbuf, 30); + } + if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) { + printk(KERN_ERR "%s: incoming packet dropped\n", + card->name); + } else { + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); + ctrl->handle_capimsg(ctrl, ApplId, skb); + } + break; + + case RECEIVE_MESSAGE: + + ApplId = (unsigned) _get_word(&p); + MsgLen = _get_slice(&p, card->msgbuf); + cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr; + if (cidx > 3) cidx = 0; + ctrl = card->ctrlinfo[cidx].capi_ctrl; + + if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { + printk(KERN_ERR "%s: incoming packet dropped\n", + card->name); + } else { + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + ctrl->handle_capimsg(ctrl, ApplId, skb); + } + break; + + case RECEIVE_NEW_NCCI: + + ApplId = _get_word(&p); + NCCI = _get_word(&p); + WindowSize = _get_word(&p); + cidx = (NCCI&0x7f) - card->cardnr; + if (cidx > 3) cidx = 0; + ctrl = card->ctrlinfo[cidx].capi_ctrl; + + ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize); + + break; + + case RECEIVE_FREE_NCCI: + + ApplId = _get_word(&p); + NCCI = _get_word(&p); + + if (NCCI != 0xffffffff) { + cidx = (NCCI&0x7f) - card->cardnr; + if (cidx > 3) cidx = 0; + ctrl = card->ctrlinfo[cidx].capi_ctrl; + ctrl->free_ncci(ctrl, ApplId, NCCI); + } else { + for (cidx=0; cidx < 4; cidx++) { + ctrl = card->ctrlinfo[cidx].capi_ctrl; + ctrl->appl_released(ctrl, ApplId); + } + } + break; + + case RECEIVE_START: +#ifdef CONFIG_C4_POLLDEBUG + printk(KERN_INFO "%s: poll from c4\n", card->name); +#endif + if (!suppress_pollack) + queue_pollack(card); + for (cidx=0; cidx < 4; cidx++) { + ctrl = card->ctrlinfo[cidx].capi_ctrl; + ctrl->resume_output(ctrl); + } + break; + + case RECEIVE_STOP: + for (cidx=0; cidx < 4; cidx++) { + ctrl = card->ctrlinfo[cidx].capi_ctrl; + ctrl->suspend_output(ctrl); + } + break; + + case RECEIVE_INIT: + + cidx = card->nlogcontr++; + cinfo = &card->ctrlinfo[cidx]; + ctrl = cinfo->capi_ctrl; + cinfo->versionlen = _get_slice(&p, cinfo->versionbuf); + b1_parse_version(cinfo); + printk(KERN_INFO "%s: %s-card (%s) now active\n", + card->name, + cinfo->version[VER_CARDTYPE], + cinfo->version[VER_DRIVER]); + ctrl->ready(cinfo->capi_ctrl); + break; + + case RECEIVE_TASK_READY: + ApplId = (unsigned) _get_word(&p); + MsgLen = _get_slice(&p, card->msgbuf); + card->msgbuf[MsgLen--] = 0; + while ( MsgLen >= 0 + && ( card->msgbuf[MsgLen] == '\n' + || card->msgbuf[MsgLen] == '\r')) + card->msgbuf[MsgLen--] = 0; + printk(KERN_INFO "%s: task %d \"%s\" ready.\n", + card->name, ApplId, card->msgbuf); + break; + + case RECEIVE_DEBUGMSG: + MsgLen = _get_slice(&p, card->msgbuf); + card->msgbuf[MsgLen--] = 0; + while ( MsgLen >= 0 + && ( card->msgbuf[MsgLen] == '\n' + || card->msgbuf[MsgLen] == '\r')) + card->msgbuf[MsgLen--] = 0; + printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); + break; + + default: + printk(KERN_ERR "%s: c4_interrupt: 0x%x ???\n", + card->name, b1cmd); + return; + } +} + +/* ------------------------------------------------------------- */ + +static void c4_handle_interrupt(avmcard *card) +{ + __u32 status = c4inmeml(card->mbase+DOORBELL); + + if (status & DBELL_RESET_HOST) { + int i; + c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c); + printk(KERN_ERR "%s: unexpected reset\n", card->name); + for (i=0; i < 4; i++) { + avmctrl_info *cinfo = &card->ctrlinfo[i]; + memset(cinfo->version, 0, sizeof(cinfo->version)); + if (cinfo->capi_ctrl) + cinfo->capi_ctrl->reseted(cinfo->capi_ctrl); + } + return; + } + + status &= (DBELL_UP_HOST | DBELL_DOWN_HOST); + if (!status) + return; + c4outmeml(card->mbase+DOORBELL, status); + + if ((status & DBELL_UP_HOST) != 0) { + card->dma->recvlen = c4inmeml(card->mbase+MBOX_UP_LEN); + c4outmeml(card->mbase+MBOX_UP_LEN, 0); + c4_handle_rx(card); + card->dma->recvlen = 0; + c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf)); + c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); + } + + if ((status & DBELL_DOWN_HOST) != 0) { + card->csr &= ~DBELL_DOWN_ARM; + c4_dispatch_tx(card); + } else if (card->csr & DBELL_DOWN_HOST) { + if (c4inmeml(card->mbase+MBOX_DOWN_LEN) == 0) { + card->csr &= ~DBELL_DOWN_ARM; + c4_dispatch_tx(card); + } + } +} + +static void c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +{ + avmcard *card; + + card = (avmcard *) devptr; + + if (!card) { + printk(KERN_WARNING "%s: interrupt: wrong device\n", card->name); + return; + } + if (card->interrupt) { + printk(KERN_ERR "%s: reentering interrupt hander\n", + card->name); + return; + } + + card->interrupt = 1; + + c4_handle_interrupt(card); + + card->interrupt = 0; +} + +/* ------------------------------------------------------------- */ + +static void c4_send_init(avmcard *card) +{ + struct sk_buff *skb; + void *p; + + skb = alloc_skb(15, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost register appl.\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_INIT); + _put_word(&p, AVM_NAPPS); + _put_word(&p, AVM_NCCI_PER_CHANNEL*30); + _put_word(&p, card->cardnr - 1); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); +} + +static int c4_send_config(avmcard *card, capiloaddatapart * config) +{ + struct sk_buff *skb; + __u8 val[sizeof(__u32)]; + void *p; + unsigned char *dp; + int left, retval; + + skb = alloc_skb(12 + ((config->len+3)/4)*5, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, can't send config.\n", + card->name); + return -ENOMEM; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_CONFIG); + _put_word(&p, 1); + _put_byte(&p, SEND_CONFIG); + _put_word(&p, config->len); /* 12 */ + + dp = config->data; + left = config->len; + while (left >= sizeof(__u32)) { + if (config->user) { + retval = copy_from_user(val, dp, sizeof(val)); + if (retval) { + dev_kfree_skb(skb); + return -EFAULT; + } + } else { + memcpy(val, dp, sizeof(val)); + } + _put_byte(&p, SEND_CONFIG); + _put_byte(&p, val[0]); + _put_byte(&p, val[1]); + _put_byte(&p, val[2]); + _put_byte(&p, val[3]); + left -= sizeof(val); + dp += sizeof(val); + } + if (left) { + memset(val, 0, sizeof(val)); + if (config->user) { + retval = copy_from_user(&val, dp, left); + if (retval) { + dev_kfree_skb(skb); + return -EFAULT; + } + } else { + memcpy(&val, dp, left); + } + _put_byte(&p, SEND_CONFIG); + _put_byte(&p, val[0]); + _put_byte(&p, val[1]); + _put_byte(&p, val[2]); + _put_byte(&p, val[3]); + } + + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); + + return 0; +} + +static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + unsigned long flags; + int retval; + + if ((retval = c4_load_t4file(card, &data->firmware))) { + printk(KERN_ERR "%s: failed to load t4file!!\n", + card->name); + c4_reset(card); + return retval; + } + + save_flags(flags); + cli(); + + card->csr = 0; + c4outmeml(card->mbase+MBOX_UP_LEN, 0); + c4outmeml(card->mbase+MBOX_DOWN_LEN, 0); + c4outmeml(card->mbase+DOORBELL, DBELL_INIT); + udelay(1000); + c4outmeml(card->mbase+DOORBELL, + DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST); + + c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08); + + card->dma->recvlen = 0; + c4outmeml(card->mbase+MBOX_UP_ADDR, virt_to_phys(card->dma->recvbuf)); + c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf)); + c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); + restore_flags(flags); + + if (data->configuration.len > 0 && data->configuration.data) + c4_send_config(card, &data->configuration); + + c4_send_init(card); + + return 0; +} + + +void c4_reset_ctr(struct capi_ctr *ctrl) +{ + avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card; + avmctrl_info *cinfo; + int i; + + c4_reset(card); + + for (i=0; i < 4; i++) { + cinfo = &card->ctrlinfo[i]; + memset(cinfo->version, 0, sizeof(cinfo->version)); + if (cinfo->capi_ctrl) + cinfo->capi_ctrl->reseted(cinfo->capi_ctrl); + } +} + +static void c4_remove_ctr(struct capi_ctr *ctrl) +{ + avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card; + avmctrl_info *cinfo; + int i; + + c4_reset(card); + + for (i=0; i <= 4; i++) { + cinfo = &card->ctrlinfo[i]; + if (cinfo->capi_ctrl) + di->detach_ctr(cinfo->capi_ctrl); + } + + free_irq(card->irq, card); + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + release_region(card->port, AVMB1_PORTLEN); + ctrl->driverdata = 0; + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + + MOD_DEC_USE_COUNT; +} + +/* ------------------------------------------------------------- */ + + +void c4_register_appl(struct capi_ctr *ctrl, + __u16 appl, + capi_register_params *rp) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + struct sk_buff *skb; + int want = rp->level3cnt; + int nconn; + void *p; + + if (ctrl->cnr == card->cardnr) { + + if (want > 0) nconn = want; + else nconn = ctrl->profile.nbchannel * 4 * -want; + if (nconn == 0) nconn = ctrl->profile.nbchannel * 4; + + skb = alloc_skb(23, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost register appl.\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_REGISTER); + _put_word(&p, appl); + _put_word(&p, 1024 * (nconn+1)); + _put_word(&p, nconn); + _put_word(&p, rp->datablkcnt); + _put_word(&p, rp->datablklen); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); + } + + ctrl->appl_registered(ctrl, appl); +} + +/* ------------------------------------------------------------- */ + +void c4_release_appl(struct capi_ctr *ctrl, __u16 appl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + struct sk_buff *skb; + void *p; + + if (ctrl->cnr == card->cardnr) { + skb = alloc_skb(7, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost release appl.\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_RELEASE); + _put_word(&p, appl); + + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); + } +} + +/* ------------------------------------------------------------- */ + + +static void c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); +} + +/* ------------------------------------------------------------- */ + +static char *c4_procinfo(struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + + if (!cinfo) + return ""; + sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx", + cinfo->cardname[0] ? cinfo->cardname : "-", + cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", + cinfo->card ? cinfo->card->port : 0x0, + cinfo->card ? cinfo->card->irq : 0, + cinfo->card ? cinfo->card->membase : 0 + ); + return cinfo->infobuf; +} + +static int c4_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + __u8 flag; + int len = 0; + char *s; + + len += sprintf(page+len, "%-16s %s\n", "name", card->name); + len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); + len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); + len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase); + switch (card->cardtype) { + case avm_b1isa: s = "B1 ISA"; break; + case avm_b1pci: s = "B1 PCI"; break; + case avm_b1pcmcia: s = "B1 PCMCIA"; break; + case avm_m1: s = "M1"; break; + case avm_m2: s = "M2"; break; + case avm_t1isa: s = "T1 ISA (HEMA)"; break; + case avm_t1pci: s = "T1 PCI"; break; + case avm_c4: s = "C4"; break; + default: s = "???"; break; + } + len += sprintf(page+len, "%-16s %s\n", "type", s); + if ((s = cinfo->version[VER_DRIVER]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + if ((s = cinfo->version[VER_CARDTYPE]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + if ((s = cinfo->version[VER_SERIAL]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + + if (card->cardtype != avm_m1) { + flag = ((__u8 *)(ctrl->profile.manu))[3]; + if (flag) + len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n", + "protocol", + (flag & 0x01) ? " DSS1" : "", + (flag & 0x02) ? " CT1" : "", + (flag & 0x04) ? " VN3" : "", + (flag & 0x08) ? " NI1" : "", + (flag & 0x10) ? " AUSTEL" : "", + (flag & 0x20) ? " ESS" : "", + (flag & 0x40) ? " 1TR6" : "" + ); + } + if (card->cardtype != avm_m1) { + flag = ((__u8 *)(ctrl->profile.manu))[5]; + if (flag) + len += sprintf(page+len, "%-16s%s%s%s%s\n", + "linetype", + (flag & 0x01) ? " point to point" : "", + (flag & 0x02) ? " point to multipoint" : "", + (flag & 0x08) ? " leased line without D-channel" : "", + (flag & 0x04) ? " leased line with D-channel" : "" + ); + } + len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); + + if (off+count >= len) + *eof = 1; + if (len < off) + return 0; + *start = page + off; + return ((count < len-off) ? count : len-off); +} + +/* ------------------------------------------------------------- */ + +static int c4_add_card(struct capi_driver *driver, struct capicardparams *p) +{ + unsigned long base, page_offset; + avmctrl_info *cinfo; + avmcard *card; + int retval; + int i; + + MOD_INC_USE_COUNT; + + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); + + if (!card) { + printk(KERN_WARNING "%s: no memory.\n", driver->name); + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + memset(card, 0, sizeof(avmcard)); + card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC); + if (!card->dma) { + printk(KERN_WARNING "%s: no memory.\n", driver->name); + kfree(card); + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + memset(card->dma, 0, sizeof(avmcard_dmainfo)); + cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC); + if (!cinfo) { + printk(KERN_WARNING "%s: no memory.\n", driver->name); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + memset(cinfo, 0, sizeof(avmctrl_info)*4); + card->ctrlinfo = cinfo; + for (i=0; i < 4; i++) { + cinfo = &card->ctrlinfo[i]; + cinfo->card = card; + } + sprintf(card->name, "c4-%x", p->port); + card->port = p->port; + card->irq = p->irq; + card->membase = p->membase; + card->cardtype = avm_c4; + + if (check_region(card->port, AVMB1_PORTLEN)) { + printk(KERN_WARNING + "%s: ports 0x%03x-0x%03x in use.\n", + driver->name, card->port, card->port + AVMB1_PORTLEN); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + base = card->membase & PAGE_MASK; + page_offset = card->membase - base; + card->mbase = ioremap_nocache(base, page_offset + 128); + if (card->mbase) { + card->mbase += page_offset; + } else { + printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", + driver->name, card->membase); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + MOD_DEC_USE_COUNT; + return -EIO; + } + + if ((retval = c4_detect(card)) != 0) { + printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", + driver->name, card->port, retval); + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + MOD_DEC_USE_COUNT; + return -EIO; + } + c4_reset(card); + + request_region(p->port, AVMB1_PORTLEN, card->name); + + retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card); + if (retval) { + printk(KERN_ERR "%s: unable to get IRQ %d.\n", + driver->name, card->irq); + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + release_region(card->port, AVMB1_PORTLEN); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + for (i=0; i < 4; i++) { + cinfo = &card->ctrlinfo[i]; + cinfo->card = card; + cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo); + if (!cinfo->capi_ctrl) { + printk(KERN_ERR "%s: attach controller failed (%d).\n", + driver->name, i); + for (i--; i >= 0; i--) { + cinfo = &card->ctrlinfo[i]; + di->detach_ctr(cinfo->capi_ctrl); + } + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + free_irq(card->irq, card); + release_region(card->port, AVMB1_PORTLEN); + kfree(card->dma); + kfree(card->ctrlinfo); + kfree(card); + MOD_DEC_USE_COUNT; + return -EBUSY; + } + if (i == 0) + card->cardnr = cinfo->capi_ctrl->cnr; + } + + skb_queue_head_init(&card->dma->send_queue); + + printk(KERN_INFO + "%s: AVM C4 at i/o %#x, irq %d, mem %#lx\n", + driver->name, card->port, card->irq, card->membase); + + return 0; +} + +/* ------------------------------------------------------------- */ + +static struct capi_driver c4_driver = { + "c4", + "0.0", + c4_load_firmware, + c4_reset_ctr, + c4_remove_ctr, + c4_register_appl, + c4_release_appl, + c4_send_message, + + c4_procinfo, + c4_read_proc, + 0, /* use standard driver_read_proc */ + + 0, /* no add_card function */ +}; + +#ifdef MODULE +#define c4_init init_module +void cleanup_module(void); +#endif + + +static int ncards = 0; + +int c4_init(void) +{ + struct capi_driver *driver = &c4_driver; + struct pci_dev *dev = NULL; + char *p; + int retval; + + if ((p = strchr(revision, ':'))) { + strncpy(driver->revision, p + 1, sizeof(driver->revision)); + p = strchr(driver->revision, '$'); + *p = 0; + } + + printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); + + di = attach_capi_driver(driver); + + if (!di) { + printk(KERN_ERR "%s: failed to attach capi_driver\n", + driver->name); + return -EIO; + } + +#ifdef CONFIG_PCI + if (!pci_present()) { + printk(KERN_ERR "%s: no PCI bus present\n", driver->name); + detach_capi_driver(driver); + return -EIO; + } + + while ((dev = pci_find_subsys( + PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, + PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, dev))) { + struct capicardparams param; + + param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK; + param.irq = dev->irq; + param.membase = dev->resource[ 0].start & PCI_BASE_ADDRESS_MEM_MASK; + + printk(KERN_INFO + "%s: PCI BIOS reports AVM-C4 at i/o %#x, irq %d, mem %#x\n", + driver->name, param.port, param.irq, param.membase); + retval = c4_add_card(driver, ¶m); + if (retval != 0) { + printk(KERN_ERR + "%s: no AVM-C4 at i/o %#x, irq %d detected, mem %#x\n", + driver->name, param.port, param.irq, param.membase); +#ifdef MODULE + cleanup_module(); +#endif + return retval; + } + ncards++; + } + if (ncards) { + printk(KERN_INFO "%s: %d C4 card(s) detected\n", + driver->name, ncards); + return 0; + } + printk(KERN_ERR "%s: NO C4 card detected\n", driver->name); + return -ESRCH; +#else + printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name); + return -EIO; +#endif +} + +#ifdef MODULE +void cleanup_module(void) +{ + detach_capi_driver(&c4_driver); +} +#endif diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c index 6214a7c75..62f246407 100644 --- a/drivers/isdn/avmb1/capi.c +++ b/drivers/isdn/avmb1/capi.c @@ -128,6 +128,7 @@ #include <linux/poll.h> #include <linux/capi.h> #include <linux/kernelcapi.h> +#include <linux/devfs_fs_kernel.h> #include "capiutil.h" #include "capicmd.h" @@ -511,13 +512,18 @@ capi_release(struct inode *inode, struct file *file) static struct file_operations capi_fops = { - llseek: capi_llseek, - read: capi_read, - write: capi_write, - poll: capi_poll, - ioctl: capi_ioctl, - open: capi_open, - release: capi_release, + capi_llseek, + capi_read, + capi_write, + NULL, /* capi_readdir */ + capi_poll, + capi_ioctl, + NULL, /* capi_mmap */ + capi_open, + NULL, /* capi_flush */ + capi_release, + NULL, /* capi_fsync */ + NULL, /* capi_fasync */ }; /* -------- /proc functions ----------------------------------- */ @@ -616,14 +622,36 @@ int capi_init(void) init_waitqueue_head(&capidevs[j].recv_wait); } - if (register_chrdev(capi_major, "capi20", &capi_fops)) { + if (devfs_register_chrdev(capi_major, "capi20", &capi_fops)) { printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); return -EIO; } + devfs_register (NULL, "isdn/capi20", 0, DEVFS_FL_DEFAULT, + capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + &capi_fops, NULL); + devfs_register_series (NULL, "isdn/capi20.0%u", 10, DEVFS_FL_DEFAULT, + capi_major, 1, + S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + &capi_fops, NULL); + devfs_register_series (NULL, "isdn/capi20.1%u", 10, DEVFS_FL_DEFAULT, + capi_major, 11, + S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + &capi_fops, NULL); printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major); if ((capifuncs = attach_capi_interface(&cuser)) == 0) { - unregister_chrdev(capi_major, "capi20"); + devfs_unregister_chrdev(capi_major, "capi20"); + devfs_unregister(devfs_find_handle(NULL, "capi20", 0, + capi_major, 0, + DEVFS_SPECIAL_CHR, 0)); + for (j = 0; j < 10; j++) { + char devname[32]; + + sprintf(devname, "isdn/capi20.0%i", j); + devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 1, DEVFS_SPECIAL_CHR, 0)); + sprintf (devname, "isdn/capi20.1%i", j); + devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 11, DEVFS_SPECIAL_CHR, 0)); + } return -EIO; } (void)proc_init(); @@ -633,8 +661,18 @@ int capi_init(void) #ifdef MODULE void cleanup_module(void) { + int i; + char devname[32]; + (void)proc_exit(); - unregister_chrdev(capi_major, "capi20"); + devfs_unregister_chrdev(capi_major, "capi20"); + devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", 0, capi_major, 0, DEVFS_SPECIAL_CHR, 0)); + for (i = 0; i < 10; i++) { + sprintf (devname, "isdn/capi20.0%i", i); + devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 1, DEVFS_SPECIAL_CHR, 0)); + sprintf (devname, "isdn/capi20.1%i", i); + devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 11, DEVFS_SPECIAL_CHR, 0)); + } (void) detach_capi_interface(&cuser); } diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c index 6db170e42..79bb370d1 100644 --- a/drivers/isdn/avmb1/capidrv.c +++ b/drivers/isdn/avmb1/capidrv.c @@ -1,11 +1,14 @@ /* - * $Id: capidrv.c,v 1.28 1999/11/05 16:22:37 calle Exp $ + * $Id: capidrv.c,v 1.29 1999/12/06 17:13:06 calle Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.c,v $ + * Revision 1.29 1999/12/06 17:13:06 calle + * Added controller watchdog. + * * Revision 1.28 1999/11/05 16:22:37 calle * Bugfix: Missing break in switch on ISDN_CMD_HANGUP. * @@ -168,7 +171,7 @@ #include "capicmd.h" #include "capidrv.h" -static char *revision = "$Revision: 1.28 $"; +static char *revision = "$Revision: 1.29 $"; int debugmode = 0; MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>"); @@ -196,6 +199,7 @@ struct capidrv_contr { int state; __u32 cipmask; __u32 cipmask2; + struct timer_list listentimer; /* * ID of capi message sent @@ -2188,6 +2192,29 @@ static void disable_dchannel_trace(capidrv_contr *card) send_message(card, &cmdcmsg); } +static void send_listen(capidrv_contr *card) +{ + capi_fill_LISTEN_REQ(&cmdcmsg, global.appid, + card->msgid++, + card->contrnr, /* controller */ + 1 << 6, /* Infomask */ + card->cipmask, + card->cipmask2, + 0, 0); + send_message(card, &cmdcmsg); + listen_change_state(card, EV_LISTEN_REQ); +} + +static void listentimerfunc(unsigned long x) +{ + capidrv_contr *card = (capidrv_contr *)x; + if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE) + printk(KERN_ERR "%s: controller dead ??\n", card->name); + send_listen(card); + mod_timer(&card->listentimer, jiffies + 60*HZ); +} + + static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) { capidrv_contr *card; @@ -2202,6 +2229,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) return -1; } memset(card, 0, sizeof(capidrv_contr)); + init_timer(&card->listentimer); strcpy(card->name, id); card->contrnr = contr; card->nbchan = profp->nbchannel; @@ -2258,15 +2286,11 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) card->cipmask = 0x1FFF03FF; /* any */ card->cipmask2 = 0; - capi_fill_LISTEN_REQ(&cmdcmsg, global.appid, - card->msgid++, - contr, /* controller */ - 1 << 6, /* Infomask */ - card->cipmask, - card->cipmask2, - 0, 0); - send_message(card, &cmdcmsg); - listen_change_state(card, EV_LISTEN_REQ); + send_listen(card); + + card->listentimer.data = (unsigned long)card; + card->listentimer.function = listentimerfunc; + mod_timer(&card->listentimer, jiffies + 60*HZ); printk(KERN_INFO "%s: now up (%d B channels)\n", card->name, card->nbchan); @@ -2312,6 +2336,7 @@ static int capidrv_delcontr(__u16 contr) printk(KERN_ERR "capidrv: bug in free_plci()\n"); } kfree(card->bchans); + del_timer(&card->listentimer); printk(KERN_INFO "%s: now down.\n", card->name); diff --git a/drivers/isdn/avmb1/kcapi.c b/drivers/isdn/avmb1/kcapi.c index 84fb0d2f7..d82fbc496 100644 --- a/drivers/isdn/avmb1/kcapi.c +++ b/drivers/isdn/avmb1/kcapi.c @@ -1,11 +1,18 @@ /* - * $Id: kcapi.c,v 1.10 1999/10/26 15:30:32 calle Exp $ + * $Id: kcapi.c,v 1.12 2000/01/28 16:45:39 calle Exp $ * * Kernel CAPI 2.0 Module * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: kcapi.c,v $ + * Revision 1.12 2000/01/28 16:45:39 calle + * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard), + * will search named driver and call the add_card function if one exist. + * + * Revision 1.11 1999/11/23 13:29:29 calle + * Bugfix: incoming capi message were never traced. + * * Revision 1.10 1999/10/26 15:30:32 calle * Generate error message if user want to add card, but driver module is * not loaded. @@ -79,7 +86,7 @@ #include <linux/b1lli.h> #endif -static char *revision = "$Revision: 1.10 $"; +static char *revision = "$Revision: 1.12 $"; /* ------------------------------------------------------------- */ @@ -154,10 +161,6 @@ static int ncards = 0; static struct sk_buff_head recv_queue; static struct capi_interface_user *capi_users = 0; static struct capi_driver *drivers; -#ifdef CONFIG_AVMB1_COMPAT -static struct capi_driver *b1isa_driver; -static struct capi_driver *t1isa_driver; -#endif static long notify_up_set = 0; static long notify_down_set = 0; @@ -703,9 +706,9 @@ static void controllercb_handle_capimsg(struct capi_ctr * card, if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) { card->nrecvdatapkt++; if (card->traceflag > 2) showctl |= 2; - if (card->traceflag) showctl |= 2; } else { card->nrecvctlpkt++; + if (card->traceflag) showctl |= 2; } showctl |= (card->traceflag & 1); if (showctl & 2) { @@ -877,8 +880,14 @@ drivercb_attach_ctr(struct capi_driver *driver, char *name, void *driverdata) *pp = card; driver->ncontroller++; sprintf(card->procfn, "capi/controllers/%d", card->cnr); - card->procent = create_proc_read_entry(card->procfn, 0, 0, - driver->ctr_read_proc, card); + card->procent = create_proc_entry(card->procfn, 0, 0); + if (card->procent) { + card->procent->read_proc = + (int (*)(char *,char **,off_t,int,int *,void *)) + driver->ctr_read_proc; + card->procent->data = card; + } + ncards++; printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n", card->cnr, card->name); @@ -947,18 +956,18 @@ struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver) driver->next = 0; *pp = driver; printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name); -#ifdef CONFIG_AVMB1_COMPAT - if (strcmp(driver->name, "b1isa") == 0 && driver->add_card) - b1isa_driver = driver; - if (strcmp(driver->name, "t1isa") == 0 && driver->add_card) - t1isa_driver = driver; -#endif sprintf(driver->procfn, "capi/drivers/%s", driver->name); - driver->procent = create_proc_read_entry(driver->procfn, 0, 0, - driver->driver_read_proc - ? driver->driver_read_proc - : driver_read_proc, - driver); + driver->procent = create_proc_entry(driver->procfn, 0, 0); + if (driver->procent) { + if (driver->driver_read_proc) { + driver->procent->read_proc = + (int (*)(char *,char **,off_t,int,int *,void *)) + driver->driver_read_proc; + } else { + driver->procent->read_proc = driver_read_proc; + } + driver->procent->data = driver; + } return &di; } @@ -968,10 +977,6 @@ void detach_capi_driver(struct capi_driver *driver) for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ; if (*pp) { *pp = (*pp)->next; -#ifdef CONFIG_AVMB1_COMPAT - if (driver == b1isa_driver) b1isa_driver = 0; - if (driver == t1isa_driver) t1isa_driver = 0; -#endif printk(KERN_NOTICE "kcapi: driver %s detached\n", driver->name); } else { printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name); @@ -1186,6 +1191,15 @@ static __u16 capi_get_profile(__u32 contr, struct capi_profile *profp) return CAPI_NOERROR; } +static struct capi_driver *find_driver(char *name) +{ + struct capi_driver *dp; + for (dp = drivers; dp; dp = dp->next) + if (strcmp(dp->name, name) == 0) + return dp; + return 0; +} + #ifdef CONFIG_AVMB1_COMPAT static int old_capi_manufacturer(unsigned int cmd, void *data) { @@ -1217,9 +1231,15 @@ static int old_capi_manufacturer(unsigned int cmd, void *data) cparams.cardnr = cdef.cardnr; switch (cdef.cardtype) { - case AVM_CARDTYPE_B1: driver = b1isa_driver; break; - case AVM_CARDTYPE_T1: driver = t1isa_driver; break; - default: driver = 0; + case AVM_CARDTYPE_B1: + driver = find_driver("b1isa"); + break; + case AVM_CARDTYPE_T1: + driver = find_driver("t1isa"); + break; + default: + driver = 0; + break; } if (!driver) { printk(KERN_ERR "kcapi: driver not loaded.\n"); @@ -1331,9 +1351,7 @@ static int old_capi_manufacturer(unsigned int cmd, void *data) return -ESRCH; gdef.cardstate = card->cardstate; - if (card->driver == b1isa_driver) - gdef.cardtype = AVM_CARDTYPE_B1; - else if (card->driver == t1isa_driver) + if (card->driver == find_driver("t1isa")) gdef.cardtype = AVM_CARDTYPE_T1; else gdef.cardtype = AVM_CARDTYPE_B1; @@ -1377,7 +1395,6 @@ static int old_capi_manufacturer(unsigned int cmd, void *data) static int capi_manufacturer(unsigned int cmd, void *data) { struct capi_ctr *card; - kcapi_flagdef fdef; int retval; switch (cmd) { @@ -1392,6 +1409,9 @@ static int capi_manufacturer(unsigned int cmd, void *data) return old_capi_manufacturer(cmd, data); #endif case KCAPI_CMD_TRACE: + { + kcapi_flagdef fdef; + if ((retval = copy_from_user((void *) &fdef, data, sizeof(kcapi_flagdef)))) return retval; @@ -1406,6 +1426,44 @@ static int capi_manufacturer(unsigned int cmd, void *data) card->cnr, card->traceflag); return 0; } + + case KCAPI_CMD_ADDCARD: + { + struct capi_driver *driver; + capicardparams cparams; + kcapi_carddef cdef; + + if ((retval = copy_from_user((void *) &cdef, data, + sizeof(cdef)))) + return retval; + + cparams.port = cdef.port; + cparams.irq = cdef.irq; + cparams.membase = cdef.membase; + cparams.cardnr = cdef.cardnr; + cparams.cardtype = 0; + cdef.driver[sizeof(cdef.driver)-1] = 0; + + if ((driver = find_driver(cdef.driver)) == 0) { + printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n", + cdef.driver); + return -ESRCH; + } + + if (!driver->add_card) { + printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver); + return -EIO; + } + + return driver->add_card(driver, &cparams); + } + + default: + printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n", + cmd); + break; + + } return -EINVAL; } diff --git a/drivers/isdn/avmb1/t1isa.c b/drivers/isdn/avmb1/t1isa.c index 22a07f2ad..e1efd3939 100644 --- a/drivers/isdn/avmb1/t1isa.c +++ b/drivers/isdn/avmb1/t1isa.c @@ -1,11 +1,19 @@ /* - * $Id: t1isa.c,v 1.8 1999/11/05 16:38:01 calle Exp $ + * $Id: t1isa.c,v 1.10 2000/02/02 18:36:04 calle Exp $ * * Module for AVM T1 HEMA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1isa.c,v $ + * Revision 1.10 2000/02/02 18:36:04 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.9 2000/01/25 14:37:39 calle + * new message after successfull detection including card revision and + * used resources. + * * Revision 1.8 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -73,7 +81,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.8 $"; +static char *revision = "$Revision: 1.10 $"; /* ------------------------------------------------------------- */ @@ -413,10 +421,13 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) avmcard *card; int retval; + MOD_INC_USE_COUNT; + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card, 0, sizeof(avmcard)); @@ -424,6 +435,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(cinfo, 0, sizeof(avmctrl_info)); @@ -440,6 +452,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->port); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EINVAL; } @@ -449,6 +462,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->port, card->port + AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } if (hema_irq_table[card->irq & 0xf] == 0) { @@ -456,6 +470,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->irq); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EINVAL; } for (ctrl = driver->controller; ctrl; ctrl = ctrl->next) { @@ -465,6 +480,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->cardnr, cardp->port); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } } @@ -473,6 +489,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->port, retval); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } t1_disable_irq(card->port); @@ -487,6 +504,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -498,10 +516,14 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } - MOD_INC_USE_COUNT; + printk(KERN_INFO + "%s: AVM T1 ISA at i/o %#x, irq %d, card %d\n", + driver->name, card->port, card->irq, card->cardnr); + return 0; } diff --git a/drivers/isdn/avmb1/t1pci.c b/drivers/isdn/avmb1/t1pci.c index d77340bff..d24894d9b 100644 --- a/drivers/isdn/avmb1/t1pci.c +++ b/drivers/isdn/avmb1/t1pci.c @@ -1,11 +1,20 @@ /* - * $Id: t1pci.c,v 1.3 1999/11/13 21:27:16 keil Exp $ + * $Id: t1pci.c,v 1.5 2000/02/02 18:36:04 calle Exp $ * * Module for AVM T1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1pci.c,v $ + * Revision 1.5 2000/02/02 18:36:04 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.4 2000/01/25 14:33:38 calle + * - Added Support AVM B1 PCI V4.0 (tested with prototype) + * - splitted up t1pci.c into b1dma.c for common function with b1pciv4 + * - support for revision register + * * Revision 1.3 1999/11/13 21:27:16 keil * remove KERNELVERSION * @@ -38,7 +47,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.3 $"; +static char *revision = "$Revision: 1.5 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG @@ -55,712 +64,20 @@ static char *revision = "$Revision: 1.3 $"; /* ------------------------------------------------------------- */ -int suppress_pollack = 0; - MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>"); -MODULE_PARM(suppress_pollack, "0-1i"); - - /* ------------------------------------------------------------- */ static struct capi_driver_interface *di; /* ------------------------------------------------------------- */ -static void t1pci_dispatch_tx(avmcard *card); - -/* ------------------------------------------------------------- */ - -/* S5933 */ - -#define AMCC_RXPTR 0x24 -#define AMCC_RXLEN 0x28 -#define AMCC_TXPTR 0x2c -#define AMCC_TXLEN 0x30 - -#define AMCC_INTCSR 0x38 -# define EN_READ_TC_INT 0x00008000L -# define EN_WRITE_TC_INT 0x00004000L -# define EN_TX_TC_INT EN_READ_TC_INT -# define EN_RX_TC_INT EN_WRITE_TC_INT -# define AVM_FLAG 0x30000000L - -# define ANY_S5933_INT 0x00800000L -# define READ_TC_INT 0x00080000L -# define WRITE_TC_INT 0x00040000L -# define TX_TC_INT READ_TC_INT -# define RX_TC_INT WRITE_TC_INT -# define MASTER_ABORT_INT 0x00100000L -# define TARGET_ABORT_INT 0x00200000L -# define BUS_MASTER_INT 0x00200000L -# define ALL_INT 0x000C0000L - -#define AMCC_MCSR 0x3c -# define A2P_HI_PRIORITY 0x00000100L -# define EN_A2P_TRANSFERS 0x00000400L -# define P2A_HI_PRIORITY 0x00001000L -# define EN_P2A_TRANSFERS 0x00004000L -# define RESET_A2P_FLAGS 0x04000000L -# define RESET_P2A_FLAGS 0x02000000L - -/* ------------------------------------------------------------- */ - -#define t1outmeml(addr, value) writel(value, addr) -#define t1inmeml(addr) readl(addr) -#define t1outmemw(addr, value) writew(value, addr) -#define t1inmemw(addr) readw(addr) -#define t1outmemb(addr, value) writeb(value, addr) -#define t1inmemb(addr) readb(addr) - -/* ------------------------------------------------------------- */ - -static inline int t1pci_tx_empty(unsigned int port) -{ - return inb(port + 0x03) & 0x1; -} - -static inline int t1pci_rx_full(unsigned int port) -{ - return inb(port + 0x02) & 0x1; -} - -static int t1pci_tolink(avmcard *card, void *buf, unsigned int len) -{ - unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ - unsigned char *s = (unsigned char *)buf; - while (len--) { - while ( !t1pci_tx_empty(card->port) - && time_before(jiffies, stop)); - if (!t1pci_tx_empty(card->port)) - return -1; - t1outp(card->port, 0x01, *s++); - } - return 0; -} - -static int t1pci_fromlink(avmcard *card, void *buf, unsigned int len) -{ - unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ - unsigned char *s = (unsigned char *)buf; - while (len--) { - while ( !t1pci_rx_full(card->port) - && time_before(jiffies, stop)); - if (!t1pci_rx_full(card->port)) - return -1; - *s++ = t1inp(card->port, 0x00); - } - return 0; -} - -static int WriteReg(avmcard *card, __u32 reg, __u8 val) -{ - __u8 cmd = 0x00; - if ( t1pci_tolink(card, &cmd, 1) == 0 - && t1pci_tolink(card, ®, 4) == 0) { - __u32 tmp = val; - return t1pci_tolink(card, &tmp, 4); - } - return -1; -} - -static __u8 ReadReg(avmcard *card, __u32 reg) -{ - __u8 cmd = 0x01; - if ( t1pci_tolink(card, &cmd, 1) == 0 - && t1pci_tolink(card, ®, 4) == 0) { - __u32 tmp; - if (t1pci_fromlink(card, &tmp, 4) == 0) - return (__u8)tmp; - } - return 0xff; -} - -/* ------------------------------------------------------------- */ - -static inline void _put_byte(void **pp, __u8 val) -{ - __u8 *s = *pp; - *s++ = val; - *pp = s; -} - -static inline void _put_word(void **pp, __u32 val) -{ - __u8 *s = *pp; - *s++ = val & 0xff; - *s++ = (val >> 8) & 0xff; - *s++ = (val >> 16) & 0xff; - *s++ = (val >> 24) & 0xff; - *pp = s; -} - -static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len) -{ - unsigned i = len; - _put_word(pp, i); - while (i-- > 0) - _put_byte(pp, *dp++); -} - -static inline __u8 _get_byte(void **pp) -{ - __u8 *s = *pp; - __u8 val; - val = *s++; - *pp = s; - return val; -} - -static inline __u32 _get_word(void **pp) -{ - __u8 *s = *pp; - __u32 val; - val = *s++; - val |= (*s++ << 8); - val |= (*s++ << 16); - val |= (*s++ << 24); - *pp = s; - return val; -} - -static inline __u32 _get_slice(void **pp, unsigned char *dp) -{ - unsigned int len, i; - - len = i = _get_word(pp); - while (i-- > 0) *dp++ = _get_byte(pp); - return len; -} - -/* ------------------------------------------------------------- */ - -static void t1pci_reset(avmcard *card) -{ - unsigned long flags; - - save_flags(flags); - cli(); - card->csr = 0x0; - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); - t1outmeml(card->mbase+AMCC_MCSR, 0); - t1outmeml(card->mbase+AMCC_RXLEN, 0); - t1outmeml(card->mbase+AMCC_TXLEN, 0); - - t1outp(card->port, T1_RESETLINK, 0x00); - t1outp(card->port, 0x07, 0x00); - - restore_flags(flags); - - t1outmeml(card->mbase+AMCC_MCSR, 0); - udelay(10 * 1000); - t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */ - udelay(10 * 1000); - t1outmeml(card->mbase+AMCC_MCSR, 0); - udelay(42 * 1000); - -} - -/* ------------------------------------------------------------- */ - -static int t1pci_detect(avmcard *card) -{ - t1outmeml(card->mbase+AMCC_MCSR, 0); - udelay(10 * 1000); - t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */ - udelay(10 * 1000); - t1outmeml(card->mbase+AMCC_MCSR, 0); - udelay(42 * 1000); - - t1outmeml(card->mbase+AMCC_RXLEN, 0); - t1outmeml(card->mbase+AMCC_TXLEN, 0); - card->csr = 0x0; - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); - - if (t1inmeml(card->mbase+AMCC_MCSR) != 0x000000E6) - return 1; - - t1outmeml(card->mbase+AMCC_RXPTR, 0xffffffff); - t1outmeml(card->mbase+AMCC_TXPTR, 0xffffffff); - if ( t1inmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc - || t1inmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc) - return 2; - - t1outmeml(card->mbase+AMCC_RXPTR, 0x0); - t1outmeml(card->mbase+AMCC_TXPTR, 0x0); - if ( t1inmeml(card->mbase+AMCC_RXPTR) != 0x0 - || t1inmeml(card->mbase+AMCC_TXPTR) != 0x0) - return 3; - - t1outp(card->port, T1_RESETLINK, 0x00); - t1outp(card->port, 0x07, 0x00); - - t1outp(card->port, 0x02, 0x02); - t1outp(card->port, 0x03, 0x02); - - if ( (t1inp(card->port, 0x02) & 0xFE) != 0x02 - || t1inp(card->port, 0x3) != 0x03) - return 4; - - t1outp(card->port, 0x02, 0x00); - t1outp(card->port, 0x03, 0x00); - - if ( (t1inp(card->port, 0x02) & 0xFE) != 0x00 - || t1inp(card->port, 0x3) != 0x01) - return 5; - - /* Transputer test */ - - if ( WriteReg(card, 0x80001000, 0x11) != 0 - || WriteReg(card, 0x80101000, 0x22) != 0 - || WriteReg(card, 0x80201000, 0x33) != 0 - || WriteReg(card, 0x80301000, 0x44) != 0) - return 6; - - if ( ReadReg(card, 0x80001000) != 0x11 - || ReadReg(card, 0x80101000) != 0x22 - || ReadReg(card, 0x80201000) != 0x33 - || ReadReg(card, 0x80301000) != 0x44) - return 7; - - if ( WriteReg(card, 0x80001000, 0x55) != 0 - || WriteReg(card, 0x80101000, 0x66) != 0 - || WriteReg(card, 0x80201000, 0x77) != 0 - || WriteReg(card, 0x80301000, 0x88) != 0) - return 8; - - if ( ReadReg(card, 0x80001000) != 0x55 - || ReadReg(card, 0x80101000) != 0x66 - || ReadReg(card, 0x80201000) != 0x77 - || ReadReg(card, 0x80301000) != 0x88) - return 9; - - return 0; -} - -/* ------------------------------------------------------------- */ - -static void t1pci_dispatch_tx(avmcard *card) -{ - avmcard_dmainfo *dma = card->dma; - unsigned long flags; - struct sk_buff *skb; - __u8 cmd, subcmd; - __u16 len; - __u32 txlen; - int inint; - void *p; - - save_flags(flags); - cli(); - - inint = card->interrupt; - - if (card->csr & EN_TX_TC_INT) { /* tx busy */ - restore_flags(flags); - return; - } - - skb = skb_dequeue(&dma->send_queue); - if (!skb) { -#ifdef CONFIG_T1PCI_DEBUG - printk(KERN_DEBUG "tx(%d): underrun\n", inint); -#endif - restore_flags(flags); - return; - } - - len = CAPIMSG_LEN(skb->data); - - if (len) { - cmd = CAPIMSG_COMMAND(skb->data); - subcmd = CAPIMSG_SUBCOMMAND(skb->data); - - p = dma->sendbuf; - - if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { - __u16 dlen = CAPIMSG_DATALEN(skb->data); - _put_byte(&p, SEND_DATA_B3_REQ); - _put_slice(&p, skb->data, len); - _put_slice(&p, skb->data + len, dlen); - } else { - _put_byte(&p, SEND_MESSAGE); - _put_slice(&p, skb->data, len); - } - txlen = (__u8 *)p - (__u8 *)dma->sendbuf; -#ifdef CONFIG_T1PCI_DEBUG - printk(KERN_DEBUG "tx(%d): put msg len=%d\n", - inint, txlen); -#endif - } else { - txlen = skb->len-2; -#ifdef CONFIG_T1PCI_POLLDEBUG - if (skb->data[2] == SEND_POLLACK) - printk(KERN_INFO "%s: ack to t1\n", card->name); -#endif -#ifdef CONFIG_T1PCI_DEBUG - printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n", - inint, skb->data[2], txlen); -#endif - memcpy(dma->sendbuf, skb->data+2, skb->len-2); - } - txlen = (txlen + 3) & ~3; - - t1outmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf)); - t1outmeml(card->mbase+AMCC_TXLEN, txlen); - - card->csr |= EN_TX_TC_INT; - - if (!inint) - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); - - restore_flags(flags); - dev_kfree_skb(skb); -} - -/* ------------------------------------------------------------- */ - -static void queue_pollack(avmcard *card) -{ - struct sk_buff *skb; - void *p; - - skb = alloc_skb(3, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost poll ack\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_POLLACK); - skb_put(skb, (__u8 *)p - (__u8 *)skb->data); - - skb_queue_tail(&card->dma->send_queue, skb); - t1pci_dispatch_tx(card); -} - -/* ------------------------------------------------------------- */ - -static void t1pci_handle_rx(avmcard *card) -{ - avmctrl_info *cinfo = &card->ctrlinfo[0]; - avmcard_dmainfo *dma = card->dma; - struct capi_ctr *ctrl = cinfo->capi_ctrl; - struct sk_buff *skb; - void *p = dma->recvbuf+4; - __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; - __u8 b1cmd = _get_byte(&p); - -#ifdef CONFIG_T1PCI_DEBUG - printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen); -#endif - - switch (b1cmd) { - case RECEIVE_DATA_B3_IND: - - ApplId = (unsigned) _get_word(&p); - MsgLen = _get_slice(&p, card->msgbuf); - DataB3Len = _get_slice(&p, card->databuf); - - if (MsgLen < 30) { /* not CAPI 64Bit */ - memset(card->msgbuf+MsgLen, 0, 30-MsgLen); - MsgLen = 30; - CAPIMSG_SETLEN(card->msgbuf, 30); - } - if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) { - printk(KERN_ERR "%s: incoming packet dropped\n", - card->name); - } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); - memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); - ctrl->handle_capimsg(ctrl, ApplId, skb); - } - break; - - case RECEIVE_MESSAGE: - - ApplId = (unsigned) _get_word(&p); - MsgLen = _get_slice(&p, card->msgbuf); - if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { - printk(KERN_ERR "%s: incoming packet dropped\n", - card->name); - } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); - ctrl->handle_capimsg(ctrl, ApplId, skb); - } - break; - - case RECEIVE_NEW_NCCI: - - ApplId = _get_word(&p); - NCCI = _get_word(&p); - WindowSize = _get_word(&p); - - ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize); - - break; - - case RECEIVE_FREE_NCCI: - - ApplId = _get_word(&p); - NCCI = _get_word(&p); - - if (NCCI != 0xffffffff) - ctrl->free_ncci(ctrl, ApplId, NCCI); - else ctrl->appl_released(ctrl, ApplId); - break; - - case RECEIVE_START: -#ifdef CONFIG_T1PCI_POLLDEBUG - printk(KERN_INFO "%s: poll from t1\n", card->name); -#endif - if (!suppress_pollack) - queue_pollack(card); - ctrl->resume_output(ctrl); - break; - - case RECEIVE_STOP: - ctrl->suspend_output(ctrl); - break; - - case RECEIVE_INIT: - - cinfo->versionlen = _get_slice(&p, cinfo->versionbuf); - b1_parse_version(cinfo); - printk(KERN_INFO "%s: %s-card (%s) now active\n", - card->name, - cinfo->version[VER_CARDTYPE], - cinfo->version[VER_DRIVER]); - ctrl->ready(ctrl); - break; - - case RECEIVE_TASK_READY: - ApplId = (unsigned) _get_word(&p); - MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; - printk(KERN_INFO "%s: task %d \"%s\" ready.\n", - card->name, ApplId, card->msgbuf); - break; - - case RECEIVE_DEBUGMSG: - MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; - printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); - break; - - default: - printk(KERN_ERR "%s: t1pci_interrupt: 0x%x ???\n", - card->name, b1cmd); - return; - } -} - -/* ------------------------------------------------------------- */ - -static void t1pci_handle_interrupt(avmcard *card) -{ - __u32 status = t1inmeml(card->mbase+AMCC_INTCSR); - __u32 newcsr; - - if ((status & ANY_S5933_INT) == 0) - return; - - newcsr = card->csr | (status & ALL_INT); - if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT; - if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT; - t1outmeml(card->mbase+AMCC_INTCSR, newcsr); - - if ((status & RX_TC_INT) != 0) { - __u8 *recvbuf = card->dma->recvbuf; - __u32 rxlen; - if (card->dma->recvlen == 0) { - card->dma->recvlen = *((__u32 *)recvbuf); - rxlen = (card->dma->recvlen + 3) & ~3; - t1outmeml(card->mbase+AMCC_RXPTR, - virt_to_phys(recvbuf+4)); - t1outmeml(card->mbase+AMCC_RXLEN, rxlen); - } else { - t1pci_handle_rx(card); - card->dma->recvlen = 0; - t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf)); - t1outmeml(card->mbase+AMCC_RXLEN, 4); - } - } - - if ((status & TX_TC_INT) != 0) { - card->csr &= ~EN_TX_TC_INT; - t1pci_dispatch_tx(card); - } else if (card->csr & EN_TX_TC_INT) { - if (t1inmeml(card->mbase+AMCC_TXLEN) == 0) { - card->csr &= ~EN_TX_TC_INT; - t1pci_dispatch_tx(card); - } - } - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); -} - -static void t1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs) -{ - avmcard *card; - - card = (avmcard *) devptr; - - if (!card) { - printk(KERN_WARNING "t1pci: interrupt: wrong device\n"); - return; - } - if (card->interrupt) { - printk(KERN_ERR "%s: reentering interrupt hander\n", card->name); - return; - } - - card->interrupt = 1; - - t1pci_handle_interrupt(card); - - card->interrupt = 0; -} - -/* ------------------------------------------------------------- */ - -static int t1pci_loaded(avmcard *card) -{ - unsigned long stop; - unsigned char ans; - unsigned long tout = 2; - unsigned int base = card->port; - - for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { - if (b1_tx_empty(base)) - break; - } - if (!b1_tx_empty(base)) { - printk(KERN_ERR "%s: t1pci_loaded: tx err, corrupted t4 file ?\n", - card->name); - return 0; - } - b1_put_byte(base, SEND_POLLACK); - for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { - if (b1_rx_full(base)) { - if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) { - return 1; - } - printk(KERN_ERR "%s: t1pci_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans); - return 0; - } - } - printk(KERN_ERR "%s: t1pci_loaded: firmware not running\n", card->name); - return 0; -} - -/* ------------------------------------------------------------- */ - -static void t1pci_send_init(avmcard *card) -{ - struct sk_buff *skb; - void *p; - - skb = alloc_skb(15, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost register appl.\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_INIT); - _put_word(&p, AVM_NAPPS); - _put_word(&p, AVM_NCCI_PER_CHANNEL*30); - _put_word(&p, card->cardnr - 1); - skb_put(skb, (__u8 *)p - (__u8 *)skb->data); - - skb_queue_tail(&card->dma->send_queue, skb); - t1pci_dispatch_tx(card); -} - -static int t1pci_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned long flags; - int retval; - - t1pci_reset(card); - - if ((retval = b1_load_t4file(card, &data->firmware))) { - t1pci_reset(card); - printk(KERN_ERR "%s: failed to load t4file!!\n", - card->name); - return retval; - } - - if (data->configuration.len > 0 && data->configuration.data) { - if ((retval = b1_load_config(card, &data->configuration))) { - t1pci_reset(card); - printk(KERN_ERR "%s: failed to load config!!\n", - card->name); - return retval; - } - } - - if (!t1pci_loaded(card)) { - t1pci_reset(card); - printk(KERN_ERR "%s: failed to load t4file.\n", card->name); - return -EIO; - } - - save_flags(flags); - cli(); - - card->csr = AVM_FLAG; - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); - t1outmeml(card->mbase+AMCC_MCSR, - EN_A2P_TRANSFERS|EN_P2A_TRANSFERS - |A2P_HI_PRIORITY|P2A_HI_PRIORITY - |RESET_A2P_FLAGS|RESET_P2A_FLAGS); - t1outp(card->port, 0x07, 0x30); - t1outp(card->port, 0x10, 0xF0); - - card->dma->recvlen = 0; - t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf)); - t1outmeml(card->mbase+AMCC_RXLEN, 4); - card->csr |= EN_RX_TC_INT; - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); - restore_flags(flags); - - t1pci_send_init(card); - - return 0; -} - -void t1pci_reset_ctr(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - - t1pci_reset(card); - - memset(cinfo->version, 0, sizeof(cinfo->version)); - ctrl->reseted(ctrl); -} - static void t1pci_remove_ctr(struct capi_ctr *ctrl) { avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; - t1pci_reset(card); + b1dma_reset(card); di->detach_ctr(ctrl); free_irq(card->irq, card); @@ -776,210 +93,20 @@ static void t1pci_remove_ctr(struct capi_ctr *ctrl) /* ------------------------------------------------------------- */ - -void t1pci_register_appl(struct capi_ctr *ctrl, - __u16 appl, - capi_register_params *rp) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - struct sk_buff *skb; - int want = rp->level3cnt; - int nconn; - void *p; - - if (want > 0) nconn = want; - else nconn = ctrl->profile.nbchannel * -want; - if (nconn == 0) nconn = ctrl->profile.nbchannel; - - skb = alloc_skb(23, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost register appl.\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_REGISTER); - _put_word(&p, appl); - _put_word(&p, 1024 * (nconn+1)); - _put_word(&p, nconn); - _put_word(&p, rp->datablkcnt); - _put_word(&p, rp->datablklen); - skb_put(skb, (__u8 *)p - (__u8 *)skb->data); - - skb_queue_tail(&card->dma->send_queue, skb); - t1pci_dispatch_tx(card); - - ctrl->appl_registered(ctrl, appl); -} - -/* ------------------------------------------------------------- */ - -void t1pci_release_appl(struct capi_ctr *ctrl, __u16 appl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - struct sk_buff *skb; - void *p; - - skb = alloc_skb(7, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost release appl.\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_RELEASE); - _put_word(&p, appl); - - skb_put(skb, (__u8 *)p - (__u8 *)skb->data); - skb_queue_tail(&card->dma->send_queue, skb); - t1pci_dispatch_tx(card); -} - -/* ------------------------------------------------------------- */ - - -static void t1pci_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - skb_queue_tail(&card->dma->send_queue, skb); - t1pci_dispatch_tx(card); -} - -/* ------------------------------------------------------------- */ - -static char *t1pci_procinfo(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - - if (!cinfo) - return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx", - cinfo->cardname[0] ? cinfo->cardname : "-", - cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", - cinfo->card ? cinfo->card->port : 0x0, - cinfo->card ? cinfo->card->irq : 0, - cinfo->card ? cinfo->card->membase : 0 - ); - return cinfo->infobuf; -} - -static int t1pci_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned long flags; - __u8 flag; - int len = 0; - char *s; - __u32 txaddr, txlen, rxaddr, rxlen, csr; - - len += sprintf(page+len, "%-16s %s\n", "name", card->name); - len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); - len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); - len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase); - switch (card->cardtype) { - case avm_b1isa: s = "B1 ISA"; break; - case avm_b1pci: s = "B1 PCI"; break; - case avm_b1pcmcia: s = "B1 PCMCIA"; break; - case avm_m1: s = "M1"; break; - case avm_m2: s = "M2"; break; - case avm_t1isa: s = "T1 ISA (HEMA)"; break; - case avm_t1pci: s = "T1 PCI"; break; - case avm_c4: s = "C4"; break; - default: s = "???"; break; - } - len += sprintf(page+len, "%-16s %s\n", "type", s); - if ((s = cinfo->version[VER_DRIVER]) != 0) - len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != 0) - len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != 0) - len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); - - if (card->cardtype != avm_m1) { - flag = ((__u8 *)(ctrl->profile.manu))[3]; - if (flag) - len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n", - "protocol", - (flag & 0x01) ? " DSS1" : "", - (flag & 0x02) ? " CT1" : "", - (flag & 0x04) ? " VN3" : "", - (flag & 0x08) ? " NI1" : "", - (flag & 0x10) ? " AUSTEL" : "", - (flag & 0x20) ? " ESS" : "", - (flag & 0x40) ? " 1TR6" : "" - ); - } - if (card->cardtype != avm_m1) { - flag = ((__u8 *)(ctrl->profile.manu))[5]; - if (flag) - len += sprintf(page+len, "%-16s%s%s%s%s\n", - "linetype", - (flag & 0x01) ? " point to point" : "", - (flag & 0x02) ? " point to multipoint" : "", - (flag & 0x08) ? " leased line without D-channel" : "", - (flag & 0x04) ? " leased line with D-channel" : "" - ); - } - len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); - - save_flags(flags); - cli(); - - txaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x2c)); - txaddr -= (__u32)card->dma->sendbuf; - txlen = t1inmeml(card->mbase+0x30); - - rxaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x24)); - rxaddr -= (__u32)card->dma->recvbuf; - rxlen = t1inmeml(card->mbase+0x28); - - csr = t1inmeml(card->mbase+AMCC_INTCSR); - - restore_flags(flags); - - len += sprintf(page+len, "%-16s 0x%lx\n", - "csr (cached)", (unsigned long)card->csr); - len += sprintf(page+len, "%-16s 0x%lx\n", - "csr", (unsigned long)csr); - len += sprintf(page+len, "%-16s %lu\n", - "txoff", (unsigned long)txaddr); - len += sprintf(page+len, "%-16s %lu\n", - "txlen", (unsigned long)txlen); - len += sprintf(page+len, "%-16s %lu\n", - "rxoff", (unsigned long)rxaddr); - len += sprintf(page+len, "%-16s %lu\n", - "rxlen", (unsigned long)rxlen); - - if (off+count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len-off) ? count : len-off); -} - -/* ------------------------------------------------------------- */ - static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) { - unsigned long page_offset, base; + unsigned long base, page_offset; avmcard *card; avmctrl_info *cinfo; int retval; + MOD_INC_USE_COUNT; + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card, 0, sizeof(avmcard)); @@ -987,6 +114,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) if (!card->dma) { printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card->dma, 0, sizeof(avmcard_dmainfo)); @@ -995,6 +123,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(cinfo, 0, sizeof(avmctrl_info)); @@ -1013,14 +142,26 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } - base = card->membase & PAGE_MASK; + base = card->membase & PAGE_MASK; page_offset = card->membase - base; card->mbase = ioremap_nocache(base, page_offset + 64); + if (card->mbase) { + card->mbase += page_offset; + } else { + printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", + driver->name, card->membase); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + MOD_DEC_USE_COUNT; + return -EIO; + } - t1pci_reset(card); + b1dma_reset(card); if ((retval = t1pci_detect(card)) != 0) { printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", @@ -1029,13 +170,14 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } - t1pci_reset(card); + b1dma_reset(card); request_region(p->port, AVMB1_PORTLEN, card->name); - retval = request_irq(card->irq, t1pci_interrupt, SA_SHIRQ, card->name, card); + retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card); if (retval) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", driver->name, card->irq); @@ -1044,6 +186,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -1056,31 +199,52 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } card->cardnr = cinfo->capi_ctrl->cnr; skb_queue_head_init(&card->dma->send_queue); - MOD_INC_USE_COUNT; + printk(KERN_INFO + "%s: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n", + driver->name, card->port, card->irq, card->membase); return 0; } /* ------------------------------------------------------------- */ +static char *t1pci_procinfo(struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + + if (!cinfo) + return ""; + sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx", + cinfo->cardname[0] ? cinfo->cardname : "-", + cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", + cinfo->card ? cinfo->card->port : 0x0, + cinfo->card ? cinfo->card->irq : 0, + cinfo->card ? cinfo->card->membase : 0 + ); + return cinfo->infobuf; +} + +/* ------------------------------------------------------------- */ + static struct capi_driver t1pci_driver = { "t1pci", "0.0", - t1pci_load_firmware, - t1pci_reset_ctr, + b1dma_load_firmware, + b1dma_reset_ctr, t1pci_remove_ctr, - t1pci_register_appl, - t1pci_release_appl, - t1pci_send_message, + b1dma_register_appl, + b1dma_release_appl, + b1dma_send_message, t1pci_procinfo, - t1pci_read_proc, + b1dmactl_read_proc, 0, /* use standard driver_read_proc */ 0, /* no add_card function */ |