From 7e6e58c4c7f91947ec1f9a10a284f8d9c2fdf1f2 Mon Sep 17 00:00:00 2001 From: hm Date: Fri, 25 May 2001 08:43:30 +0000 Subject: Submitted by: Juha-Matti Liukkonen (Cubical Solutions Ltd) (jml@cubical.fi) Add a CAPI (hardware independent) driver i4bcapi(4) and hardware driver iavc (4) to support active CAPI-based BRI and PRI cards (currently AVM B1 and T1 cards) to isdn4bsd. --- sys/i4b/capi/iavc/iavc.h | 586 +++++++++++++++++++++++++++++ sys/i4b/capi/iavc/iavc_card.c | 292 +++++++++++++++ sys/i4b/capi/iavc/iavc_isa.c | 297 +++++++++++++++ sys/i4b/capi/iavc/iavc_lli.c | 834 ++++++++++++++++++++++++++++++++++++++++++ sys/i4b/capi/iavc/iavc_pci.c | 283 ++++++++++++++ 5 files changed, 2292 insertions(+) create mode 100644 sys/i4b/capi/iavc/iavc.h create mode 100644 sys/i4b/capi/iavc/iavc_card.c create mode 100644 sys/i4b/capi/iavc/iavc_isa.c create mode 100644 sys/i4b/capi/iavc/iavc_lli.c create mode 100644 sys/i4b/capi/iavc/iavc_pci.c (limited to 'sys/i4b/capi/iavc') diff --git a/sys/i4b/capi/iavc/iavc.h b/sys/i4b/capi/iavc/iavc.h new file mode 100644 index 0000000..a38ad70 --- /dev/null +++ b/sys/i4b/capi/iavc/iavc.h @@ -0,0 +1,586 @@ +/* + * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * capi/iavc/iavc.h The AVM ISDN controllers' common declarations. + * + * $FreeBSD$ + */ + +#ifndef _CAPI_IAVC_H_ +#define _CAPI_IAVC_H_ + +/* max 4 units supported per machine */ + +#define IAVC_MAXUNIT 4 + +/* +// iavc_softc_t +// The software context of one AVM T1 controller. +*/ + +#define IAVC_IO_BASES 1 + +typedef struct i4b_info { + struct resource * io_base[IAVC_IO_BASES]; + int io_rid [IAVC_IO_BASES]; + struct resource * irq; + int irq_rid; + struct resource * mem; + int mem_rid; +} i4b_info_t; + +typedef struct iavc_softc { + capi_softc_t sc_capi; + int sc_unit; + int sc_cardtyp; + + u_int32_t sc_membase; + bus_space_handle_t sc_mem_bh; + bus_space_tag_t sc_mem_bt; + u_int32_t sc_iobase; + bus_space_handle_t sc_io_bh; + bus_space_tag_t sc_io_bt; + + int sc_state; +#define IAVC_DOWN 0 +#define IAVC_POLL 1 +#define IAVC_INIT 2 +#define IAVC_UP 3 + int sc_blocked; + int sc_dma; + int sc_t1; + int sc_intr; + + u_int32_t sc_csr; + + char sc_sendbuf[128+2048]; + char sc_recvbuf[128+2048]; + int sc_recvlen; + + struct ifqueue sc_txq; + + i4b_info_t sc_resources; +} iavc_softc_t; + +extern iavc_softc_t iavc_sc[]; + +#define iavc_find_sc(unit) (&iavc_sc[(unit)]) + +/* +// {b1,b1dma,t1}_{detect,reset} +// Routines to detect and manage the specific type of card. +*/ + +extern int b1_detect(iavc_softc_t *sc); +extern void b1_disable_irq(iavc_softc_t *sc); +extern void b1_reset(iavc_softc_t *sc); + +extern int b1dma_detect(iavc_softc_t *sc); +extern void b1dma_reset(iavc_softc_t *sc); + +extern int t1_detect(iavc_softc_t *sc); +extern void t1_disable_irq(iavc_softc_t *sc); +extern void t1_reset(iavc_softc_t *sc); + +/* +// AMCC_{READ,WRITE} +// Routines to access the memory mapped registers of the +// S5933 DMA controller. +*/ + +static __inline u_int32_t AMCC_READ(iavc_softc_t *sc, int off) +{ + return bus_space_read_4(sc->sc_mem_bt, sc->sc_mem_bh, off); +} + +static __inline void AMCC_WRITE(iavc_softc_t *sc, int off, u_int32_t value) +{ + bus_space_write_4(sc->sc_mem_bt, sc->sc_mem_bh, off, value); +} + +/* +// amcc_{put,get}_{byte,word} +// Routines to access the DMA buffers byte- or wordwise. +*/ + +static __inline u_int8_t* amcc_put_byte(u_int8_t *buf, u_int8_t value) +{ + *buf++ = value; + return buf; +} + +static __inline u_int8_t* amcc_get_byte(u_int8_t *buf, u_int8_t *value) +{ + *value = *buf++; + return buf; +} + +static __inline u_int8_t* amcc_put_word(u_int8_t *buf, u_int32_t value) +{ + *buf++ = (value & 0xff); + *buf++ = (value >> 8) & 0xff; + *buf++ = (value >> 16) & 0xff; + *buf++ = (value >> 24) & 0xff; + return buf; +} + +static __inline u_int8_t* amcc_get_word(u_int8_t *buf, u_int32_t *value) +{ + *value = *buf++; + *value |= (*buf++ << 8); + *value |= (*buf++ << 16); + *value |= (*buf++ << 24); + return buf; +} + +/* +// Controller LLI message numbers. +*/ + +#define SEND_POLL 0x72 +#define SEND_INIT 0x11 +#define SEND_REGISTER 0x12 +#define SEND_DATA_B3_REQ 0x13 +#define SEND_RELEASE 0x14 +#define SEND_MESSAGE 0x15 +#define SEND_CONFIG 0x71 +#define SEND_POLLACK 0x73 + +#define RECEIVE_POLL 0x32 +#define RECEIVE_INIT 0x27 +#define RECEIVE_MESSAGE 0x21 +#define RECEIVE_DATA_B3_IND 0x22 +#define RECEIVE_START 0x23 +#define RECEIVE_STOP 0x24 +#define RECEIVE_NEW_NCCI 0x25 +#define RECEIVE_FREE_NCCI 0x26 +#define RECEIVE_RELEASE 0x26 +#define RECEIVE_TASK_READY 0x31 +#define RECEIVE_DEBUGMSG 0x71 +#define RECEIVE_POLLDWORD 0x75 + +/* Operation constants */ + +#define WRITE_REGISTER 0x00 +#define READ_REGISTER 0x01 + +/* Port offsets in I/O space */ + +#define B1_READ 0x00 +#define B1_WRITE 0x01 +#define B1_INSTAT 0x02 +#define B1_OUTSTAT 0x03 +#define B1_ANALYSE 0x04 +#define B1_REVISION 0x05 +#define B1_RESET 0x10 + +#define T1_FASTLINK 0x00 +#define T1_SLOWLINK 0x08 + +#define T1_READ B1_READ +#define T1_WRITE B1_WRITE +#define T1_INSTAT B1_INSTAT +#define T1_OUTSTAT B1_OUTSTAT +#define T1_IRQENABLE 0x05 +#define T1_FIFOSTAT 0x06 +#define T1_RESETLINK 0x10 +#define T1_ANALYSE 0x11 +#define T1_IRQMASTER 0x12 +#define T1_IDENT 0x17 +#define T1_RESETBOARD 0x1f + +#define T1F_IREADY 0x01 +#define T1F_IHALF 0x02 +#define T1F_IFULL 0x04 +#define T1F_IEMPTY 0x08 +#define T1F_IFLAGS 0xf0 + +#define T1F_OREADY 0x10 +#define T1F_OHALF 0x20 +#define T1F_OEMPTY 0x40 +#define T1F_OFULL 0x80 +#define T1F_OFLAGS 0xf0 + +#define FIFO_OUTBSIZE 256 +#define FIFO_INPBSIZE 512 + +#define HEMA_VERSION_ID 0 +#define HEMA_PAL_ID 0 + +/* +// S5933 DMA controller register offsets in memory, and bitmasks. +*/ + +#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 0x00008000 +#define EN_WRITE_TC_INT 0x00004000 +#define EN_TX_TC_INT EN_READ_TC_INT +#define EN_RX_TC_INT EN_WRITE_TC_INT +#define AVM_FLAG 0x30000000 + +#define ANY_S5933_INT 0x00800000 +#define READ_TC_INT 0x00080000 +#define WRITE_TC_INT 0x00040000 +#define TX_TC_INT READ_TC_INT +#define RX_TC_INT WRITE_TC_INT +#define MASTER_ABORT_INT 0x00100000 +#define TARGET_ABORT_INT 0x00200000 +#define BUS_MASTER_INT 0x00200000 +#define ALL_INT 0x000c0000 + +#define AMCC_MCSR 0x3c +#define A2P_HI_PRIORITY 0x00000100 +#define EN_A2P_TRANSFERS 0x00000400 +#define P2A_HI_PRIORITY 0x00001000 +#define EN_P2A_TRANSFERS 0x00004000 +#define RESET_A2P_FLAGS 0x04000000 +#define RESET_P2A_FLAGS 0x02000000 + +/* +// (B1IO_WAIT_MAX * B1IO_WAIT_DLY) is the max wait in us for the card +// to become ready after an I/O operation. The default is 1 ms. +*/ + +#define B1IO_WAIT_MAX 1000 +#define B1IO_WAIT_DLY 1 + +/* +// b1io_outp +// Diagnostic output routine, returns the written value via +// the device's analysis register. +// +// b1io_rx_full +// Returns nonzero if data is readable from the card via the +// I/O ports. +// +// b1io_tx_empty +// Returns nonzero if data can be written to the card via the +// I/O ports. +*/ + +static __inline u_int8_t b1io_outp(iavc_softc_t *sc, int off, u_int8_t val) +{ + bus_space_write_1(sc->sc_io_bt, sc->sc_io_bh, off, val); + DELAY(1); + return bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, B1_ANALYSE); +} + +static __inline int b1io_rx_full(iavc_softc_t *sc) +{ + u_int8_t val = bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, B1_INSTAT); + return (val & 0x01); +} + +static __inline int b1io_tx_empty(iavc_softc_t *sc) +{ + u_int8_t val = bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, B1_OUTSTAT); + return (val & 0x01); +} + +/* +// b1io_{get,put}_{byte,word} +// Routines to read and write the device I/O registers byte- or +// wordwise. +// +// b1io_{get,put}_slice +// Routines to read and write sequential bytes to the device +// I/O registers. +*/ + +static __inline u_int8_t b1io_get_byte(iavc_softc_t *sc) +{ + int spin = 0; + while (!b1io_rx_full(sc) && spin < B1IO_WAIT_MAX) { + spin++; DELAY(B1IO_WAIT_DLY); + } + if (b1io_rx_full(sc)) + return bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, B1_READ); + printf("iavc%d: rx not completed\n", sc->sc_unit); + return 0xff; +} + +static __inline int b1io_put_byte(iavc_softc_t *sc, u_int8_t val) +{ + int spin = 0; + while (!b1io_tx_empty(sc) && spin < B1IO_WAIT_MAX) { + spin++; DELAY(B1IO_WAIT_DLY); + } + if (b1io_tx_empty(sc)) { + bus_space_write_1(sc->sc_io_bt, sc->sc_io_bh, B1_WRITE, val); + return 0; + } + printf("iavc%d: tx not emptied\n", sc->sc_unit); + return -1; +} + +static __inline int b1io_save_put_byte(iavc_softc_t *sc, u_int8_t val) +{ + int spin = 0; + while (!b1io_tx_empty(sc) && spin < B1IO_WAIT_MAX) { + spin++; DELAY(B1IO_WAIT_DLY); + } + if (b1io_tx_empty(sc)) { + b1io_outp(sc, B1_WRITE, val); + return 0; + } + printf("iavc%d: tx not emptied\n", sc->sc_unit); + return -1; +} + +static __inline u_int32_t b1io_get_word(iavc_softc_t *sc) +{ + u_int32_t val = 0; + val |= b1io_get_byte(sc); + val |= (b1io_get_byte(sc) << 8); + val |= (b1io_get_byte(sc) << 16); + val |= (b1io_get_byte(sc) << 24); + return val; +} + +static __inline void b1io_put_word(iavc_softc_t *sc, u_int32_t val) +{ + b1io_put_byte(sc, (val & 0xff)); + b1io_put_byte(sc, (val >> 8) & 0xff); + b1io_put_byte(sc, (val >> 16) & 0xff); + b1io_put_byte(sc, (val >> 24) & 0xff); +} + +static __inline int b1io_get_slice(iavc_softc_t *sc, u_int8_t *dp) +{ + int len, i; + len = i = b1io_get_word(sc); + while (i--) *dp++ = b1io_get_byte(sc); + return len; +} + +static __inline void b1io_put_slice(iavc_softc_t *sc, u_int8_t *dp, int len) +{ + b1io_put_word(sc, len); + while (len--) b1io_put_byte(sc, *dp++); +} + +/* +// b1io_{read,write}_reg +// Routines to read and write the device registers via the I/O +// ports. +*/ + +static __inline u_int32_t b1io_read_reg(iavc_softc_t *sc, int reg) +{ + b1io_put_byte(sc, READ_REGISTER); + b1io_put_word(sc, reg); + return b1io_get_word(sc); +} + +static __inline u_int32_t b1io_write_reg(iavc_softc_t *sc, int reg, u_int32_t val) +{ + b1io_put_byte(sc, WRITE_REGISTER); + b1io_put_word(sc, reg); + b1io_put_word(sc, val); + return b1io_get_word(sc); +} + +/* +// t1io_outp +// I/O port write operation for the T1, which does not seem +// to have the analysis port. +*/ + +static __inline void t1io_outp(iavc_softc_t *sc, int off, u_int8_t val) +{ + bus_space_write_1(sc->sc_io_bt, sc->sc_io_bh, off, val); +} + +static __inline u_int8_t t1io_inp(iavc_softc_t *sc, int off) +{ + return bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, off); +} + +static __inline int t1io_isfastlink(iavc_softc_t *sc) +{ + return ((bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, T1_IDENT) & ~0x82) == 1); +} + +static __inline u_int8_t t1io_fifostatus(iavc_softc_t *sc) +{ + return bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, T1_FIFOSTAT); +} + +static __inline int t1io_get_slice(iavc_softc_t *sc, u_int8_t *dp) +{ + int len, i; + len = i = b1io_get_word(sc); + if (t1io_isfastlink(sc)) { + int status; + while (i) { + status = t1io_fifostatus(sc) & (T1F_IREADY|T1F_IHALF); + if (i >= FIFO_INPBSIZE) status |= T1F_IFULL; + + switch (status) { + case T1F_IREADY|T1F_IHALF|T1F_IFULL: + bus_space_read_multi_1(sc->sc_io_bt, sc->sc_io_bh, + T1_READ, dp, FIFO_INPBSIZE); + dp += FIFO_INPBSIZE; + i -= FIFO_INPBSIZE; + break; + + case T1F_IREADY|T1F_IHALF: + bus_space_read_multi_1(sc->sc_io_bt, sc->sc_io_bh, + T1_READ, dp, i); + dp += i; + i = 0; + break; + + default: + *dp++ = b1io_get_byte(sc); + i--; + } + } + } else { /* not fastlink */ + if (i--) *dp++ = b1io_get_byte(sc); + } + return len; +} + +static __inline void t1io_put_slice(iavc_softc_t *sc, u_int8_t *dp, int len) +{ + int i = len; + b1io_put_word(sc, i); + if (t1io_isfastlink(sc)) { + int status; + while (i) { + status = t1io_fifostatus(sc) & (T1F_OREADY|T1F_OHALF); + if (i >= FIFO_OUTBSIZE) status |= T1F_OFULL; + + switch (status) { + case T1F_OREADY|T1F_OHALF|T1F_OFULL: + bus_space_write_multi_1(sc->sc_io_bt, sc->sc_io_bh, + T1_WRITE, dp, FIFO_OUTBSIZE); + dp += FIFO_OUTBSIZE; + i -= FIFO_OUTBSIZE; + break; + + case T1F_OREADY|T1F_OHALF: + bus_space_write_multi_1(sc->sc_io_bt, sc->sc_io_bh, + T1_WRITE, dp, i); + dp += i; + i = 0; + break; + + default: + b1io_put_byte(sc, *dp++); + i--; + } + } + } else { + while (i--) b1io_put_byte(sc, *dp++); + } +} + +/* +// An attempt to bring it all together: +// ------------------------------------ +// +// iavc_{read,write}_reg +// Routines to access the device registers via the I/O port. +// +// iavc_{read,write}_port +// Routines to access the device I/O ports. +// +// iavc_tx_empty, iavc_rx_full +// Routines to check when the device has drained the last written +// byte, or produced a full byte to read. +// +// iavc_{get,put}_byte +// Routines to read/write byte values to the device via the I/O port. +// +// iavc_{get,put}_word +// Routines to read/write 32-bit words to the device via the I/O port. +// +// iavc_{get,put}_slice +// Routines to read/write {length, data} pairs to the device via the +// ubiquituous I/O port. Uses the HEMA FIFO on a T1. +*/ + +#define iavc_read_reg(sc, reg) b1io_read_reg(sc, reg) +#define iavc_write_reg(sc, reg, val) b1io_write_reg(sc, reg, val) + +#define iavc_read_port(sc, port) \ + bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, (port)) +#define iavc_write_port(sc, port, val) \ + bus_space_write_1(sc->sc_io_bt, sc->sc_io_bh, (port), (val)) + +#define iavc_tx_empty(sc) b1io_tx_empty(sc) +#define iavc_rx_full(sc) b1io_rx_full(sc) + +#define iavc_get_byte(sc) b1io_get_byte(sc) +#define iavc_put_byte(sc, val) b1io_put_byte(sc, val) +#define iavc_get_word(sc) b1io_get_word(sc) +#define iavc_put_word(sc, val) b1io_put_word(sc, val) + +static __inline u_int32_t iavc_get_slice(iavc_softc_t *sc, u_int8_t *dp) +{ + if (sc->sc_t1) return t1io_get_slice(sc, dp); + else return b1io_get_slice(sc, dp); +} + +static __inline void iavc_put_slice(iavc_softc_t *sc, u_int8_t *dp, int len) +{ + if (sc->sc_t1) t1io_put_slice(sc, dp, len); + else b1io_put_slice(sc, dp, len); +} + +/* +// iavc_handle_intr +// Interrupt handler, called by the bus specific interrupt routine +// in iavc_.c module. +// +// iavc_load +// CAPI callback. Resets device and loads firmware. +// +// iavc_register +// CAPI callback. Registers an application id. +// +// iavc_release +// CAPI callback. Releases an application id. +// +// iavc_send +// CAPI callback. Sends a CAPI message. A B3_DATA_REQ message has +// m_next point to a data mbuf. +*/ + +extern void iavc_handle_intr(iavc_softc_t *); +extern int iavc_load(capi_softc_t *, int, u_int8_t *); +extern int iavc_register(capi_softc_t *, int, int); +extern int iavc_release(capi_softc_t *, int); +extern int iavc_send(capi_softc_t *, struct mbuf *); + +extern void b1isa_setup_irq(struct iavc_softc *sc); + +#endif /* _CAPI_IAVC_H_ */ diff --git a/sys/i4b/capi/iavc/iavc_card.c b/sys/i4b/capi/iavc/iavc_card.c new file mode 100644 index 0000000..831dc68 --- /dev/null +++ b/sys/i4b/capi/iavc/iavc_card.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * capi/iavc/iavc_card.c + * The AVM ISDN controllers' card specific support routines. + * + * $FreeBSD$ + */ + +#include "iavc.h" +#include "i4bcapi.h" +#include "pci.h" + +#if (NIAVC > 0) && (NI4BCAPI > 0) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +/* +// AVM B1 (active BRI, PIO mode) +*/ + +int b1_detect(iavc_softc_t *sc) +{ + if ((iavc_read_port(sc, B1_INSTAT) & 0xfc) || + (iavc_read_port(sc, B1_OUTSTAT) & 0xfc)) + return (1); + + b1io_outp(sc, B1_INSTAT, 0x02); + b1io_outp(sc, B1_OUTSTAT, 0x02); + if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) != 2 || + (iavc_read_port(sc, B1_OUTSTAT) & 0xfe) != 2) + return (2); + + b1io_outp(sc, B1_INSTAT, 0x00); + b1io_outp(sc, B1_OUTSTAT, 0x00); + if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) || + (iavc_read_port(sc, B1_OUTSTAT) & 0xfe)) + return (3); + + return (0); /* found */ +} + +void b1_disable_irq(iavc_softc_t *sc) +{ + b1io_outp(sc, B1_INSTAT, 0x00); +} + +void b1_reset(iavc_softc_t *sc) +{ + b1io_outp(sc, B1_RESET, 0); + DELAY(55*2*1000); + + b1io_outp(sc, B1_RESET, 1); + DELAY(55*2*1000); + + b1io_outp(sc, B1_RESET, 0); + DELAY(55*2*1000); +} + +/* +// Newer PCI-based B1's, and T1's, supports DMA +*/ + +int b1dma_detect(iavc_softc_t *sc) +{ + AMCC_WRITE(sc, AMCC_MCSR, 0); + DELAY(10*1000); + AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000); + DELAY(10*1000); + AMCC_WRITE(sc, AMCC_MCSR, 0); + DELAY(42*1000); + + AMCC_WRITE(sc, AMCC_RXLEN, 0); + AMCC_WRITE(sc, AMCC_TXLEN, 0); + sc->sc_csr = 0; + AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr); + + if (AMCC_READ(sc, AMCC_INTCSR) != 0) + return 1; + + AMCC_WRITE(sc, AMCC_RXPTR, 0xffffffff); + AMCC_WRITE(sc, AMCC_TXPTR, 0xffffffff); + if ((AMCC_READ(sc, AMCC_RXPTR) != 0xfffffffc) || + (AMCC_READ(sc, AMCC_TXPTR) != 0xfffffffc)) + return 2; + + AMCC_WRITE(sc, AMCC_RXPTR, 0); + AMCC_WRITE(sc, AMCC_TXPTR, 0); + if ((AMCC_READ(sc, AMCC_RXPTR) != 0) || + (AMCC_READ(sc, AMCC_TXPTR) != 0)) + return 3; + + iavc_write_port(sc, 0x10, 0x00); + iavc_write_port(sc, 0x07, 0x00); + + iavc_write_port(sc, 0x02, 0x02); + iavc_write_port(sc, 0x03, 0x02); + + if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x02) || + (iavc_read_port(sc, 0x03) != 0x03)) + return 4; + + iavc_write_port(sc, 0x02, 0x00); + iavc_write_port(sc, 0x03, 0x00); + + if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x00) || + (iavc_read_port(sc, 0x03) != 0x01)) + return 5; + + return (0); /* found */ +} + +void b1dma_reset(iavc_softc_t *sc) +{ + int s = SPLI4B(); + + sc->sc_csr = 0; + AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr); + AMCC_WRITE(sc, AMCC_MCSR, 0); + AMCC_WRITE(sc, AMCC_RXLEN, 0); + AMCC_WRITE(sc, AMCC_TXLEN, 0); + + iavc_write_port(sc, 0x10, 0x00); /* XXX magic numbers from */ + iavc_write_port(sc, 0x07, 0x00); /* XXX the linux driver */ + + splx(s); + + AMCC_WRITE(sc, AMCC_MCSR, 0); + DELAY(10 * 1000); + AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000); + DELAY(10 * 1000); + AMCC_WRITE(sc, AMCC_MCSR, 0); + DELAY(42 * 1000); +} + +/* +// AVM T1 (active PRI) +*/ + +/* XXX how do these differ from b1io_{read,write}_reg()? XXX */ + +static int b1dma_tx_empty(int iobase) +{ return inb(iobase + 3) & 1; } + +static int b1dma_rx_full(int iobase) +{ return inb(iobase + 2) & 1; } + +static int b1dma_tolink(iavc_softc_t *sc, void *buf, int len) +{ + volatile int spin; + char *s = (char*) buf; + while (len--) { + spin = 0; + while (!b1dma_tx_empty(sc->sc_iobase) && spin < 100000) + spin++; + if (!b1dma_tx_empty(sc->sc_iobase)) + return -1; + t1io_outp(sc, 1, *s++); + } + return 0; +} + +static int b1dma_fromlink(iavc_softc_t *sc, void *buf, int len) +{ + volatile int spin; + char *s = (char*) buf; + while (len--) { + spin = 0; + while (!b1dma_rx_full(sc->sc_iobase) && spin < 100000) + spin++; + if (!b1dma_rx_full(sc->sc_iobase)) + return -1; + *s++ = t1io_inp(sc, 0); + } + return 0; +} + +static int WriteReg(iavc_softc_t *sc, u_int32_t reg, u_int8_t val) +{ + u_int8_t cmd = 0; + if (b1dma_tolink(sc, &cmd, 1) == 0 && + b1dma_tolink(sc, ®, 4) == 0) { + u_int32_t tmp = val; + return b1dma_tolink(sc, &tmp, 4); + } + return -1; +} + +static u_int8_t ReadReg(iavc_softc_t *sc, u_int32_t reg) +{ + u_int8_t cmd = 1; + if (b1dma_tolink(sc, &cmd, 1) == 0 && + b1dma_tolink(sc, ®, 4) == 0) { + u_int32_t tmp; + if (b1dma_fromlink(sc, &tmp, 4) == 0) + return (u_int8_t) tmp; + } + return 0xff; +} + +int t1_detect(iavc_softc_t *sc) +{ + int ret = b1dma_detect(sc); + if (ret) return ret; + + if ((WriteReg(sc, 0x80001000, 0x11) != 0) || + (WriteReg(sc, 0x80101000, 0x22) != 0) || + (WriteReg(sc, 0x80201000, 0x33) != 0) || + (WriteReg(sc, 0x80301000, 0x44) != 0)) + return 6; + + if ((ReadReg(sc, 0x80001000) != 0x11) || + (ReadReg(sc, 0x80101000) != 0x22) || + (ReadReg(sc, 0x80201000) != 0x33) || + (ReadReg(sc, 0x80301000) != 0x44)) + return 7; + + if ((WriteReg(sc, 0x80001000, 0x55) != 0) || + (WriteReg(sc, 0x80101000, 0x66) != 0) || + (WriteReg(sc, 0x80201000, 0x77) != 0) || + (WriteReg(sc, 0x80301000, 0x88) != 0)) + return 8; + + if ((ReadReg(sc, 0x80001000) != 0x55) || + (ReadReg(sc, 0x80101000) != 0x66) || + (ReadReg(sc, 0x80201000) != 0x77) || + (ReadReg(sc, 0x80301000) != 0x88)) + return 9; + + return 0; /* found */ +} + +void t1_disable_irq(iavc_softc_t *sc) +{ + iavc_write_port(sc, T1_IRQMASTER, 0x00); +} + +void t1_reset(iavc_softc_t *sc) +{ + b1_reset(sc); + iavc_write_port(sc, B1_INSTAT, 0x00); + iavc_write_port(sc, B1_OUTSTAT, 0x00); + iavc_write_port(sc, T1_IRQMASTER, 0x00); + iavc_write_port(sc, T1_RESETBOARD, 0x0f); +} + +#endif diff --git a/sys/i4b/capi/iavc/iavc_isa.c b/sys/i4b/capi/iavc/iavc_isa.c new file mode 100644 index 0000000..96ea1c9 --- /dev/null +++ b/sys/i4b/capi/iavc/iavc_isa.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2001 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "iavc.h" +#include "i4bcapi.h" + +#if (NIAVC > 0) && (NI4BCAPI > 0) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +/* ISA driver linkage */ + +static void iavc_isa_intr(iavc_softc_t *sc); +static int iavc_isa_probe(device_t dev); +static int iavc_isa_attach(device_t dev); + +static device_method_t iavc_isa_methods[] = +{ + DEVMETHOD(device_probe, iavc_isa_probe), + DEVMETHOD(device_attach, iavc_isa_attach), + { 0, 0 } +}; + +static driver_t iavc_isa_driver = +{ + "iavc", + iavc_isa_methods, + 0 +}; + +static devclass_t iavc_isa_devclass; + +DRIVER_MODULE(iavc, isa, iavc_isa_driver, iavc_isa_devclass, 0, 0); + +#define B1_IOLENGTH 0x20 + +static int b1_irq_table[] = +{0, 0, 0, 192, 32, 160, 96, 224, 0, 64, 80, 208, 48, 0, 0, 112}; +/* 3 4 5 6 7 9 10 11 12 15 */ + +/*---------------------------------------------------------------------------* + * device probe + *---------------------------------------------------------------------------*/ + +static int +iavc_isa_probe(device_t dev) +{ + struct iavc_softc *sc; + int ret = ENXIO; + int unit = device_get_unit(dev); + + if(isa_get_vendorid(dev)) /* no PnP probes here */ + return ENXIO; + + /* check max unit range */ + + if (unit >= IAVC_MAXUNIT) + { + printf("iavc%d: too many units\n", unit); + return(ENXIO); + } + + sc = iavc_find_sc(unit); /* get softc */ + + sc->sc_unit = unit; + + if (!(sc->sc_resources.io_base[0] = + bus_alloc_resource(dev, SYS_RES_IOPORT, + &sc->sc_resources.io_rid[0], + 0UL, ~0UL, B1_IOLENGTH, RF_ACTIVE))) + { + printf("iavc%d: can't allocate io region\n", unit); + return(ENXIO); + } + + sc->sc_iobase = rman_get_start(sc->sc_resources.io_base[0]); + + switch(sc->sc_iobase) + { + case 0x150: + case 0x250: + case 0x300: + case 0x340: + break; + default: + printf("iavc%d: ERROR, invalid i/o base addr 0x%x configured!\n", sc->sc_unit, sc->sc_iobase); + bus_release_resource(dev, SYS_RES_IOPORT, + sc->sc_resources.io_rid[0], + sc->sc_resources.io_base[0]); + return(ENXIO); + } + + sc->sc_io_bt = rman_get_bustag(sc->sc_resources.io_base[0]); + sc->sc_io_bh = rman_get_bushandle(sc->sc_resources.io_base[0]); + + /* setup characteristics */ + + sc->sc_t1 = FALSE; + sc->sc_dma = FALSE; + + sc->sc_capi.card_type = CARD_TYPEC_AVM_B1_ISA; + sc->sc_capi.sc_nbch = 2; + + b1_reset(sc); + DELAY(100); + + ret = b1_detect(sc); + + if(ret) + { + printf("iavc%d: no card ? b1_detect returns 0x02x\n", sc->sc_unit, ret); + return(ENXIO); + } + + DELAY(100); + + b1_reset(sc); + + DELAY(100); + + if(bootverbose) + { + printf("iavc%d: class = 0x%02x, rev = 0x%02x\n", sc->sc_unit, + iavc_read_port(sc, B1_ANALYSE), + iavc_read_port(sc, B1_REVISION)); + } + + device_set_desc(dev, "AVM B1 ISA"); + return(0); +} + +/*---------------------------------------------------------------------------* + * attach + *---------------------------------------------------------------------------*/ +static int +iavc_isa_attach(device_t dev) +{ + struct iavc_softc *sc; + void *ih = 0; + int unit = device_get_unit(dev); + int irq; + + sc = iavc_find_sc(unit); /* get softc */ + + sc->sc_resources.irq_rid = 0; + + if(!(sc->sc_resources.irq = + bus_alloc_resource(dev, SYS_RES_IRQ, + &sc->sc_resources.irq_rid, + 0UL, ~0UL, 1, RF_ACTIVE))) + { + printf("iavc%d: can't allocate irq\n",unit); + bus_release_resource(dev, SYS_RES_IOPORT, + sc->sc_resources.io_rid[0], + sc->sc_resources.io_base[0]); + return(ENXIO); + } + + irq = rman_get_start(sc->sc_resources.irq); + + if(b1_irq_table[irq] == 0) + { + printf("iavc%d: ERROR, illegal irq %d configured!\n",unit, irq); + bus_release_resource(dev, SYS_RES_IOPORT, + sc->sc_resources.io_rid[0], + sc->sc_resources.io_base[0]); + bus_release_resource(dev, SYS_RES_IRQ, + sc->sc_resources.irq_rid, + sc->sc_resources.irq); + return(ENXIO); + } + + memset(&sc->sc_txq, 0, sizeof(struct ifqueue)); + sc->sc_txq.ifq_maxlen = sc->sc_capi.sc_nbch * 4; + +#if defined (__FreeBSD__) && __FreeBSD__ > 4 + mtx_init(&sc->sc_txq.ifq_mtx, "i4b_ivac_isa", MTX_DEF); +#endif + + sc->sc_intr = FALSE; + sc->sc_state = IAVC_DOWN; + sc->sc_blocked = FALSE; + + /* setup capi link */ + + sc->sc_capi.load = iavc_load; + sc->sc_capi.reg_appl = iavc_register; + sc->sc_capi.rel_appl = iavc_release; + sc->sc_capi.send = iavc_send; + sc->sc_capi.ctx = (void*) sc; + + if (capi_ll_attach(&sc->sc_capi)) + { + printf("iavc%d: capi attach failed\n", unit); + return(ENXIO); + } + + /* setup the interrupt */ + + if(bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, + (void(*)(void*))iavc_isa_intr, + sc, &ih)) + { + printf("iavc%d: irq setup failed\n", unit); + bus_release_resource(dev, SYS_RES_IOPORT, + sc->sc_resources.io_rid[0], + sc->sc_resources.io_base[0]); + bus_release_resource(dev, SYS_RES_IRQ, + sc->sc_resources.irq_rid, + sc->sc_resources.irq); + return(ENXIO); + } + + /* the board is now ready to be loaded */ + + return(0); +} + +/*---------------------------------------------------------------------------* + * setup interrupt + *---------------------------------------------------------------------------*/ +void +b1isa_setup_irq(struct iavc_softc *sc) +{ + int irq = rman_get_start(sc->sc_resources.irq); + + if(bootverbose) + printf("iavc%d: using irq %d\n", sc->sc_unit, irq); + + /* enable the interrupt */ + + b1io_outp(sc, B1_INSTAT, 0x00); + b1io_outp(sc, B1_RESET, b1_irq_table[irq]); + b1io_outp(sc, B1_INSTAT, 0x02); +} + +/*---------------------------------------------------------------------------* + * IRQ handler + *---------------------------------------------------------------------------*/ +static void +iavc_isa_intr(struct iavc_softc *sc) +{ + iavc_handle_intr(sc); +} + +#endif diff --git a/sys/i4b/capi/iavc/iavc_lli.c b/sys/i4b/capi/iavc/iavc_lli.c new file mode 100644 index 0000000..7ce7eb4 --- /dev/null +++ b/sys/i4b/capi/iavc/iavc_lli.c @@ -0,0 +1,834 @@ +/* + * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * capi/iavc/iavc_lli.c + * The AVM ISDN controllers' Low Level Interface. + * + * $FreeBSD$ + */ + +#include "iavc.h" +#include "i4bcapi.h" +#include "pci.h" + +#if (NIAVC > 0) && (NI4BCAPI > 0) + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +/* Forward declarations of local subroutines... */ + +static int iavc_send_init(iavc_softc_t *); + +static void iavc_handle_rx(iavc_softc_t *); +static void iavc_start_tx(iavc_softc_t *); + +/* +// Callbacks from the upper (capi) layer: +// -------------------------------------- +// +// iavc_load +// Resets the board and loads the firmware, then initiates +// board startup. +// +// iavc_register +// Registers a CAPI application id. +// +// iavc_release +// Releases a CAPI application id. +// +// iavc_send +// Sends a capi message. +*/ + +int iavc_load(capi_softc_t *capi_sc, int len, u_int8_t *cp) +{ + iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx; + u_int8_t val; + + if(bootverbose) + printf("iavc%d: reset card ....\n", sc->sc_unit); + + if (sc->sc_dma) + b1dma_reset(sc); /* PCI cards */ + else if (sc->sc_t1) + t1_reset(sc); /* ISA attachment T1 */ + else + b1_reset(sc); /* ISA attachment B1 */ + + DELAY(1000); + + if(bootverbose) + printf("iavc%d: start loading %d bytes firmware ....\n", sc->sc_unit, len); + + while (len && b1io_save_put_byte(sc, *cp++) == 0) + len--; + + if (len) { + printf("iavc%d: loading failed, can't write to card, len = %d\n", + sc->sc_unit, len); + return (EIO); + } + + if(bootverbose) + printf("iavc%d: firmware loaded, wait for ACK ....\n", sc->sc_unit); + + if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA) + iavc_put_byte(sc, SEND_POLL); + else + iavc_put_byte(sc, SEND_POLLACK); + + for (len = 0; len < 1000 && !iavc_rx_full(sc); len++) + DELAY(100); + + if (!iavc_rx_full(sc)) { + printf("iavc%d: loading failed, no ack\n", sc->sc_unit); + return (EIO); + } + + val = iavc_get_byte(sc); + + if ((sc->sc_dma && val != RECEIVE_POLLDWORD) || + (!sc->sc_dma && val != RECEIVE_POLL)) { + printf("iavc%d: loading failed, bad ack = %02x\n", sc->sc_unit, val); + return (EIO); + } + + if(bootverbose) + printf("iavc%d: got ACK = 0x%02x\n", sc->sc_unit, val); + + if (sc->sc_dma) { + /* Start the DMA engine */ + + int s = SPLI4B(); + + sc->sc_csr = AVM_FLAG; + AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr); + AMCC_WRITE(sc, AMCC_MCSR, (EN_A2P_TRANSFERS|EN_P2A_TRANSFERS| + A2P_HI_PRIORITY|P2A_HI_PRIORITY| + RESET_A2P_FLAGS|RESET_P2A_FLAGS)); + + iavc_write_port(sc, 0x07, 0x30); /* XXX magic numbers from */ + iavc_write_port(sc, 0x10, 0xf0); /* XXX the linux driver */ + + sc->sc_recvlen = 0; + AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[0])); + AMCC_WRITE(sc, AMCC_RXLEN, 4); + sc->sc_csr |= EN_RX_TC_INT|EN_TX_TC_INT; + AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr); + + splx(s); + } + + if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA) + b1isa_setup_irq(sc); + + iavc_send_init(sc); + + return 0; +} + +int iavc_register(capi_softc_t *capi_sc, int applid, int nchan) +{ + iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx; + struct mbuf *m = i4b_Dgetmbuf(23); + u_int8_t *p; + + if (!m) { + printf("iavc%d: can't get memory\n", sc->sc_unit); + return (ENOMEM); + } + + /* + * byte 0x12 = SEND_REGISTER + * dword ApplId + * dword NumMessages + * dword NumB3Connections 0..nbch + * dword NumB3Blocks + * dword B3Size + */ + + p = amcc_put_byte(mtod(m, u_int8_t*), 0); + p = amcc_put_byte(p, 0); + p = amcc_put_byte(p, SEND_REGISTER); + p = amcc_put_word(p, applid); +#if 0 + p = amcc_put_word(p, 1024 + (nchan + 1)); +#else + p = amcc_put_word(p, 1024 * (nchan + 1)); +#endif + p = amcc_put_word(p, nchan); + p = amcc_put_word(p, 8); + p = amcc_put_word(p, 2048); + + _IF_ENQUEUE(&sc->sc_txq, m); + + iavc_start_tx(sc); + + return 0; +} + +int iavc_release(capi_softc_t *capi_sc, int applid) +{ + iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx; + struct mbuf *m = i4b_Dgetmbuf(7); + u_int8_t *p; + + if (!m) { + printf("iavc%d: can't get memory\n", sc->sc_unit); + return (ENOMEM); + } + + /* + * byte 0x14 = SEND_RELEASE + * dword ApplId + */ + + p = amcc_put_byte(mtod(m, u_int8_t*), 0); + p = amcc_put_byte(p, 0); + p = amcc_put_byte(p, SEND_RELEASE); + p = amcc_put_word(p, applid); + + _IF_ENQUEUE(&sc->sc_txq, m); + + iavc_start_tx(sc); + return 0; +} + +int iavc_send(capi_softc_t *capi_sc, struct mbuf *m) +{ + iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx; + + if (sc->sc_state != IAVC_UP) { + printf("iavc%d: attempt to send before device up\n", sc->sc_unit); + + if (m->m_next) i4b_Bfreembuf(m->m_next); + i4b_Dfreembuf(m); + + return (ENXIO); + } + + if (_IF_QFULL(&sc->sc_txq)) { + _IF_DROP(&sc->sc_txq); + + printf("iavc%d: tx overflow, message dropped\n", sc->sc_unit); + + if (m->m_next) i4b_Bfreembuf(m->m_next); + i4b_Dfreembuf(m); + + } else { + _IF_ENQUEUE(&sc->sc_txq, m); + + iavc_start_tx(sc); + } + + return 0; +} + +/* +// Functions called by ourself during the initialization sequence: +// --------------------------------------------------------------- +// +// iavc_send_init +// Sends the system initialization message to a newly loaded +// board, and sets state to INIT. +*/ + +static int iavc_send_init(iavc_softc_t *sc) +{ + struct mbuf *m = i4b_Dgetmbuf(15); + u_int8_t *p; + int s; + + if (!m) { + printf("iavc%d: can't get memory\n", sc->sc_unit); + return (ENOMEM); + } + + /* + * byte 0x11 = SEND_INIT + * dword NumApplications + * dword NumNCCIs + * dword BoardNumber + */ + + p = amcc_put_byte(mtod(m, u_int8_t*), 0); + p = amcc_put_byte(p, 0); + p = amcc_put_byte(p, SEND_INIT); + p = amcc_put_word(p, 1); /* XXX MaxAppl XXX */ + p = amcc_put_word(p, sc->sc_capi.sc_nbch); + p = amcc_put_word(p, sc->sc_unit); + + s = SPLI4B(); + _IF_ENQUEUE(&sc->sc_txq, m); + + iavc_start_tx(sc); + + sc->sc_state = IAVC_INIT; + splx(s); + return 0; +} + +/* +// Functions called during normal operation: +// ----------------------------------------- +// +// iavc_receive_init +// Reads the initialization reply and calls capi_ll_control(). +// +// iavc_receive_new_ncci +// Reads a new NCCI notification and calls capi_ll_control(). +// +// iavc_receive_free_ncci +// Reads a freed NCCI notification and calls capi_ll_control(). +// +// iavc_receive_task_ready +// Reads a task ready message -- which should not occur XXX. +// +// iavc_receive_debugmsg +// Reads a debug message -- which should not occur XXX. +// +// iavc_receive_start +// Reads a START TRANSMIT message and unblocks device. +// +// iavc_receive_stop +// Reads a STOP TRANSMIT message and blocks device. +// +// iavc_receive +// Reads an incoming message and calls capi_ll_receive(). +*/ + +static int iavc_receive_init(iavc_softc_t *sc, u_int8_t *dmabuf) +{ + u_int32_t Length; + u_int8_t *p; + u_int8_t *cardtype, *serial, *profile, *version, *caps, *prot; + + if (sc->sc_dma) { + p = amcc_get_word(dmabuf, &Length); + } else { + Length = iavc_get_slice(sc, sc->sc_recvbuf); + p = sc->sc_recvbuf; + } + +#if 0 + { + int len = 0; + printf("iavc%d: rx_init: ", sc->sc_unit); + while (len < Length) { + printf(" %02x", p[len]); + if (len && (len % 16) == 0) printf("\n"); + len++; + } + if (len % 16) printf("\n"); + } +#endif + + version = (p + 1); + p += (*p + 1); /* driver version */ + cardtype = (p + 1); + p += (*p + 1); /* card type */ + p += (*p + 1); /* hardware ID */ + serial = (p + 1); + p += (*p + 1); /* serial number */ + caps = (p + 1); + p += (*p + 1); /* supported options */ + prot = (p + 1); + p += (*p + 1); /* supported protocols */ + profile = (p + 1); + + if (cardtype && serial && profile) { + int nbch = ((profile[3]<<8) | profile[2]); + + printf("iavc%d: AVM %s, s/n %s, %d chans, f/w rev %s, prot %s\n", + sc->sc_unit, cardtype, serial, nbch, version, prot); + + if(bootverbose) + printf("iavc%d: %s\n", sc->sc_unit, caps); + + capi_ll_control(&sc->sc_capi, CAPI_CTRL_PROFILE, (int) profile); + + } else { + printf("iavc%d: no profile data in info response?\n", sc->sc_unit); + } + + sc->sc_blocked = TRUE; /* controller will send START when ready */ + return 0; +} + +static int iavc_receive_start(iavc_softc_t *sc, u_int8_t *dmabuf) +{ + struct mbuf *m = i4b_Dgetmbuf(3); + u_int8_t *p; + + if (sc->sc_blocked && sc->sc_state == IAVC_UP) + printf("iavc%d: receive_start\n", sc->sc_unit); + + if (!m) { + printf("iavc%d: can't get memory\n", sc->sc_unit); + return (ENOMEM); + } + + /* + * byte 0x73 = SEND_POLLACK + */ + + p = amcc_put_byte(mtod(m, u_int8_t*), 0); + p = amcc_put_byte(p, 0); + p = amcc_put_byte(p, SEND_POLLACK); + + _IF_PREPEND(&sc->sc_txq, m); + + NDBGL4(L4_IAVCDBG, "iavc%d: blocked = %d, state = %d", + sc->sc_unit, sc->sc_blocked, sc->sc_state); + + sc->sc_blocked = FALSE; + iavc_start_tx(sc); + + /* If this was our first START, register our readiness */ + + if (sc->sc_state != IAVC_UP) { + sc->sc_state = IAVC_UP; + capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, TRUE); + } + + return 0; +} + +static int iavc_receive_stop(iavc_softc_t *sc, u_int8_t *dmabuf) +{ + printf("iavc%d: receive_stop\n", sc->sc_unit); + sc->sc_blocked = TRUE; + return 0; +} + +static int iavc_receive_new_ncci(iavc_softc_t *sc, u_int8_t *dmabuf) +{ + u_int32_t ApplId, NCCI, WindowSize; + + if (sc->sc_dma) { + dmabuf = amcc_get_word(dmabuf, &ApplId); + dmabuf = amcc_get_word(dmabuf, &NCCI); + dmabuf = amcc_get_word(dmabuf, &WindowSize); + } else { + ApplId = iavc_get_word(sc); + NCCI = iavc_get_word(sc); + WindowSize = iavc_get_word(sc); + } + + capi_ll_control(&sc->sc_capi, CAPI_CTRL_NEW_NCCI, NCCI); + return 0; +} + +static int iavc_receive_free_ncci(iavc_softc_t *sc, u_int8_t *dmabuf) +{ + u_int32_t ApplId, NCCI; + + if (sc->sc_dma) { + dmabuf = amcc_get_word(dmabuf, &ApplId); + dmabuf = amcc_get_word(dmabuf, &NCCI); + } else { + ApplId = iavc_get_word(sc); + NCCI = iavc_get_word(sc); + } + + capi_ll_control(&sc->sc_capi, CAPI_CTRL_FREE_NCCI, NCCI); + return 0; +} + +static int iavc_receive_task_ready(iavc_softc_t *sc, u_int8_t *dmabuf) +{ + u_int32_t TaskId, Length; + u_int8_t *p; + printf("iavc%d: receive_task_ready\n", sc->sc_unit); + + if (sc->sc_dma) { + p = amcc_get_word(dmabuf, &TaskId); + p = amcc_get_word(p, &Length); + } else { + TaskId = iavc_get_word(sc); + Length = iavc_get_slice(sc, sc->sc_recvbuf); + p = sc->sc_recvbuf; + } + + /* XXX could show the message if trace enabled? XXX */ + return 0; +} + +static int iavc_receive_debugmsg(iavc_softc_t *sc, u_int8_t *dmabuf) +{ + u_int32_t Length; + u_int8_t *p; + printf("iavc%d: receive_debugmsg\n", sc->sc_unit); + + if (sc->sc_dma) { + p = amcc_get_word(dmabuf, &Length); + } else { + Length = iavc_get_slice(sc, sc->sc_recvbuf); + p = sc->sc_recvbuf; + } + + /* XXX could show the message if trace enabled? XXX */ + return 0; +} + +static int iavc_receive(iavc_softc_t *sc, u_int8_t *dmabuf, int b3data) +{ + struct mbuf *m; + u_int32_t ApplId, Length; + + /* + * byte 0x21 = RECEIVE_MESSAGE + * dword ApplId + * dword length + * ... CAPI msg + * + * --or-- + * + * byte 0x22 = RECEIVE_DATA_B3_IND + * dword ApplId + * dword length + * ... CAPI msg + * dword datalen + * ... B3 data + */ + + if (sc->sc_dma) { + dmabuf = amcc_get_word(dmabuf, &ApplId); + dmabuf = amcc_get_word(dmabuf, &Length); + } else { + ApplId = iavc_get_word(sc); + Length = iavc_get_slice(sc, sc->sc_recvbuf); + dmabuf = sc->sc_recvbuf; + } + + m = i4b_Dgetmbuf(Length); + if (!m) { + printf("iavc%d: can't get memory for receive\n", sc->sc_unit); + return (ENOMEM); + } + + bcopy(dmabuf, mtod(m, u_int8_t*), Length); + +#if 0 + { + u_int8_t *p = mtod(m, u_int8_t*); + int len = 0; + printf("iavc%d: applid=%d, len=%d\n", sc->sc_unit, ApplId, Length); + while (len < m->m_len) { + printf(" %02x", p[len]); + if (len && (len % 16) == 0) printf("\n"); + len++; + } + if (len % 16) printf("\n"); + } +#endif + + if (b3data) { + if (sc->sc_dma) { + dmabuf = amcc_get_word(dmabuf + Length, &Length); + } else { + Length = iavc_get_slice(sc, sc->sc_recvbuf); + dmabuf = sc->sc_recvbuf; + } + + m->m_next = i4b_Bgetmbuf(Length); + if (!m->m_next) { + printf("iavc%d: can't get memory for receive\n", sc->sc_unit); + i4b_Dfreembuf(m); + return (ENOMEM); + } + + bcopy(dmabuf, mtod(m->m_next, u_int8_t*), Length); + } + + capi_ll_receive(&sc->sc_capi, m); + return 0; +} + +/* +// iavc_handle_intr +// Checks device interrupt status and calls iavc_handle_{rx,tx}() +// as necessary. +// +// iavc_handle_rx +// Reads in the command byte and calls the subroutines above. +// +// iavc_start_tx +// Initiates DMA on the next queued message if possible. +*/ + +void iavc_handle_intr(iavc_softc_t *sc) +{ + u_int32_t status; + u_int32_t newcsr; + + if (!sc->sc_dma) { + while (iavc_rx_full(sc)) + iavc_handle_rx(sc); + return; + } + + status = AMCC_READ(sc, AMCC_INTCSR); + if ((status & ANY_S5933_INT) == 0) + return; + + newcsr = sc->sc_csr | (status & ALL_INT); + if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT; + if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT; + AMCC_WRITE(sc, AMCC_INTCSR, newcsr); + sc->sc_intr = TRUE; + + if (status & RX_TC_INT) { + u_int32_t rxlen; + + if (sc->sc_recvlen == 0) { + sc->sc_recvlen = *((u_int32_t*)(&sc->sc_recvbuf[0])); + rxlen = (sc->sc_recvlen + 3) & ~3; + AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[4])); + AMCC_WRITE(sc, AMCC_RXLEN, rxlen); + } else { + iavc_handle_rx(sc); + sc->sc_recvlen = 0; + AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[0])); + AMCC_WRITE(sc, AMCC_RXLEN, 4); + } + } + + if (status & TX_TC_INT) { + sc->sc_csr &= ~EN_TX_TC_INT; + iavc_start_tx(sc); + } + + AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr); + sc->sc_intr = FALSE; +} + +static void iavc_handle_rx(iavc_softc_t *sc) +{ + u_int8_t *dmabuf = 0, cmd; + + if (sc->sc_dma) { + dmabuf = amcc_get_byte(&sc->sc_recvbuf[4], &cmd); + } else { + cmd = iavc_get_byte(sc); + } + + NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd); + + switch (cmd) { + case RECEIVE_DATA_B3_IND: + iavc_receive(sc, dmabuf, TRUE); + break; + + case RECEIVE_MESSAGE: + iavc_receive(sc, dmabuf, FALSE); + break; + + case RECEIVE_NEW_NCCI: + iavc_receive_new_ncci(sc, dmabuf); + break; + + case RECEIVE_FREE_NCCI: + iavc_receive_free_ncci(sc, dmabuf); + break; + + case RECEIVE_START: + iavc_receive_start(sc, dmabuf); + break; + + case RECEIVE_STOP: + iavc_receive_stop(sc, dmabuf); + break; + + case RECEIVE_INIT: + iavc_receive_init(sc, dmabuf); + break; + + case RECEIVE_TASK_READY: + iavc_receive_task_ready(sc, dmabuf); + break; + + case RECEIVE_DEBUGMSG: + iavc_receive_debugmsg(sc, dmabuf); + break; + + default: + printf("iavc%d: unknown msg %02x\n", sc->sc_unit, cmd); + } +} + +static void iavc_start_tx(iavc_softc_t *sc) +{ + struct mbuf *m; + u_int8_t *dmabuf; + u_int32_t txlen = 0; + + /* If device has put us on hold, punt. */ + + if (sc->sc_blocked) { + return; + } + + /* If using DMA and transmitter busy, punt. */ + + if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) { + return; + } + + /* Else, see if we have messages to send. */ + + _IF_DEQUEUE(&sc->sc_txq, m); + if (!m) { + return; + } + + /* Have message, will send. */ + + if (CAPIMSG_LEN(m->m_data)) { + /* A proper CAPI message, possibly with B3 data */ + + if (sc->sc_dma) { + /* Copy message to DMA buffer. */ + + if (m->m_next) { + dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_DATA_B3_REQ); + } else { + dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_MESSAGE); + } + + dmabuf = amcc_put_word(dmabuf, m->m_len); + bcopy(m->m_data, dmabuf, m->m_len); + dmabuf += m->m_len; + txlen = 5 + m->m_len; + + if (m->m_next) { + dmabuf = amcc_put_word(dmabuf, m->m_next->m_len); + bcopy(m->m_next->m_data, dmabuf, m->m_next->m_len); + txlen += 4 + m->m_next->m_len; + } + + } else { + /* Use PIO. */ + + if (m->m_next) { + iavc_put_byte(sc, SEND_DATA_B3_REQ); + NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d", sc->sc_unit, m->m_len); + } else { + iavc_put_byte(sc, SEND_MESSAGE); + NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d", sc->sc_unit, m->m_len); + } +#if 0 + { + u_int8_t *p = mtod(m, u_int8_t*); + int len; + for (len = 0; len < m->m_len; len++) { + printf(" %02x", *p++); + if (len && (len % 16) == 0) printf("\n"); + } + if (len % 16) printf("\n"); + } +#endif + + iavc_put_slice(sc, m->m_data, m->m_len); + + if (m->m_next) { + iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len); + } + } + + } else { + /* A board control message to be sent as is */ + + if (sc->sc_dma) { + bcopy(m->m_data + 2, &sc->sc_sendbuf[0], m->m_len - 2); + txlen = m->m_len - 2; + + } else { +#if 0 + { + u_int8_t *p = mtod(m, u_int8_t*) + 2; + int len; + printf("iavc%d: tx BDC msg, len = %d, msg =", sc->sc_unit, m->m_len-2); + for (len = 0; len < m->m_len-2; len++) { + printf(" %02x", *p++); + if (len && (len % 16) == 0) printf("\n"); + } + if (len % 16) printf("\n"); + } +#endif + + txlen = m->m_len - 2; + dmabuf = mtod(m, char*) + 2; + while(txlen--) + b1io_put_byte(sc, *dmabuf++); + } + } + + if (m->m_next) { + i4b_Bfreembuf(m->m_next); + m->m_next = NULL; + } + i4b_Dfreembuf(m); + + if (sc->sc_dma) { + /* Start transmitter */ + + txlen = (txlen + 3) & ~3; + AMCC_WRITE(sc, AMCC_TXPTR, vtophys(&sc->sc_sendbuf[0])); + AMCC_WRITE(sc, AMCC_TXLEN, txlen); + sc->sc_csr |= EN_TX_TC_INT; + + if (!sc->sc_intr) + AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr); + } +} + +#endif diff --git a/sys/i4b/capi/iavc/iavc_pci.c b/sys/i4b/capi/iavc/iavc_pci.c new file mode 100644 index 0000000..5579a3c --- /dev/null +++ b/sys/i4b/capi/iavc/iavc_pci.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * capi/iavc/iavc_pci.c + * The AVM ISDN controllers' PCI bus attachment handling. + * + * $FreeBSD$ + */ + +#include "iavc.h" +#include "i4bcapi.h" +#include "pci.h" + +#if (NIAVC > 0) && (NI4BCAPI > 0) && (NPCI > 0) + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +/* PCI device ids */ + +#define PCI_AVM_VID 0x1244 +#define PCI_AVMT1_DID 0x1200 +#define PCI_AVMB1_DID 0x0700 + +/* PCI driver linkage */ + +static void iavc_pci_intr(iavc_softc_t *sc); +static int iavc_pci_probe(device_t dev); +static int iavc_pci_attach(device_t dev); + +static device_method_t iavc_pci_methods[] = +{ + DEVMETHOD(device_probe, iavc_pci_probe), + DEVMETHOD(device_attach, iavc_pci_attach), + { 0, 0 } +}; + +static driver_t iavc_pci_driver = +{ + "iavc", + iavc_pci_methods, + 0 +}; + +static devclass_t iavc_pci_devclass; + +DRIVER_MODULE(iavc, pci, iavc_pci_driver, iavc_pci_devclass, 0, 0); + +/* Driver soft contexts */ + +iavc_softc_t iavc_sc[IAVC_MAXUNIT]; + +/*---------------------------------------------------------------------------* + * + *---------------------------------------------------------------------------*/ + +static int +iavc_pci_probe(device_t dev) +{ + u_int16_t did = pci_get_device(dev); + u_int16_t vid = pci_get_vendor(dev); + + if ((vid == PCI_AVM_VID) && (did == PCI_AVMT1_DID)) { + device_set_desc(dev, "AVM T1 PCI"); + } else if ((vid == PCI_AVM_VID) && (did == PCI_AVMB1_DID)) { + device_set_desc(dev, "AVM B1 PCI"); + } else { + return(ENXIO); + } + + return(0); +} + +/*---------------------------------------------------------------------------* + * + *---------------------------------------------------------------------------*/ + +static int +iavc_pci_attach(device_t dev) +{ + struct iavc_softc *sc; + void *ih = 0; + u_int16_t did = pci_get_device(dev); + int unit = device_get_unit(dev), ret; + + /* check max unit range */ + + if (unit >= IAVC_MAXUNIT) { + printf("iavc%d: too many units\n", unit); + return(ENXIO); + } + + sc = iavc_find_sc(unit); /* get softc */ + + sc->sc_unit = unit; + + /* use the i/o mapped base address */ + + sc->sc_resources.io_rid[0] = 0x14; + + if (!(sc->sc_resources.io_base[0] = + bus_alloc_resource(dev, SYS_RES_IOPORT, + &sc->sc_resources.io_rid[0], + 0UL, ~0UL, 1, RF_ACTIVE))) { + printf("iavc%d: can't allocate io region\n", unit); + return(ENXIO); + } + + sc->sc_iobase = rman_get_start(sc->sc_resources.io_base[0]); + sc->sc_io_bt = rman_get_bustag(sc->sc_resources.io_base[0]); + sc->sc_io_bh = rman_get_bushandle(sc->sc_resources.io_base[0]); + + /* use the memory mapped DMA controller */ + + sc->sc_resources.mem_rid = 0x10; + + if (!(sc->sc_resources.mem = + bus_alloc_resource(dev, SYS_RES_MEMORY, + &sc->sc_resources.mem_rid, + 0UL, ~0UL, 1, RF_ACTIVE))) { + printf("iavc%d: can't allocate memory region\n", unit); + return(ENXIO); + } + + sc->sc_membase = rman_get_start(sc->sc_resources.mem); + sc->sc_mem_bt = rman_get_bustag(sc->sc_resources.mem); + sc->sc_mem_bh = rman_get_bushandle(sc->sc_resources.mem); + + /* do some detection */ + + sc->sc_t1 = FALSE; + sc->sc_dma = FALSE; + b1dma_reset(sc); + + if (did == PCI_AVMT1_DID) { + sc->sc_capi.card_type = CARD_TYPEC_AVM_T1_PCI; + sc->sc_capi.sc_nbch = 30; + ret = t1_detect(sc); + if (ret) { + if (ret < 6) { + printf("iavc%d: no card detected?\n", sc->sc_unit); + } else { + printf("iavc%d: black box not on\n", sc->sc_unit); + } + return(ENXIO); + } else { + sc->sc_dma = TRUE; + sc->sc_t1 = TRUE; + } + + } else if (did == PCI_AVMB1_DID) { + sc->sc_capi.card_type = CARD_TYPEC_AVM_B1_PCI; + sc->sc_capi.sc_nbch = 2; + ret = b1dma_detect(sc); + if (ret) { + ret = b1_detect(sc); + if (ret) { + printf("iavc%d: no card detected?\n", sc->sc_unit); + return(ENXIO); + } + } else { + sc->sc_dma = TRUE; + } + } + + if (sc->sc_dma) b1dma_reset(sc); +#if 0 + if (sc->sc_t1) t1_reset(sc); + else b1_reset(sc); +#endif + + /* of course we need an interrupt */ + + sc->sc_resources.irq_rid = 0x00; + + if(!(sc->sc_resources.irq = + bus_alloc_resource(dev, SYS_RES_IRQ, + &sc->sc_resources.irq_rid, + 0UL, ~0UL, 1, RF_SHAREABLE|RF_ACTIVE))) { + printf("iavc%d: can't allocate irq\n",unit); + return(ENXIO); + } + + /* finalize our own context */ + + memset(&sc->sc_txq, 0, sizeof(struct ifqueue)); + sc->sc_txq.ifq_maxlen = sc->sc_capi.sc_nbch * 4; + +#if defined (__FreeBSD__) && __FreeBSD__ > 4 + mtx_init(&sc->sc_txq.ifq_mtx, "i4b_ivac_pci", MTX_DEF); +#endif + + sc->sc_intr = FALSE; + sc->sc_state = IAVC_DOWN; + sc->sc_blocked = FALSE; + + /* setup capi link */ + + sc->sc_capi.load = iavc_load; + sc->sc_capi.reg_appl = iavc_register; + sc->sc_capi.rel_appl = iavc_release; + sc->sc_capi.send = iavc_send; + sc->sc_capi.ctx = (void*) sc; + + if (capi_ll_attach(&sc->sc_capi)) { + printf("iavc%d: capi attach failed\n", unit); + return(ENXIO); + } + + /* setup the interrupt */ + + if(bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, + (void(*)(void*))iavc_pci_intr, + sc, &ih)) { + printf("iavc%d: irq setup failed\n", unit); + return(ENXIO); + } + + /* the board is now ready to be loaded */ + + return(0); +} + +/*---------------------------------------------------------------------------* + * IRQ handler + *---------------------------------------------------------------------------*/ + +static void +iavc_pci_intr(struct iavc_softc *sc) +{ + iavc_handle_intr(sc); +} + +#endif -- cgit v1.1