diff options
| author | martin <martin@NetBSD.org> | 2001-01-05 12:49:52 +0000 |
|---|---|---|
| committer | martin <martin@NetBSD.org> | 2001-01-05 12:49:52 +0000 |
| commit | c3cb638bcaf3ab422b9fbdaa4552afd21a817f40 (patch) | |
| tree | 739005e0a66c10d03cc90d4791b5e1597b016670 /sys/dev | |
| parent | f60c2ea4df70477bade4f1c69ac781c95f862a0c (diff) | |
Initial import of ISDN4BSD release 0.96
Diffstat (limited to 'sys/dev')
41 files changed, 17938 insertions, 0 deletions
diff --git a/sys/dev/ic/daic.c b/sys/dev/ic/daic.c new file mode 100644 index 00000000000..b6ecd0e7f27 --- /dev/null +++ b/sys/dev/ic/daic.c @@ -0,0 +1,1060 @@ +/* + * Copyright (c) 1997,1999,2001 Martin Husemann <martin@duskware.de> + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + */ + +/* + * Last Edit-Date: [Fri Jan 5 12:31:50 2001] + * + * daic.c: MI driver for Diehl active ISDN cards (S, SX, SXn, SCOM, QUADRO) + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/socket.h> +#include <net/if.h> + +#include <netisdn/i4b_ioctl.h> +#include <netisdn/i4b_l3l4.h> +#include <netisdn/i4b_isdnq931.h> +#include <netisdn/i4b_q931.h> +#include <netisdn/i4b_l3fsm.h> +#include <netisdn/i4b_l4.h> + +#include <machine/bus.h> +#include <dev/ic/daicvar.h> +#include <dev/ic/daicreg.h> +#include <dev/microcode/daic/dnload.h> + +#ifdef NetBSD1_3 +#if NetBSD1_3 < 2 +/* the device is MI, only the attach struct is in the bus + dependend frontend. And only on old versions... */ +struct cfdriver daic_cd = { + NULL, "daic", DV_DULL +}; +#endif +#endif + +/* local function prototypes */ +static char * cardtypename __P((int cardtype)); +static int daic_download __P((int unit, int portcount, struct isdn_dr_prot *data)); +static int daic_diagnostic __P((int unit, struct isdn_diagnostic_request *req)); +static void daic_connect_request(unsigned int); +static void daic_connect_response(unsigned int, int, int); +static void daic_disconnect_request(unsigned int, int); +static int daic_reset __P((bus_space_tag_t bus, bus_space_handle_t io, int port, int quiet)); +static int daic_handle_intr __P((struct daic *sc, int port)); +static int daic_register_port(struct daic *sc, int port); +static void daic_request(struct daic *sc, int port, u_int req, u_int id, bus_size_t parmsize, const u_int8_t *parms); +static u_int daic_assign(struct daic *sc, int port, u_int instance, bus_size_t parmsize, const u_int8_t *parms); +static void daic_indicate_ind(struct daic *sc, int port); +static void daic_bch_config(int unit, int channel, int bprot, int updown); +static void daic_bch_tx_start(int unit, int channel); +static void daic_set_linktab(int unit, int channel, drvr_link_t *dlt); +static isdn_link_t *daic_ret_linktab(int unit, int channel); + +#ifdef DAIC_DEBUG +static void daic_dump_request(struct daic *sc, int port, u_int req, u_int id, bus_size_t parmsize, u_int8_t *parms); +#endif + +/* static data */ +static char *cardnames[] = { + "S", "SX", "SCOM", "QUADRO" +}; + +static char *err_codes[DAIC_RC_ERRMASK+1] = { + "NO ERROR", + "UNKNOWN COMMAND", + "WRONG COMMAND", + "WRONG ID", + "WRONG CH", + "UNKNOWN IE", + "WRONG IE", + "OUT OF RESOURCES" +}; + +/* fixed parameters */ + +/* no parameters */ +static u_int8_t parm_none[] = { 0 }; +#define VOIDREQ(sc,port,req,id) daic_request(sc, port, req, id, sizeof parm_none, parm_none) + +/* assign request for the global d-channel instance */ +static u_int8_t parm_global_assign[] = { +/* BC len cap rate a-law */ + 0x04, 0x03, 0x80, 0x90, 0xa3, /* 64k speech */ + 0x04, 0x02, 0x88, 0x90, /* 64k data */ + 0x04, 0x03, 0x89, 0x90, 0xa3, /* restricted digital info */ + 0x04, 0x03, 0x90, 0x90, 0xa3, /* 3.1k speech */ +/* shift6 SIN len service */ + 0x96, 0x01, 0x02, 0x00, 0x00, /* any service */ +/* end of parms */ + 0x00 +}; + +/*---------------------------------------------------------------------------* + * structure mapping one isdn port (a 'unit') to an sc/port pair + *---------------------------------------------------------------------------*/ +struct daic_unit_map { + struct daic *sc; + int port; +}; +static struct daic_unit_map *unit_map = NULL; +static int next_unit = 0; + +/*---------------------------------------------------------------------------* + * Return the name of a card with given cardtype + *---------------------------------------------------------------------------*/ +static char * +cardtypename(cardtype) + int cardtype; +{ + if (cardtype >= 0 && cardtype < (sizeof(cardnames) / sizeof(cardnames[0]))) + return cardnames[cardtype]; + else + return "unknown type"; +} + +/*---------------------------------------------------------------------------* + * Probe for presence of device at given io space. + * Return: 0 no card identified + * 1 card found + *---------------------------------------------------------------------------*/ +int +daic_probe(bus, io) + bus_space_tag_t bus; + bus_space_handle_t io; +{ + return daic_reset(bus, io, 0, 1); +} + +/*---------------------------------------------------------------------------* + * Attach and initialize the card at given io space. + *---------------------------------------------------------------------------*/ +void +daic_attach(self, sc) + struct device *self; + struct daic *sc; +{ + int i, num_ports; + + num_ports = sc->sc_cardtype == DAIC_TYPE_QUAD ? 4 : 1; + + /* init sc */ + bzero(sc->sc_assign_res, sizeof sc->sc_assign_res); + bzero(sc->sc_assign, sizeof sc->sc_assign); + for (i = 0; i < num_ports; i++) { + sc->sc_state[i] = DAIC_STATE_COLD; + } + sc->sc_cardtype = -1; + + /* init card */ + sc->sc_cardtype = daic_reset(sc->sc_iot, sc->sc_ioh, 0, 0); + if (sc->sc_cardtype >= 0) + for (i = 0; i < num_ports; i++) + sc->sc_state[i] = DAIC_STATE_DOWNLOAD; + + /* register all ports this card has */ + for (i = 0; i < num_ports; i++) + daic_register_port(sc, i); +} + +/*---------------------------------------------------------------------------* + * handle interrupts for one port of the card + *---------------------------------------------------------------------------*/ +static int +daic_handle_intr(sc, port) + struct daic *sc; + int port; +{ + struct outcallentry *assoc; + int off = port * DAIC_ISA_MEMSIZE; + u_int8_t rc, rcid; + u_int8_t ind, indid; + int chan; + + /* check if we caused the interrupt */ + if (!bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_IRQ+off)) + return 0; /* nope, exit */ + + /* is the card in running state yet? */ + if (sc->sc_state[port] == DAIC_STATE_TESTING) { + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off, 0); + sc->sc_state[port] = DAIC_STATE_RUNNING; + wakeup(&sc->sc_state[port]); + goto done; + } + + /* what caused the interrupt? */ + /* (1) Check for a return code */ + rc = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off); + rcid = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RCID+off); + if (!rc) goto check_ind; + + /* maybe an assign answer (positive or negative) */ + if (rc == DAIC_RC_ASSIGN_OK) { + sc->sc_assign_res[port] = rcid; + /* assing rc is special, we tell the card it's done */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQ+off, 0); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off, 0); + /* we handle some types of assigns to global dchannel id's automaticaly */ + if (sc->sc_assign[port] & DAIC_ASSIGN_GLOBAL) { + sc->sc_global_dchan[port] = rcid; + sc->sc_assign[port] &= ~(DAIC_ASSIGN_GLOBAL|DAIC_ASSIGN_PENDING); + if (sc->sc_assign[port] & DAIC_ASSIGN_SLEEPING) { + sc->sc_assign[port] = 0; + wakeup(&sc->sc_assign_res[port]); + } + } else { + wakeup(&sc->sc_assign[port]); + } + goto check_ind; + } else if ((rc & DAIC_RC_ASSIGN_MASK) == DAIC_RC_ASSIGN_RC) { + printf("%s: assign request failed, error 0x%02x: %s\n", + sc->sc_dev.dv_xname, rc & DAIC_RC_ERRMASK, + err_codes[rc & DAIC_RC_ERRMASK]); + sc->sc_assign_res[port] = 0; + /* assing rc is special, we tell the card it's done */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQ+off, 0); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off, 0); + /* that's it */ + wakeup(&sc->sc_assign[port]); + goto check_ind; + } + if (rcid == sc->sc_global_dchan[port]) { + sc->sc_request_res[port] = rc; + wakeup(&sc->sc_request_res[port]); + goto req_done; + } + for (chan = 0; chan < 2; chan++) { + if (rcid == sc->sc_con[port*2+chan].dchan_inst) { + sc->sc_con[port*2+chan].dchan_rc = rc; + wakeup(&sc->sc_con[port*2+chan].dchan_rc); + goto req_done; + } else if (rcid == sc->sc_con[port*2+chan].bchan_inst) { + sc->sc_con[port*2+chan].bchan_rc = rc; + wakeup(&sc->sc_con[port*2+chan].bchan_rc); + goto req_done; + } + } + for (assoc = sc->sc_outcalls[port].tqh_first; assoc; assoc = assoc->queue.tqe_next) { + if (rcid == assoc->dchan_id) { + assoc->rc = rc; + wakeup(assoc); + goto req_done; + } + } + + /* not found? */ + printf("%s: unknown id 0x%02x got rc 0x%02x: %s\n", + sc->sc_dev.dv_xname, rcid, rc, + err_codes[rc & DAIC_RC_ERRMASK]); + +req_done: + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off, 0); + +check_ind: + /* (2) Check for an indication */ + ind = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_IND+off); + indid = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_INDID+off); + if (!ind) goto done; + + /* incoming call routed to global dchannel task? */ + if (indid == sc->sc_global_dchan[port]) { + if (ind == DAIC_IND_INDICATE) { + daic_indicate_ind(sc, port); + } else if (ind == DAIC_IND_INFO) { + int i; + + printf("%s: got info indication\n", + sc->sc_dev.dv_xname); + + for (i = 0; i < 48; i++) { + if (!(i % 16)) + printf("\n%02x:", i); + printf(" %02x", bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+off+i)); + } + printf("\n"); + } else if (ind == DAIC_IND_HANGUP) { + printf("%s: got global HANGUP indication\n", + sc->sc_dev.dv_xname); + } else { + printf("%s: unknown global indication: 0x%02x\n", + sc->sc_dev.dv_xname, ind); + } + goto ind_done; + } + + for (chan = 0; chan < 2; chan++) { + if (indid == sc->sc_con[port*2+chan].dchan_inst) { + printf("%s: D-Channel indication 0x%02x for channel %d\n", + sc->sc_dev.dv_xname, ind, chan); + goto ind_done; + } else if (indid == sc->sc_con[port*2+chan].bchan_inst) { + printf("%s: B-Channel indication 0x%02x for channel %d\n", + sc->sc_dev.dv_xname, ind, chan); + goto ind_done; + } + } + + for (assoc = sc->sc_outcalls[port].tqh_first; assoc; assoc = assoc->queue.tqe_next) { + if (indid == assoc->dchan_id) { + printf("%s: D-Channel indication 0x%02x for outgoing call with cdid %d\n", + sc->sc_dev.dv_xname, ind, assoc->cdid); + goto ind_done; + } + } + + /* not found - something's wrong! */ + printf("%s: got ind 0x%02x for id 0x%02x\n", sc->sc_dev.dv_xname, ind, indid); + +ind_done: + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_IND+off, 0); + +done: + /* tell card we're ready for more... */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_IRQ+off, 0); + + return 1; +} + +/*---------------------------------------------------------------------------* + * Handle interrupts + *---------------------------------------------------------------------------*/ +int +daic_intr(sc) + struct daic *sc; +{ + int handeld = 0; + if (sc->sc_cardtype == DAIC_TYPE_QUAD) { + int i; + for (i = 0; i < 4; i++) + handeld |= daic_handle_intr(sc, i); + } else + handeld = daic_handle_intr(sc, 0); + return handeld; +} + +/*---------------------------------------------------------------------------* + * Download primary protocol microcode to on-board processor + *---------------------------------------------------------------------------*/ +static int +daic_download(unit, count, data) + int unit, count; + struct isdn_dr_prot *data; +{ + struct daic *sc = unit_map[unit].sc; + int i; + + if (sc->sc_cardtype != DAIC_TYPE_QUAD) + count = 1; /* XXX - or signal error ? */ + + for (i = 0; i < count; i++) { + int off = DAIC_ISA_MEMSIZE * i; + u_int8_t *p = data[i].microcode; + size_t s = data[i].bytecount; + u_int32_t sw_id; + int cnt, x; + for (p = data[i].microcode+4, cnt = 0; *p && cnt < 70; p++, cnt++) + ; + sw_id = p[1] | (p[2] << 8) | (p[3] << 16) | (p[4] << 24); + if (sc->sc_cardtype == DAIC_TYPE_QUAD) + printf("%s port %d: downloading %s\n", + sc->sc_dev.dv_xname, i, data[i].microcode+4); + else + printf("%s: downloading %s\n", + sc->sc_dev.dv_xname, data[i].microcode+4); + x = splnet(); + p = data[i].microcode; + while (s > 0) { + size_t size = (s > 256) ? 256 : s; + bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_BUF+off, p, size); + p += size; + s -= size; + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_CTRL+off, 1); + splx(x); + for (cnt = 0; cnt < 2*hz; cnt++) { + x = splnet(); + if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_CTRL+off) == 0) + break; + splx(x); + tsleep(sc, 0, "daic download", 1); + } + if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_CTRL+off) != 0) { + splx(x); + printf("%s: download of microcode failed\n", + sc->sc_dev.dv_xname); + return EIO; + } + } + + /* configure microcode - no parameters yet - XXX */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_TEI+off, 0); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_NT2+off, 0); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_ZERO+off, 0); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_WATCHDOG+off, 0); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_PERMANENT+off, 0); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_XINTERFACE+off, 0); + + /* start protocol */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_CTRL+off, 2); + + /* wait for signature */ + for (cnt = 0; cnt < 2*hz; cnt++) { + u_int16_t signature; + signature = bus_space_read_2(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_SIGNATURE+off); + if (signature == DAIC_SIGNATURE_VALUE) + break; + if (signature) { + if (signature != DAIC_SIGNATURE_VALUE) { + splx(x); + printf("%s: microcode signature bad: should be %04x, is %04x\n", + sc->sc_dev.dv_xname, DAIC_SIGNATURE_VALUE,signature); + return EIO; + } + break; + } + splx(x); + tsleep(&sc->sc_state[i], 0, "daic protocol init", hz/25); + x = splnet(); + } + + /* real check: send an invalid request and wait for an interrupt */ + sc->sc_state[i] = DAIC_STATE_TESTING; + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off, 0); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQID+off, 0xff); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQ+off, 1); + splx(x); + tsleep(&sc->sc_state[i], 0, "daic irq test", 2*hz); + x = splnet(); + if (sc->sc_state[i] != DAIC_STATE_RUNNING) { + splx(x); + printf("%s: download interrupt test timeout\n", + sc->sc_dev.dv_xname); + return EIO; + } + + /* finish card configuration */ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, DAIC_SWID+off, sw_id); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_SET_CARD+off, sc->sc_cardtype); + splx(x); + + /* assign global d-channel id for that port */ + sc->sc_global_dchan[i] = + daic_assign(sc, i, DAIC_GLOBALID_DCHAN, + sizeof parm_global_assign, parm_global_assign); + + /* send an INDICATE request to get incoming calls on this id */ + x = splnet(); + VOIDREQ(sc, i, DAIC_REQ_INDICATE, sc->sc_global_dchan[i]); + splx(x); + tsleep(&sc->sc_request_res[i], 0, "daic request", 0); + x = splnet(); + if (sc->sc_request_res[i] != DAIC_RC_OK) { + printf("%s: INDICATE request error (0x%02x): %s\n", + sc->sc_dev.dv_xname, sc->sc_request_res[i], + err_codes[sc->sc_request_res[i] & DAIC_RC_ERRMASK]); + splx(x); + return EIO; + } + splx(x); + } + return 0; +} + +/*---------------------------------------------------------------------------* + * Reset the card, download primary bootstrap, let it check the + * card and return the cardtype identified by the microcode + * or -1 if no known card is detected. + *---------------------------------------------------------------------------*/ +static int +daic_reset(bus, io, port, quiet) + bus_space_tag_t bus; + bus_space_handle_t io; + int port, quiet; +{ + int memsize = 0, cardtype = -1; + int i, off = port * DAIC_ISA_MEMSIZE; + + /* clear any pending interrupt */ + bus_space_read_1(bus, io, DAIC_IRQ+off); + /* reset card */ + bus_space_write_1(bus, io, DAIC_BOOT_SET_RESET+off, 0); + + /* download primary bootstrap */ + bus_space_set_region_1(bus, io, DAIC_BOOT_START+off, 0, DAIC_BOOT_CODE-DAIC_BOOT_START); + bus_space_write_region_1(bus, io, DAIC_BOOT_CODE+off, dnload, DAIC_BOOT_END-DAIC_BOOT_CODE+1); + if (bus_space_read_1(bus, io, DAIC_BOOT_CTRL+off) + || bus_space_read_1(bus, io, DAIC_BOOT_EBIT+off)) { + if (!quiet) printf(": shared memory test failed!\n"); + return -1; + } + /* let card perform memory test */ + bus_space_write_1(bus, io, DAIC_BOOT_CTRL+off, DAIC_TEST_MEM); + /* and off we go... */ + bus_space_write_1(bus, io, DAIC_BOOT_CLR_RESET+off, 0); + /* wait for response from bootstrap */ + for (i = 0; i < 15000 && bus_space_read_1(bus, io, DAIC_BOOT_CTRL+off) != DAIC_TEST_RDY; i++) + DELAY(100); + if (i >= 15000) { + if (!quiet) printf(": on board processor test failed!\n"); + return -1; + } + if (bus_space_read_1(bus, io, DAIC_BOOT_EBIT+off)) { + if (!quiet) printf(": on board memory test failed at %p\n", + (void*)bus_space_read_2(bus, io, DAIC_BOOT_ELOC+off)); + return -1; + } + + /* fetch info from primary bootstrap code */ + cardtype = bus_space_read_1(bus, io, DAIC_BOOT_CARD+off); + memsize = bus_space_read_1(bus, io, DAIC_BOOT_MSIZE+off); + + /* done, output info */ + if (!quiet) printf(": EICON.Diehl-%s (%d kB RAM)\n", cardtypename(cardtype), memsize << 4); + + return cardtype; +} + +/*---------------------------------------------------------------------------* + * Generic diagnostic interface - pass through the microcode data + * without knowing too much about it. This passes a lot work to + * userland, but hey, this is only a diagnostic tool... + *---------------------------------------------------------------------------*/ +static int +daic_diagnostic(unit, req) + int unit; + struct isdn_diagnostic_request *req; +{ + struct daic *sc = unit_map[unit].sc; + int port = unit_map[unit].port; + int off = port * DAIC_ISA_MEMSIZE; + int rc, cnt; + int s, err = 0; + + /* validate parameters */ + if (req->cmd < 0 || req->cmd > DAIC_DIAG_MAXCMD) { + printf("%s: daic_diagnostic: illegal cmd %d\n", + sc->sc_dev.dv_xname, req->cmd); + return EIO; + } + if (req->out_param_len > (DAIC_DIAG_DATA_SIZE+1)) { + printf("%s: daic_diagnostic: illegal out_param_len %d\n", + sc->sc_dev.dv_xname, req->out_param_len); + return EIO; + } + + /* XXX - only for debug */ + if (req->cmd == 0x05) { + /* pass through request from userland */ + + u_int8_t id; + static u_int8_t parms[] = { + IEI_CALLID, 0x01, 0x81, + IEI_CALLINGPN, 7, NUMBER_TYPEPLAN, '9', '8', '9', '0', '2', '0', + 0x96, 0x01, 0x02, 0x01, 0x00, + 0x00 + }; + + /* create the d-channel task for this call */ + printf("%s: assigning id for pass-through call\n", sc->sc_dev.dv_xname); + id = daic_assign(sc, port, DAIC_GLOBALID_DCHAN, sizeof(parms), parms); + printf("%s: got id 0x%02x\n", sc->sc_dev.dv_xname, id); + +#ifdef DAIC_DEBUG + daic_dump_request(sc, port, DAIC_REQ_CALL, id, req->in_param_len, req->in_param); +#endif + daic_request(sc, port, DAIC_REQ_CALL, id, req->in_param_len, req->in_param); + return 0; + } + + /* all these need an output parameter */ + if (req->out_param == NULL) + return EIO; + + /* check state and switch to DIAGNOSTIC */ + s = splnet(); + if (sc->sc_state[port] != DAIC_STATE_RUNNING) { + splx(s); + return EWOULDBLOCK; + } + sc->sc_state[port] = DAIC_STATE_DIAGNOSTIC; + splx(s); + + /* set new request */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_REQ+off, req->cmd); + + /* sorry, no interrupt on completition - have to poll */ + for (cnt = 0; cnt < 3*hz; cnt++) { + if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_REQ+off) == 0 + && bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_RC+off) != 0) + break; + tsleep(sc, 0, "daic diagnostic", 1); + } + rc = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_RC+off); + if (rc == 0) { + /* stop request and return error */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_REQ+off, 0); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_RC+off, 0); + err = EIO; + goto done; + } + /* out param gets rc and all the data */ + if (req->out_param_len >= 2) { + ((u_int8_t*)(req->out_param))[0] = (u_int8_t)rc; + bus_space_read_region_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_DATA+off, ((u_int8_t*)req->out_param)+1, req->out_param_len-1); + } + /* acknowledge data */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_RC+off, 0); + +done: /* back to normal state */ + s = splnet(); + sc->sc_state[port] = DAIC_STATE_RUNNING; + splx(s); + + return err; +} + +/*---------------------------------------------------------------------------* + * Register one port and attach it to the upper layers + *---------------------------------------------------------------------------*/ +static int +daic_register_port(struct daic *sc, int port) +{ + int chan; + int unit = next_unit++; + + /* make sure this hardware driver type is known to layer 4 */ + ctrl_types[CTRL_DAIC].set_linktab = daic_set_linktab; + ctrl_types[CTRL_DAIC].get_linktab = daic_ret_linktab; + + /* attach a new unit */ + if (unit_map) { + struct daic_unit_map *temp = malloc(next_unit*sizeof(struct daic_unit_map), 0, M_DEVBUF); + bcopy(unit_map, temp, unit*sizeof(struct daic_unit_map)); + free(unit_map, M_DEVBUF); + unit_map = temp; + } else { + unit_map = malloc(sizeof(struct daic_unit_map), 0, M_DEVBUF); + next_unit = 0; + } + next_unit++; + unit_map[unit].sc = sc; + unit_map[unit].port = port; + + /* setup function pointers */ + ctrl_desc[nctrl].N_CONNECT_REQUEST = daic_connect_request; + ctrl_desc[nctrl].N_CONNECT_RESPONSE = daic_connect_response; + ctrl_desc[nctrl].N_DISCONNECT_REQUEST = daic_disconnect_request; + ctrl_desc[nctrl].N_DOWNLOAD = daic_download; + ctrl_desc[nctrl].N_DIAGNOSTICS = daic_diagnostic; + + /* init type and unit */ + ctrl_desc[nctrl].unit = unit; + ctrl_desc[nctrl].ctrl_type = CTRL_DAIC; + ctrl_desc[nctrl].card_type = sc->sc_cardtype + 1; + + /* state fields */ + ctrl_desc[nctrl].dl_est = DL_DOWN; + ctrl_desc[nctrl].bch_state[0] = BCH_ST_FREE; + ctrl_desc[nctrl].bch_state[1] = BCH_ST_FREE; + sc->sc_ctrl[port] = nctrl++; + + /* initialize linktabs for this port */ + for (chan = 0; chan < 2; chan++) { + isdn_link_t *lt = &sc->sc_con[port*2+chan].isdn_linktab; + lt->unit = unit; + lt->channel = chan; + lt->bch_config = daic_bch_config; + lt->bch_tx_start = daic_bch_tx_start; + lt->tx_queue = &sc->sc_con[port*2+chan].tx_queue; + lt->rx_queue = &sc->sc_con[port*2+chan].rx_queue; + } + TAILQ_INIT(&sc->sc_outcalls[port]); + + return unit; +} + +/*---------------------------------------------------------------------------* + * return the address of daic drivers linktab + *---------------------------------------------------------------------------*/ +static isdn_link_t * +daic_ret_linktab(int unit, int channel) +{ + struct daic *sc = unit_map[unit].sc; + int port = unit_map[unit].port; + struct daic_connection *con = &sc->sc_con[port*2+channel]; + + return(&con->isdn_linktab); +} + +/*---------------------------------------------------------------------------* + * set the driver linktab in the b channel softc + *---------------------------------------------------------------------------*/ +static void +daic_set_linktab(int unit, int channel, drvr_link_t *dlt) +{ + struct daic *sc = unit_map[unit].sc; + int port = unit_map[unit].port; + struct daic_connection *con = &sc->sc_con[port*2+channel]; + + con->drvr_linktab = dlt; +} + +/*---------------------------------------------------------------------------* + * Send a request to the card. + *---------------------------------------------------------------------------*/ +static void +daic_request( + struct daic *sc, /* ourself */ + int port, /* and the port on this card */ + u_int req, /* the request to send */ + u_int id, /* id of communication task */ + bus_size_t parmsize, /* size of parms including the terminating zero */ + const u_int8_t *parms) /* pointer to parms to pass */ +{ + int off = port*DAIC_ISA_MEMSIZE; + + /* spin while card is yet busy */ + while (bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQ)) + ; /* unlikely to happen with this driver */ + + /* output parameters */ + bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_XBUFFER+off, parms, parmsize); + + /* output request and id */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQID+off, id); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQ+off, req); +} + +/*---------------------------------------------------------------------------* + * Assign a unique instance id for some communication class + * on the card. Only one assign request may be running on a + * port at any time, handle this and return the instance id. + *---------------------------------------------------------------------------*/ +static u_int +daic_assign( + struct daic *sc, /* our state and port no */ + int port, + u_int classid, /* Diehl calls this "global instance id" */ + bus_size_t parmsize, /* sizeof paramter arra */ + const u_int8_t *parms) /* task instance parameters */ +{ + static char wchan[] = "daic assign"; + u_int8_t id; + int x; + + /* there only may be one assignment running concurrently */ + x = splnet(); + for (;;) { + if (!(sc->sc_assign[port] & DAIC_ASSIGN_PENDING)) + break; /* we got it! */ + + /* somebody else is assigning, record state and sleep */ + sc->sc_assign[port] |= DAIC_ASSIGN_SLEEPING; + tsleep(&sc->sc_assign_res[port], 0, wchan, 0); + } + + /* put parameters and request to card */ + sc->sc_assign[port] |= DAIC_ASSIGN_PENDING; + daic_request(sc, port, DAIC_REQ_ASSIGN, classid, parmsize, parms); + + /* wait for completition of assignment by the card */ + tsleep(&sc->sc_assign[port], 0, wchan, 0); + id = sc->sc_assign_res[port]; + + /* have we lost our global dchannel id in the meantime? */ + if (sc->sc_assign[port] & DAIC_ASSIGN_NOGLOBAL) { + /* start an assign request and let the result + be handled by the interrupt handler - we don't + have to wait for it here. As the assign lock + isn't freed, we don't wake up others... */ + sc->sc_assign[port] &= ~DAIC_ASSIGN_NOGLOBAL; + sc->sc_assign[port] |= DAIC_ASSIGN_PENDING|DAIC_ASSIGN_GLOBAL; + daic_request(sc, port, DAIC_REQ_ASSIGN, DAIC_GLOBALID_DCHAN, + sizeof parm_global_assign, parm_global_assign); + splx(x); + return id; + } + + /* XXX - review this, can't remember why I did it this complicated */ + + /* unlock and wakup others, if any */ + if (sc->sc_assign[port] & DAIC_ASSIGN_SLEEPING) { + sc->sc_assign[port] = 0; + wakeup(&sc->sc_assign_res[port]); + } else + sc->sc_assign[port] = 0; + splx(x); + + return id; +} + +#ifdef DAIC_DEBUG +/*---------------------------------------------------------------------------* + * Debug output of request parameters + *---------------------------------------------------------------------------*/ +static void +daic_dump_request(struct daic *sc, int port, u_int req, u_int id, bus_size_t parmsize, u_int8_t *parms) +{ + int i; + printf("%s: request 0x%02x to task id 0x%02x:", + sc->sc_dev.dv_xname, req, id); + for (i = 0; i < parmsize; i++) { + if (i % 16 == 0) + printf("\n%02x:", i); + printf(" %02x", parms[i]); + } + printf("\n"); +} +#endif + +/*---------------------------------------------------------------------------* + * Decode parameters of an INDICATE indication from the card + * and pass them to layer 4. Called from within an interrupt + * context. + *---------------------------------------------------------------------------*/ +static void +daic_indicate_ind(struct daic *sc, int port) +{ + int offset = port*DAIC_ISA_MEMSIZE; + int i; + u_int8_t ie, ielen; + call_desc_t *cd; + + /* get and init new calldescriptor */ + cd = reserve_cd(); /* cdid filled in */ + cd->controller = sc->sc_ctrl[port]; + cd->bprot = BPROT_NONE; + cd->cause_in = 0; + cd->cause_out = 0; + cd->dst_telno[0] = '\0'; + cd->src_telno[0] = '\0'; + cd->channelid = CHAN_NO; + cd->channelexcl = 0; + cd->cr = -1; + cd->crflag = CRF_DEST; + cd->ilt = NULL; /* reset link tab ptrs */ + cd->dlt = NULL; + + i = 0; + for (;;) { + ie = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+offset+i); + if (!ie) break; + i++; + if (ie & 0x80) continue; + ielen = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+offset+i); + i++; + switch (ie) { + case IEI_BEARERCAP: + ie = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+offset+i); + if (ie == 0x80 || ie == 0x89 || ie == 0x90) + cd->bprot = BPROT_NONE; + else if (ie == 0x88) + cd->bprot = BPROT_RHDLC; + break; + case IEI_CALLINGPN: + { + int off; + ie = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+offset+i); + if (ie & 0x80) + off = 1; + else + off = 2; + bus_space_read_region_1(sc->sc_iot, sc->sc_ioh, + DAIC_COM_RBUFFER+offset+i+off, cd->src_telno, + ielen - off); + cd->src_telno[ielen-off+1] = '\0'; + } + break; + case IEI_CALLEDPN: + bus_space_read_region_1(sc->sc_iot, sc->sc_ioh, + DAIC_COM_RBUFFER+offset+i+1, + cd->dst_telno, ielen-1); + cd->dst_telno[ielen] = '\0'; + break; + case IEI_CHANNELID: + ie = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+offset+i); + if ((ie & 0xf4) != 0x80) + cd->channelid = CHAN_NO; + else { + switch(ie & 0x03) { + case IE_CHAN_ID_NO: cd->channelid = CHAN_NO; break; + case IE_CHAN_ID_B1: cd->channelid = CHAN_B1; break; + case IE_CHAN_ID_B2: cd->channelid = CHAN_B2; break; + case IE_CHAN_ID_ANY: cd->channelid = CHAN_ANY; break; + } + cd->channelexcl = (ie & 0x08) >> 3; + } + } + i += ielen; + } + cd->event = EV_SETUP; + ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_RSVD; + + /* record the dchannel id for this call and the call descriptor */ + sc->sc_con[port*2+cd->channelid].dchan_inst = sc->sc_global_dchan[port]; + sc->sc_con[port*2+cd->channelid].cdid = cd->cdid; + + /* this task is busy now, we need a new global dchan id */ + if (sc->sc_assign[port] & DAIC_ASSIGN_PENDING) { + /* argh - can't assign right now */ + sc->sc_assign[port] |= DAIC_ASSIGN_NOGLOBAL; + } else { + /* yeah - can request the assign right away, but let the + interrupt handler autohandle the result */ + sc->sc_assign[port] |= DAIC_ASSIGN_PENDING|DAIC_ASSIGN_GLOBAL; + daic_request(sc, port, DAIC_REQ_ASSIGN, DAIC_GLOBALID_DCHAN, + sizeof parm_global_assign, parm_global_assign); + } + + if (cd->bprot == BPROT_NONE) + printf("\nincoming voice call from \"%s\" to \"%s\"\n", + cd->src_telno, cd->dst_telno); + else + printf("\nincoming data call from \"%s\" to \"%s\"\n", + cd->src_telno, cd->dst_telno); + + /* hand up call to layer 4 */ + i4b_l4_connect_ind(cd); +} + +/*---------------------------------------------------------------------------* + * Layer 4 request a call setup + *---------------------------------------------------------------------------*/ +static void +daic_connect_request(unsigned int cdid) +{ + u_int8_t id, cpn[TELNO_MAX+4], parms[TELNO_MAX+16], *p; + call_desc_t *cd = cd_by_cdid(cdid); + struct daic *sc = unit_map[cd->driver_unit].sc; + int port = unit_map[cd->driver_unit].port; + int x, len; + struct outcallentry *assoc; + + /* to associate the cdid with the communication task + we are going to create for this outgoing call, + we maintain a queue of pending outgoing calls. + As soon as a SETUP response is received, we move + the association to the allocated b-channel. */ + + /* configure d-channel task parameters */ + p = parms; + *p++ = IEI_CALLID; *p++ = 0x01; + if (cd->bprot == BPROT_NONE) { + *p++ = 0x82; + } else if (cd->bprot == BPROT_RHDLC) { + *p++ = 0x85; + } else { + printf("%s: daic_connect_request for unknown bchan protocol 0x%x\n", + sc->sc_dev.dv_xname, cd->bprot); + return; + } + if (cd->src_telno[0]) { + *p++ = IEI_CALLINGPN; + *p++ = strlen(cd->src_telno)+1; + *p++ = NUMBER_TYPEPLAN; + strcpy(p, cd->src_telno); + p += strlen(p); + } + if (cd->channelid == CHAN_B1 || cd->channelid == CHAN_B2) { + *p++ = IEI_CHANNELID; + *p++ = 0x01; + *p++ = 0x81 + cd->channelid; + } + if (cd->bprot == BPROT_NONE) { + *p++ = 0x96; /* shift6 */ + *p++ = 0x01; /* SIN */ + *p++ = 0x02; /* len */ + *p++ = 0x01; /* Telephony */ + *p++ = 0x00; /* add.info */ + } + *p++ = 0; + + /* create the d-channel task for this call */ + id = daic_assign(sc, port, DAIC_GLOBALID_DCHAN, p - parms, parms); + + /* map it to the call descriptor id */ + assoc = malloc(sizeof(struct outcallentry), 0, M_DEVBUF); + assoc->cdid = cdid; + assoc->dchan_id = id; + x = splnet(); + TAILQ_INSERT_TAIL(&sc->sc_outcalls[port], assoc, queue); + + /* send a call request */ + len = strlen(cd->dst_telno); + cpn[0] = IEI_CALLEDPN; + cpn[1] = len+1; + cpn[2] = NUMBER_TYPEPLAN; + strcpy(cpn+3, cd->dst_telno); +#ifdef DAIC_DEBUG + daic_dump_request(sc, port, DAIC_REQ_CALL, id, len+4, cpn); +#endif + daic_request(sc, port, DAIC_REQ_CALL, id, len+4, cpn); + splx(x); + tsleep(assoc, 0, "daic call", 0); + if (assoc->rc != DAIC_RC_OK) { + printf("%s: call request failed, error 0x%02x: %s\n", + sc->sc_dev.dv_xname, assoc->rc & DAIC_RC_ERRMASK, + err_codes[assoc->rc & DAIC_RC_ERRMASK]); + } +} + +/*---------------------------------------------------------------------------* + * TODO: + *---------------------------------------------------------------------------*/ +static void daic_connect_response(unsigned int cdid, int response, int cause) +{ +} + +/*---------------------------------------------------------------------------* + * TODO: + *---------------------------------------------------------------------------*/ +static void daic_disconnect_request(unsigned int cdid, int cause) +{ +} + +/*---------------------------------------------------------------------------* + * TODO: + *---------------------------------------------------------------------------*/ +static void daic_bch_config(int unit, int channel, int bprot, int updown) +{ + printf("daic: bch_config\n"); +} + +/*---------------------------------------------------------------------------* + * TODO: + *---------------------------------------------------------------------------*/ +static void daic_bch_tx_start(int unit, int channel) +{ + printf("daic: bch_tx_start\n"); +} + diff --git a/sys/dev/ic/daicreg.h b/sys/dev/ic/daicreg.h new file mode 100644 index 00000000000..613567eefa0 --- /dev/null +++ b/sys/dev/ic/daicreg.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1997,2001 Martin Husemann <martin@duskware.de> + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + */ + +/* + * Shared memory definitions for Diehl activ isdn adapters. + */ + +/* + * Values after reset, before isdn support is downloaded + */ +#define DAIC_BOOT_CTRL 0 /* byte */ +#define DAIC_BOOT_CARD 1 /* byte */ +#define DAIC_BOOT_MSIZE 2 /* byte */ +#define DAIC_BOOT_EBIT 4 /* 2 byte */ +#define DAIC_BOOT_ELOC 6 /* 4 byte */ +#define DAIC_BOOT_SIGNATURE 30 /* 2 byte */ +#define DAIC_BOOT_BUF 256 /* 256 bytes */ + +#define DAIC_SERNO 1008 +#define DAIC_SWID 1016 +#define DAIC_DOSIO 0x3e8 +#define DAIC_MEMFREE 0x3f4 +#define DAIC_SET_CARD 0x3fc +#define DAIC_IRQ 0x3fe + +#define DAIC_BOOT_START 0 +#define DAIC_BOOT_CODE 0x200 +#define DAIC_BOOT_END 0x3ff +#define DAIC_BOOT_SET_RESET 0x400 /* byte */ +#define DAIC_BOOT_CLR_RESET 0x401 /* byte */ + +/* + * Parameters for the microcode + */ +#define DAIC_BOOT_TEI 8 +#define DAIC_BOOT_NT2 9 +#define DAIC_BOOT_ZERO 10 +#define DAIC_BOOT_WATCHDOG 11 +#define DAIC_BOOT_PERMANENT 12 +#define DAIC_BOOT_XINTERFACE 13 + +/* + * Response from microcode + */ +#define DAIC_SIGNATURE_VALUE 0x4447 + +/* + * Diagnostic interface + */ +#define DAIC_DIAG_REQ 0x380 /* byte */ +#define DAIC_DIAG_RC 0x381 /* byte */ +#define DAIC_DIAG_MEM 0x382 /* 4 byte */ +#define DAIC_DIAG_LENGTH 0x386 /* 2 byte */ +#define DAIC_DIAG_PORT 0x388 /* 2 byte */ +#define DAIC_DIAG_DATA 0x390 /* 48 byte */ +#define DAIC_DIAG_DATA_SIZE 48 +#define DAIC_DIAG_MAXCMD 14 + +/* + * Values after download, with software running on card + */ +#define DAIC_COM_REQ 0 /* byte */ +#define DAIC_COM_REQID 1 /* byte */ +#define DAIC_COM_RC 2 /* byte */ +#define DAIC_COM_RCID 3 /* byte */ +#define DAIC_COM_IND 4 /* byte */ +#define DAIC_COM_INDID 5 /* byte */ +#define DAIC_COM_IMASK 6 /* byte */ +#define DAIC_COM_RNR 7 /* byte */ +#define DAIC_COM_XLOCK 8 /* byte */ +#define DAIC_COM_INTERRUPT 9 /* byte */ +#define DAIC_COM_REQCH 10 /* byte */ +#define DAIC_COM_RCCH 11 /* byte */ +#define DAIC_COM_INDCH 12 /* byte */ +#define DAIC_COM_MIND 13 /* byte */ +#define DAIC_COM_MLENGTH 14 /* 2 byte */ +#define DAIC_COM_SIGNATURE 30 /* 2 byte */ +#define DAIC_COM_XBUFFER 32 /* 272 byte */ +#define DAIC_COM_RBUFFER 304 /* 272 byte */ + +/* + * Diagnostic commands/results + */ +#define DAIC_TEST_RDY 0 +#define DAIC_TEST_MEM 1 +#define DAIC_TEST_SKIP 2 +#define DAIC_TEST_BUSY 3 + +/* + * ID's of global instances on the card + */ +#define DAIC_GLOBALID_DCHAN 0 +#define DAIC_GLOBALID_ISO3 0x20 +#define DAIC_GLOBALID_ISO2 0x60 +#define DAIC_GLOBALID_TASKS 0x80 +#define DAIC_GLOBALID_TIMER 0xa0 +#define DAIC_GLOBALID_PHONE 0xc0 + +/* + * REQUEST codes + */ +#define DAIC_REQ_ASSIGN 0x01 +#define DAIC_REQ_INDICATE 0x0a +#define DAIC_REQ_CALL 0x01 + +/* + * INDICATION codes + */ +#define DAIC_IND_HANGUP 0x03 +#define DAIC_IND_INDICATE 0x0a +#define DAIC_IND_INFO 0x0d + +/* + * return codes + */ +#define DAIC_RC_UNKNOWN_COMMAND 0x01 +#define DAIC_RC_WRONG_COMMAND 0x02 +#define DAIC_RC_WRONG_ID 0x03 +#define DAIC_RC_WRONG_CH 0x04 +#define DAIC_RC_UNKNOWN_IE 0x05 +#define DAIC_RC_WRONG_IE 0x06 +#define DAIC_RC_OUT_OF_RESRCS 0x07 +#define DAIC_RC_ASSIGN_RC 0xe0 +#define DAIC_RC_ASSIGN_MASK 0xf0 +#define DAIC_RC_ERRMASK 0x0f +#define DAIC_RC_ASSIGN_OK 0xef +#define DAIC_RC_TIMER_INT 0xfe +#define DAIC_RC_OK 0xff diff --git a/sys/dev/ic/daicvar.h b/sys/dev/ic/daicvar.h new file mode 100644 index 00000000000..fcb35e64fe7 --- /dev/null +++ b/sys/dev/ic/daicvar.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1997,2001 Martin Husemann <martin@duskware.de> + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + */ + +#ifndef DIEHLISDNVAR +#define DIEHLISDNVAR +#if defined(KERNEL) || defined(_KERNEL) + +#define DAIC_MAX_PORT 4 +#define DAIC_ISA_MEMSIZE 2048 +#define DAIC_ISA_QUADSIZE (DAIC_MAX_PORT*DAIC_ISA_MEMSIZE) +#define DAIC_MAX_ACTIVE (2*DAIC_MAX_PORT) /* simlutaneous connections on one instance */ + +/* A queue of pending outgoing calls */ +struct outcallentry { + TAILQ_ENTRY(outcallentry) queue; + unsigned int cdid; /* call descriptor id for layer 4 */ + u_int8_t dchan_id; /* task id for microcode */ + u_int8_t rc; /* return code */ +}; + +/* One active connection */ +struct daic_connection { + u_int cdid; /* layer 4 call descriptor id */ + struct ifqueue tx_queue; /* outgoing data */ + struct ifqueue rx_queue; /* incoming data */ + isdn_link_t isdn_linktab; /* description of ourself */ + drvr_link_t *drvr_linktab; /* application driver using us */ + u_int8_t dchan_inst; /* d-channel instance */ + u_int8_t dchan_rc; /* return code for dchannel requests */ + u_int8_t bchan_inst; /* b-channel instance */ + u_int8_t bchan_rc; /* return code for bchannel requests */ +}; + +/* superclass of all softc structs for attachments, you should + * always be able to cast an attachments struct device *self to this. */ +struct daic { + struct device sc_dev; + bus_space_tag_t sc_iot; /* bus identifier */ + bus_space_handle_t sc_ioh; /* mem handle */ + int sc_cardtype; /* variant of card */ +#define DAIC_TYPE_S 0 +#define DAIC_TYPE_SX 1 +#define DAIC_TYPE_SCOM 2 +#define DAIC_TYPE_QUAD 3 + + int sc_ctrl[DAIC_MAX_PORT]; /* upper layer controller number */ + + int sc_state[DAIC_MAX_PORT]; /* state of board, see below */ +#define DAIC_STATE_COLD 0 /* nothing happened to the board */ +#define DAIC_STATE_DOWNLOAD 1 /* the card is waiting for protocol code */ +#define DAIC_STATE_TESTING 2 /* waiting for first interrupt from card */ +#define DAIC_STATE_RUNNING 3 /* the protocol is running */ +#define DAIC_STATE_DIAGNOSTIC 4 /* temporary disabled for diagnostics */ + + int sc_assign[DAIC_MAX_PORT]; /* allocating new protocol instance */ +#define DAIC_ASSIGN_PENDING 1 /* we are awaiting a new ID */ +#define DAIC_ASSIGN_SLEEPING 2 /* somebody sleeping, wakeup after we got the ID */ +#define DAIC_ASSIGN_GLOBAL 4 /* result is a global d-channel id */ +#define DAIC_ASSIGN_NOGLOBAL 8 /* need to assign a global d-channel id */ + + u_int8_t sc_global_dchan[DAIC_MAX_PORT]; /* handle of global dchannel instance */ + u_int8_t sc_request_res[DAIC_MAX_PORT]; /* result of requests */ + u_int8_t sc_assign_res[DAIC_MAX_PORT]; /* result of assigns */ + + /* one record for each b-channel we could handle concurrently */ + struct daic_connection sc_con[DAIC_MAX_ACTIVE]; + /* a tailq of ougoing calls no yet assigned to any b-channel */ + TAILQ_HEAD(outcallhead, outcallentry) sc_outcalls[DAIC_MAX_PORT]; +}; + +/* + * functions exported from MI part + */ +extern int daic_probe __P((bus_space_tag_t bus, bus_space_handle_t io)); +extern void daic_attach __P((struct device *self, struct daic *sc)); +extern int daic_intr __P((struct daic *)); + +#endif +#endif diff --git a/sys/dev/ic/i4b_hscx.c b/sys/dev/ic/i4b_hscx.c new file mode 100644 index 00000000000..04d1961d868 --- /dev/null +++ b/sys/dev/ic/i4b_hscx.c @@ -0,0 +1,679 @@ +/* + * Copyright (c) 1997, 2000 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. + * + *--------------------------------------------------------------------------- + * + * i4b - Siemens HSCX chip (B-channel) handling + * -------------------------------------------- + * + * $Id: i4b_hscx.c,v 1.1.1.1 2001/01/05 12:50:10 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:36:10 2001] + * + *---------------------------------------------------------------------------*/ + +#include <sys/param.h> +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <machine/stdarg.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#ifndef __bsdi__ +#include <machine/bus.h> +#endif +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#include <netisdn/i4b_trace.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_mbuf.h> + +/*---------------------------------------------------------------------------* + * HSCX IRQ Handler + *---------------------------------------------------------------------------*/ +void +isic_hscx_irq(register struct l1_softc *sc, u_char ista, int h_chan, u_char ex_irq) +{ + register l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + u_char exir = 0; + int activity = -1; + u_char cmd = 0; + + NDBGL1(L1_H_IRQ, "%#x", ista); + + if(ex_irq) + { + /* get channel extended irq reg */ + + exir = HSCX_READ(h_chan, H_EXIR); + + if(exir & HSCX_EXIR_RFO) + { + chan->stat_RFO++; + NDBGL1(L1_H_XFRERR, "ex_irq: receive data overflow"); + } + + if((exir & HSCX_EXIR_XDU) && (chan->bprot != BPROT_NONE))/* xmit data underrun */ + { + chan->stat_XDU++; + NDBGL1(L1_H_XFRERR, "ex_irq: xmit data underrun"); + isic_hscx_cmd(sc, h_chan, HSCX_CMDR_XRES); + + if (chan->out_mbuf_head != NULL) /* don't continue to transmit this buffer */ + { + i4b_Bfreembuf(chan->out_mbuf_head); + chan->out_mbuf_cur = chan->out_mbuf_head = NULL; + } + } + + } + + /* rx message end, end of frame */ + + if(ista & HSCX_ISTA_RME) + { + register int fifo_data_len; + u_char rsta; + int error = 0; + + rsta = HSCX_READ(h_chan, H_RSTA); + + if((rsta & 0xf0) != 0xa0) + { + if((rsta & HSCX_RSTA_VFR) == 0) + { + chan->stat_VFR++; + cmd |= (HSCX_CMDR_RHR); + NDBGL1(L1_H_XFRERR, "received invalid Frame"); + error++; + } + + if(rsta & HSCX_RSTA_RDO) + { + chan->stat_RDO++; + NDBGL1(L1_H_XFRERR, "receive data overflow"); + error++; + } + + if((rsta & HSCX_RSTA_CRC) == 0) + { + chan->stat_CRC++; + cmd |= (HSCX_CMDR_RHR); + NDBGL1(L1_H_XFRERR, "CRC check failed"); + error++; + } + + if(rsta & HSCX_RSTA_RAB) + { + chan->stat_RAB++; + NDBGL1(L1_H_XFRERR, "Receive message aborted"); + error++; + } + } + + fifo_data_len = ((HSCX_READ(h_chan, H_RBCL)) & + ((sc->sc_bfifolen)-1)); + + if(fifo_data_len == 0) + fifo_data_len = sc->sc_bfifolen; + + /* all error conditions checked, now decide and take action */ + + if(error == 0) + { + if(chan->in_mbuf == NULL) + { + if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL) + panic("L1 isic_hscx_irq: RME, cannot allocate mbuf!\n"); + chan->in_cbptr = chan->in_mbuf->m_data; + chan->in_len = 0; + } + + fifo_data_len -= 1; /* last byte in fifo is RSTA ! */ + + if((chan->in_len + fifo_data_len) <= BCH_MAX_DATALEN) + { + /* read data from HSCX fifo */ + + HSCX_RDFIFO(h_chan, chan->in_cbptr, fifo_data_len); + + cmd |= (HSCX_CMDR_RMC); + isic_hscx_cmd(sc, h_chan, cmd); + cmd = 0; + + chan->in_len += fifo_data_len; + chan->rxcount += fifo_data_len; + + /* setup mbuf data length */ + + chan->in_mbuf->m_len = chan->in_len; + chan->in_mbuf->m_pkthdr.len = chan->in_len; + + if(sc->sc_trace & TRACE_B_RX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); + } + + (*chan->drvr_linktab->bch_rx_data_ready)(chan->drvr_linktab->unit); + + activity = ACT_RX; + + /* mark buffer ptr as unused */ + + chan->in_mbuf = NULL; + chan->in_cbptr = NULL; + chan->in_len = 0; + } + else + { + NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RME, in_len=%d, fifolen=%d", chan->in_len, fifo_data_len); + chan->in_cbptr = chan->in_mbuf->m_data; + chan->in_len = 0; + cmd |= (HSCX_CMDR_RHR | HSCX_CMDR_RMC); + } + } + else + { + if (chan->in_mbuf != NULL) + { + i4b_Bfreembuf(chan->in_mbuf); + chan->in_mbuf = NULL; + chan->in_cbptr = NULL; + chan->in_len = 0; + } + cmd |= (HSCX_CMDR_RMC); + } + } + + /* rx fifo full */ + + if(ista & HSCX_ISTA_RPF) + { + if(chan->in_mbuf == NULL) + { + if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL) + panic("L1 isic_hscx_irq: RPF, cannot allocate mbuf!\n"); + chan->in_cbptr = chan->in_mbuf->m_data; + chan->in_len = 0; + } + + chan->rxcount += sc->sc_bfifolen; + + if((chan->in_len + sc->sc_bfifolen) <= BCH_MAX_DATALEN) + { + /* read data from HSCX fifo */ + + HSCX_RDFIFO(h_chan, chan->in_cbptr, sc->sc_bfifolen); + + chan->in_cbptr += sc->sc_bfifolen; + chan->in_len += sc->sc_bfifolen; + } + else + { + if(chan->bprot == BPROT_NONE) + { + /* setup mbuf data length */ + + chan->in_mbuf->m_len = chan->in_len; + chan->in_mbuf->m_pkthdr.len = chan->in_len; + + if(sc->sc_trace & TRACE_B_RX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); + } + + /* silence detection */ + + if(!(isic_hscx_silence(chan->in_mbuf->m_data, chan->in_mbuf->m_len))) + activity = ACT_RX; + + if(!(IF_QFULL(&chan->rx_queue))) + { + IF_ENQUEUE(&chan->rx_queue, chan->in_mbuf); + } + else + { + i4b_Bfreembuf(chan->in_mbuf); + } + + /* signal upper driver that data is available */ + + (*chan->drvr_linktab->bch_rx_data_ready)(chan->drvr_linktab->unit); + + /* alloc new buffer */ + + if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL) + panic("L1 isic_hscx_irq: RPF, cannot allocate new mbuf!\n"); + + /* setup new data ptr */ + + chan->in_cbptr = chan->in_mbuf->m_data; + + /* read data from HSCX fifo */ + + HSCX_RDFIFO(h_chan, chan->in_cbptr, sc->sc_bfifolen); + + chan->in_cbptr += sc->sc_bfifolen; + chan->in_len = sc->sc_bfifolen; + + chan->rxcount += sc->sc_bfifolen; + } + else + { + NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RPF, in_len=%d", chan->in_len); + chan->in_cbptr = chan->in_mbuf->m_data; + chan->in_len = 0; + cmd |= (HSCX_CMDR_RHR); + } + } + + /* command to release fifo space */ + + cmd |= HSCX_CMDR_RMC; + } + + /* transmit fifo empty, new data can be written to fifo */ + + if(ista & HSCX_ISTA_XPR) + { + /* + * for a description what is going on here, please have + * a look at isic_bchannel_start() in i4b_bchan.c ! + */ + + int activity = -1; + int len; + int nextlen; + + NDBGL1(L1_H_IRQ, "unit %d, chan %d - XPR, Tx Fifo Empty!", sc->sc_unit, h_chan); + + if(chan->out_mbuf_cur == NULL) /* last frame is transmitted */ + { + IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head); + + if(chan->out_mbuf_head == NULL) + { + chan->state &= ~HSCX_TX_ACTIVE; + (*chan->drvr_linktab->bch_tx_queue_empty)(chan->drvr_linktab->unit); + } + else + { + chan->state |= HSCX_TX_ACTIVE; + chan->out_mbuf_cur = chan->out_mbuf_head; + chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; + chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; + + if(sc->sc_trace & TRACE_B_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); + } + + if(chan->bprot == BPROT_NONE) + { + if(!(isic_hscx_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len))) + activity = ACT_TX; + } + else + { + activity = ACT_TX; + } + } + } + + len = 0; + + while(chan->out_mbuf_cur && len != sc->sc_bfifolen) + { + nextlen = min(chan->out_mbuf_cur_len, sc->sc_bfifolen - len); + +#ifdef NOTDEF + printf("i:mh=%x, mc=%x, mcp=%x, mcl=%d l=%d nl=%d # ", + chan->out_mbuf_head, + chan->out_mbuf_cur, + chan->out_mbuf_cur_ptr, + chan->out_mbuf_cur_len, + len, + next_len); +#endif + + isic_hscx_waitxfw(sc, h_chan); /* necessary !!! */ + + HSCX_WRFIFO(h_chan, chan->out_mbuf_cur_ptr, nextlen); + cmd |= HSCX_CMDR_XTF; + + len += nextlen; + chan->txcount += nextlen; + + chan->out_mbuf_cur_ptr += nextlen; + chan->out_mbuf_cur_len -= nextlen; + + if(chan->out_mbuf_cur_len == 0) + { + if((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL) + { + chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; + chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; + + if(sc->sc_trace & TRACE_B_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); + } + } + else + { + if (chan->bprot != BPROT_NONE) + cmd |= HSCX_CMDR_XME; + i4b_Bfreembuf(chan->out_mbuf_head); + chan->out_mbuf_head = NULL; + } + + } + } + } + + if(cmd) /* is there a command for the HSCX ? */ + { + isic_hscx_cmd(sc, h_chan, cmd); /* yes, to HSCX */ + } + + /* call timeout handling routine */ + + if(activity == ACT_RX || activity == ACT_TX) + (*chan->drvr_linktab->bch_activity)(chan->drvr_linktab->unit, activity); +} + +/*---------------------------------------------------------------------------* + * HSCX initialization + * + * for telephony: extended transparent mode 1 + * for raw hdlc: transparent mode 0 + *---------------------------------------------------------------------------*/ +void +isic_hscx_init(struct l1_softc *sc, int h_chan, int activate) +{ + l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + + HSCX_WRITE(h_chan, H_MASK, 0xff); /* mask irq's */ + + if(sc->sc_ipac) + { + /* CCR1: Power Up, Clock Mode 5 */ + HSCX_WRITE(h_chan, H_CCR1, HSCX_CCR1_PU | /* power up */ + HSCX_CCR1_CM1); /* IPAC clock mode 5 */ + } + else + { + /* CCR1: Power Up, Clock Mode 5 */ + HSCX_WRITE(h_chan, H_CCR1, HSCX_CCR1_PU | /* power up */ + HSCX_CCR1_CM2 | /* HSCX clock mode 5 */ + HSCX_CCR1_CM0); + } + + /* XAD1: Transmit Address Byte 1 */ + HSCX_WRITE(h_chan, H_XAD1, 0xff); + + /* XAD2: Transmit Address Byte 2 */ + HSCX_WRITE(h_chan, H_XAD2, 0xff); + + /* RAH2: Receive Address Byte High Reg. 2 */ + HSCX_WRITE(h_chan, H_RAH2, 0xff); + + /* XBCH: reset Transmit Byte Count High */ + HSCX_WRITE(h_chan, H_XBCH, 0x00); + + /* RLCR: reset Receive Length Check Register */ + HSCX_WRITE(h_chan, H_RLCR, 0x00); + + /* CCR2: set tx/rx clock shift bit 0 */ + /* disable CTS irq, disable RIE irq*/ + HSCX_WRITE(h_chan, H_CCR2, HSCX_CCR2_XCS0|HSCX_CCR2_RCS0); + + /* XCCR: tx bit count per time slot */ + HSCX_WRITE(h_chan, H_XCCR, 0x07); + + /* RCCR: rx bit count per time slot */ + HSCX_WRITE(h_chan, H_RCCR, 0x07); + + if(sc->sc_bustyp == BUS_TYPE_IOM2) + { + switch(h_chan) + { + case HSCX_CH_A: /* Prepare HSCX channel A */ + /* TSAX: tx clock shift bits 1 & 2 */ + /* tx time slot number */ + HSCX_WRITE(h_chan, H_TSAX, 0x2f); + + /* TSAR: rx clock shift bits 1 & 2 */ + /* rx time slot number */ + HSCX_WRITE(h_chan, H_TSAR, 0x2f); + break; + + case HSCX_CH_B: /* Prepare HSCX channel B */ + /* TSAX: tx clock shift bits 1 & 2 */ + /* tx time slot number */ + HSCX_WRITE(h_chan, H_TSAX, 0x03); + + /* TSAR: rx clock shift bits 1 & 2 */ + /* rx time slot number */ + HSCX_WRITE(h_chan, H_TSAR, 0x03); + break; + } + } + else /* IOM 1 setup */ + { + /* TSAX: tx clock shift bits 1 & 2 */ + /* tx time slot number */ + HSCX_WRITE(h_chan, H_TSAX, 0x07); + + /* TSAR: rx clock shift bits 1 & 2 */ + /* rx time slot number */ + HSCX_WRITE(h_chan, H_TSAR, 0x07); + } + + if(activate) + { + if(chan->bprot == BPROT_RHDLC) + { + /* HDLC Frames, transparent mode 0 */ + HSCX_WRITE(h_chan, H_MODE, + HSCX_MODE_MDS1|HSCX_MODE_RAC|HSCX_MODE_RTS); + } + else + { + /* Raw Telephony, extended transparent mode 1 */ + HSCX_WRITE(h_chan, H_MODE, + HSCX_MODE_MDS1|HSCX_MODE_MDS0|HSCX_MODE_ADM|HSCX_MODE_RTS); + } + + isic_hscx_cmd(sc, h_chan, HSCX_CMDR_RHR|HSCX_CMDR_XRES); + } + else + { + /* TSAX: tx time slot */ + HSCX_WRITE(h_chan, H_TSAX, 0xff); + + /* TSAR: rx time slot */ + HSCX_WRITE(h_chan, H_TSAR, 0xff); + + /* Raw Telephony, extended transparent mode 1 */ + HSCX_WRITE(h_chan, H_MODE, + HSCX_MODE_MDS1|HSCX_MODE_MDS0|HSCX_MODE_ADM|HSCX_MODE_RTS); + } + + /* don't touch ICA, EXA and EXB bits, this could be HSCX_CH_B */ + /* always disable RSC and TIN */ + + chan->hscx_mask |= HSCX_MASK_RSC | HSCX_MASK_TIN; + + if(activate) + { + /* enable */ + chan->hscx_mask &= ~(HSCX_MASK_RME | HSCX_MASK_RPF | HSCX_MASK_XPR); + } + else + { + /* disable */ + chan->hscx_mask |= HSCX_MASK_RME | HSCX_MASK_RPF | HSCX_MASK_XPR; + } + + /* handle ICA, EXA, and EXB via interrupt mask of channel b */ + + if (h_chan == HSCX_CH_A) + { + if (activate) + HSCX_B_IMASK &= ~(HSCX_MASK_EXA | HSCX_MASK_ICA); + else + HSCX_B_IMASK |= HSCX_MASK_EXA | HSCX_MASK_ICA; + HSCX_WRITE(HSCX_CH_A, H_MASK, HSCX_A_IMASK); + HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK); + } + else + { + if (activate) + HSCX_B_IMASK &= ~HSCX_MASK_EXB; + else + HSCX_B_IMASK |= HSCX_MASK_EXB; + HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK); + } + + /* clear spurious interrupts left over */ + + if(h_chan == HSCX_CH_A) + { + HSCX_READ(h_chan, H_EXIR); + HSCX_READ(h_chan, H_ISTA); + } + else /* mask ICA, because it must not be cleared by reading ISTA */ + { + HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK | HSCX_MASK_ICA); + HSCX_READ(h_chan, H_EXIR); + HSCX_READ(h_chan, H_ISTA); + HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK); + } +} + +/*---------------------------------------------------------------------------* + * write command to HSCX command register + *---------------------------------------------------------------------------*/ +void +isic_hscx_cmd(struct l1_softc *sc, int h_chan, unsigned char cmd) +{ + int timeout = 20; + + while(((HSCX_READ(h_chan, H_STAR)) & HSCX_STAR_CEC) && timeout) + { + DELAY(10); + timeout--; + } + + if(timeout == 0) + { + NDBGL1(L1_H_ERR, "HSCX wait for CEC timeout!"); + } + + HSCX_WRITE(h_chan, H_CMDR, cmd); +} + +/*---------------------------------------------------------------------------* + * wait for HSCX transmit FIFO write enable + *---------------------------------------------------------------------------*/ +void +isic_hscx_waitxfw(struct l1_softc *sc, int h_chan) +{ +#define WAITVAL 50 +#define WAITTO 200 + + int timeout = WAITTO; + + while((!(((HSCX_READ(h_chan, H_STAR)) & + (HSCX_STAR_CEC | HSCX_STAR_XFW)) == HSCX_STAR_XFW)) && timeout) + { + DELAY(WAITVAL); + timeout--; + } + + if(timeout == 0) + { + NDBGL1(L1_H_ERR, "HSCX wait for XFW timeout!"); + } + else if (timeout != WAITTO) + { + NDBGL1(L1_H_XFRERR, "HSCX wait for XFW time: %d uS", (WAITTO-timeout)*50); + } +} + diff --git a/sys/dev/ic/i4b_hscx.h b/sys/dev/ic/i4b_hscx.h new file mode 100644 index 00000000000..241316a3d1d --- /dev/null +++ b/sys/dev/ic/i4b_hscx.h @@ -0,0 +1,301 @@ +/* + * Copyright (c) 1996, 1998 Gary Jennejohn. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * $Id: i4b_hscx.h,v 1.1.1.1 2001/01/05 12:50:10 martin Exp $ + * + * last edit-date: [Sun Feb 14 10:26:56 1999] + * + * -hm added AVM config register defs + * -hm split up for rewrite of Siemens chipset driver + * + *--------------------------------------------------------------------------- + */ + +#ifndef I4B_HSCX_H_ +#define I4B_HSCX_H_ + +enum HSCX_VERSIONS { + HSCX_VA1, /* 82525 A1 */ + HSCX_UNKN1, /* unknown 1 */ + HSCX_VA2, /* 82525 A2 */ + HSCX_UNKN3, /* unknown 3 */ + HSCX_VA3, /* 82525 A3 */ + HSCX_V21, /* 82525 2.1 */ + HSCX_UNKN /* unknown version */ +}; + +#define HSCX_CH_A 0 /* channel A */ +#define HSCX_CH_B 1 /* channel B */ + +#define HSCX_FIFO_LEN 32 /* 32 bytes FIFO on chip */ + +/* + * definitions of registers and bits for the HSCX ISDN chip. + */ + +typedef struct hscx_reg { + + /* 32 byte deep FIFO always first */ + + unsigned char hscx_fifo [HSCX_FIFO_LEN]; + + /* most registers can be read/written, but have different names */ + /* so define a union with read/write names to make that clear */ + + union { + struct { + unsigned char hscx_ista; + unsigned char hscx_star; + unsigned char hscx_mode; + unsigned char hscx_timr; + unsigned char hscx_exir; + unsigned char hscx_rbcl; + unsigned char dummy_26; + unsigned char hscx_rsta; + unsigned char hscx_ral1; + unsigned char hscx_rhcr; + unsigned char dummy_2a; + unsigned char dummy_2b; + unsigned char hscx_ccr2; + unsigned char hscx_rbch; + unsigned char hscx_vstr; + unsigned char hscx_ccr; + unsigned char dummy_30; + unsigned char dummy_31; + unsigned char dummy_32; + unsigned char dummy_33; + } hscx_r; + struct { + unsigned char hscx_mask; + unsigned char hscx_cmdr; + unsigned char hscx_mode; + unsigned char hscx_timr; + unsigned char hscx_xad1; + unsigned char hscx_xad2; + unsigned char hscx_rah1; + unsigned char hscx_rah2; + unsigned char hscx_ral1; + unsigned char hscx_ral2; + unsigned char hscx_xbcl; + unsigned char hscx_bgr; + unsigned char hscx_ccr2; + unsigned char hscx_xbch; + unsigned char hscx_rlcr; + unsigned char hscx_ccr1; + unsigned char hscx_tsax; + unsigned char hscx_tsar; + unsigned char hscx_xccr; + unsigned char hscx_rccr; + } hscx_w; + } hscx_rw; +} hscx_reg_t; + +#define REG_OFFSET(type, field) (int)(&(((type *)0)->field)) + +/* HSCX read registers */ + +#define h_ista hscx_rw.hscx_r.hscx_ista +#define H_ISTA REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_ista) +#define h_star hscx_rw.hscx_r.hscx_star +#define H_STAR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_star) +#define h_mode hscx_rw.hscx_r.hscx_mode +#define H_MODE REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_mode) +#define h_timr hscx_rw.hscx_r.hscx_timr +#define H_TIMR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_timr) +#define h_exir hscx_rw.hscx_r.hscx_exir +#define H_EXIR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_exir) +#define h_rbcl hscx_rw.hscx_r.hscx_rbcl +#define H_RBCL REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_rbcl) +#define h_rsta hscx_rw.hscx_r.hscx_rsta +#define H_RSTA REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_rsta) +#define h_ral1 hscx_rw.hscx_r.hscx_ral1 +#define H_RAL1 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_ral1) +#define h_rhcr hscx_rw.hscx_r.hscx_rhcr +#define H_RHCR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_rhcr) +#define h_ccr2 hscx_rw.hscx_r.hscx_ccr2 +#define H_CCR2 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_ccr2) +#define h_rbch hscx_rw.hscx_r.hscx_rbch +#define H_RBCH REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_rbch) +#define h_vstr hscx_rw.hscx_r.hscx_vstr +#define H_VSTR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_vstr) +#define h_ccr hscx_rw.hscx_r.hscx_ccr +#define H_CCR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_ccr) + +/* HSCX write registers - for hscx_mode, hscx_timr, hscx_ral1, hscx_ccr2 */ +/* see read registers */ + +#define h_mask hscx_rw.hscx_w.hscx_mask +#define H_MASK REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_mask) +#define h_cmdr hscx_rw.hscx_w.hscx_cmdr +#define H_CMDR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_cmdr) +#define h_xad1 hscx_rw.hscx_w.hscx_xad1 +#define H_XAD1 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_xad1) +#define h_xad2 hscx_rw.hscx_w.hscx_xad2 +#define H_XAD2 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_xad2) +#define h_rah1 hscx_rw.hscx_w.hscx_rah1 +#define H_RAH1 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_rah1) +#define h_rah2 hscx_rw.hscx_w.hscx_rah2 +#define H_RAH2 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_rah2) +#define h_ral2 hscx_rw.hscx_w.hscx_ral2 +#define H_RAL2 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_ral2) +#define h_xbcl hscx_rw.hscx_w.hscx_xbcl +#define H_XBCL REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_xbcl) +#define h_bgr hscx_rw.hscx_w.hscx_bgr +#define H_BGR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_bgr) +#define h_xbch hscx_rw.hscx_w.hscx_xbch +#define H_XBCH REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_xbch) +#define h_rlcr hscx_rw.hscx_w.hscx_rlcr +#define H_RLCR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_rlcr) +#define h_ccr1 hscx_rw.hscx_w.hscx_ccr1 +#define H_CCR1 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_ccr1) +#define h_tsax hscx_rw.hscx_w.hscx_tsax +#define H_TSAX REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_tsax) +#define h_tsar hscx_rw.hscx_w.hscx_tsar +#define H_TSAR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_tsar) +#define h_xccr hscx_rw.hscx_w.hscx_xccr +#define H_XCCR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_xccr) +#define h_rccr hscx_rw.hscx_w.hscx_rccr +#define H_RCCR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_rccr) + +#define HSCX_ISTA_RME 0x80 +#define HSCX_ISTA_RPF 0x40 +#define HSCX_ISTA_RSC 0x20 +#define HSCX_ISTA_XPR 0x10 +#define HSCX_ISTA_TIN 0x08 +#define HSCX_ISTA_ICA 0x04 +#define HSCX_ISTA_EXA 0x02 +#define HSCX_ISTA_EXB 0x01 + +#define HSCX_MASK_RME 0x80 +#define HSCX_MASK_RPF 0x40 +#define HSCX_MASK_RSC 0x20 +#define HSCX_MASK_XPR 0x10 +#define HSCX_MASK_TIN 0x08 +#define HSCX_MASK_ICA 0x04 +#define HSCX_MASK_EXA 0x02 +#define HSCX_MASK_EXB 0x01 + +#define HSCX_EXIR_XMR 0x80 +#define HSCX_EXIR_XDU 0x40 +#define HSCX_EXIR_PCE 0x20 +#define HSCX_EXIR_RFO 0x10 +#define HSCX_EXIR_CSC 0x08 +#define HSCX_EXIR_RFS 0x04 + +/* the other bits are always 0 */ + +#define HSCX_STAR_XDOV 0x80 +#define HSCX_STAR_XFW 0x40 +#define HSCX_STAR_XRNR 0x20 +#define HSCX_STAR_RRNR 0x10 +#define HSCX_STAR_RLI 0x08 +#define HSCX_STAR_CEC 0x04 +#define HSCX_STAR_CTS 0x02 +#define HSCX_STAR_WFA 0x01 + +#define HSCX_CMDR_RMC 0x80 +#define HSCX_CMDR_RHR 0x40 +/* also known as XREP in transparent mode */ +#define HSCX_CMDR_RNR 0x20 +#define HSCX_CMDR_STI 0x10 +#define HSCX_CMDR_XTF 0x08 +#define HSCX_CMDR_XIF 0x04 +#define HSCX_CMDR_XME 0x02 +#define HSCX_CMDR_XRES 0x01 + +#define HSCX_MODE_MDS1 0x80 +#define HSCX_MODE_MDS0 0x40 +#define HSCX_MODE_ADM 0x20 +#define HSCX_MODE_TMD 0x10 +#define HSCX_MODE_RAC 0x08 +#define HSCX_MODE_RTS 0x04 +#define HSCX_MODE_TRS 0x02 +#define HSCX_MODE_TLP 0x01 + +#define HSCX_RSTA_VFR 0x80 +#define HSCX_RSTA_RDO 0x40 +#define HSCX_RSTA_CRC 0x20 +#define HSCX_RSTA_RAB 0x10 +#define HSCX_RSTA_HA1 0x08 +#define HSCX_RSTA_HA0 0x04 +#define HSCX_RSTA_CR 0x02 +#define HSCX_RSTA_LA 0x01 + +#define HSCX_RSTA_MASK 0xf0 /* the interesting ones */ + +/* only used in DMA mode */ +#define HSCX_XBCH_DMA 0x80 +#define HSCX_XBCH_NRM 0x40 +#define HSCX_XBCH_CAS 0x20 +#define HSCX_XBCH_XC 0x10 +/* the rest are bits 11 thru 8 of the byte count */ + +#define HSCX_RBCH_DMA 0x80 +#define HSCX_RBCH_NRM 0x40 +#define HSCX_RBCH_CAS 0x20 +#define HSCX_RBCH_OV 0x10 +/* the rest are bits 11 thru 8 of the byte count */ + +#define HSCX_VSTR_CD 0x80 +/* bits 6 thru 4 are 0 */ +/* bits 3 thru 0 are the version number */ + +#define HSCX_RLCR_RC 0x80 +/* the rest of the bits are used to set the received length */ + +#define HSCX_CCR1_PU 0x80 +/* bits 6 and 5 are SC1 SC0 */ +#define HSCX_CCR1_ODS 0x10 +#define HSCX_CCR1_ITF 0x08 +#define HSCX_CCR1_CM2 0x04 +#define HSCX_CCR1_CM1 0x02 +#define HSCX_CCR1_CM0 0x01 + +/* for clock mode 5 */ +#define HSCX_CCR2_SOC2 0x80 +#define HSCX_CCR2_SOC1 0x40 +#define HSCX_CCR2_XCS0 0x20 +#define HSCX_CCR2_RCS0 0x10 +#define HSCX_CCR2_TIO 0x08 +#define HSCX_CCR2_CIE 0x04 +#define HSCX_CCR2_RIE 0x02 +#define HSCX_CCR2_DIV 0x01 + +/* bits 7 thru 2 are TSNX */ +#define HSCX_TSAX_XCS2 0x02 +#define HSCX_TSAX_XCS1 0x01 + +/* bits 7 thru 2 are TSNR */ +#define HSCX_TSAR_RCS2 0x02 +#define HSCX_TSAR_RCS1 0x01 + +#endif /* I4B_HSCX_H_ */ diff --git a/sys/dev/ic/i4b_ipac.h b/sys/dev/ic/i4b_ipac.h new file mode 100644 index 00000000000..2588d2c0d0f --- /dev/null +++ b/sys/dev/ic/i4b_ipac.h @@ -0,0 +1,204 @@ +/* + * Copyright (c) 1997, 2000 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. + * + *--------------------------------------------------------------------------- + * + * i4b_ipac.h - definitions for the Siemens IPAC PSB2115 chip + * ========================================================== + * + * $Id: i4b_ipac.h,v 1.1.1.1 2001/01/05 12:50:10 martin Exp $ + * + * last edit-date: [Thu Jan 6 14:54:19 2000] + * + *--------------------------------------------------------------------------- + */ + +#ifndef _I4B_IPAC_H_ +#define _I4B_IPAC_H_ + +#define IPAC_BFIFO_LEN 64 /* 64 bytes B-channel FIFO on chip */ + +#define IPAC_HSCXA_OFF 0x00 +#define IPAC_HSCXB_OFF 0x40 +#define IPAC_ISAC_OFF 0x80 +#define IPAC_IPAC_OFF 0xc0 + +/* chip version */ + +#define IPAC_V11 0x01 /* IPAC Version 1.1 */ +#define IPAC_V12 0x02 /* IPAC Version 1.2 */ + +/* + * definitions of registers and bits for the IPAC ISDN chip. + */ + +typedef struct ipac_reg { + + /* most registers can be read/written, but have different names */ + /* so define a union with read/write names to make that clear */ + + union { + struct { + unsigned char ipac_conf; + unsigned char ipac_ista; + unsigned char ipac_id; + unsigned char ipac_acfg; + unsigned char ipac_aoe; + unsigned char ipac_arx; + unsigned char ipac_pita1; + unsigned char ipac_pita2; + unsigned char ipac_pota1; + unsigned char ipac_pota2; + unsigned char ipac_pcfg; + unsigned char ipac_scfg; + unsigned char ipac_timr2; + } ipac_r; + struct { + unsigned char ipac_conf; + unsigned char ipac_mask; + unsigned char ipac_dummy; + unsigned char ipac_acfg; + unsigned char ipac_aoe; + unsigned char ipac_atx; + unsigned char ipac_pita1; + unsigned char ipac_pita2; + unsigned char ipac_pota1; + unsigned char ipac_pota2; + unsigned char ipac_pcfg; + unsigned char ipac_scfg; + unsigned char ipac_timr2; + } ipac_w; + } ipac_rw; +} ipac_reg_t; + +#define REG_OFFSET(type, field) (int)(&(((type *)0)->field)) + +/* IPAC read registers */ + +#define IPAC_CONF REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_conf) +#define IPAC_ISTA REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_ista) +#define IPAC_ID REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_id) +#define IPAC_ACFG REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_acfg) +#define IPAC_AOE REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_aoe) +#define IPAC_ARX REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_arx) +#define IPAC_PITA1 REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_pita1) +#define IPAC_PITA2 REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_pita2) +#define IPAC_POTA1 REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_pota1) +#define IPAC_POTA2 REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_pota2) +#define IPAC_PCFG REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_pcfg) +#define IPAC_SCFG REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_scfg) +#define IPAC_TIMR2 REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_timr2) + +/* IPAC write registers */ + +#define IPAC_MASK REG_OFFSET(ipac_reg_t, ipac_rw.ipac_w.ipac_mask) +#define IPAC_ATX REG_OFFSET(ipac_reg_t, ipac_rw.ipac_w.ipac_atx) + +/* register bits */ + +#define IPAC_CONF_AMP 0x80 +#define IPAC_CONF_CFS 0x40 +#define IPAC_CONF_TEM 0x20 +#define IPAC_CONF_PDS 0x10 +#define IPAC_CONF_IDH 0x08 +#define IPAC_CONF_SGO 0x04 +#define IPAC_CONF_ODS 0x02 +#define IPAC_CONF_IOF 0x01 + +#define IPAC_ISTA_INT1 0x80 +#define IPAC_ISTA_INT0 0x40 +#define IPAC_ISTA_ICD 0x20 +#define IPAC_ISTA_EXD 0x10 +#define IPAC_ISTA_ICA 0x08 +#define IPAC_ISTA_EXA 0x04 +#define IPAC_ISTA_ICB 0x02 +#define IPAC_ISTA_EXB 0x01 + +#define IPAC_MASK_INT1 0x80 +#define IPAC_MASK_INT0 0x40 +#define IPAC_MASK_ICD 0x20 +#define IPAC_MASK_EXD 0x10 +#define IPAC_MASK_ICA 0x08 +#define IPAC_MASK_EXA 0x04 +#define IPAC_MASK_ICB 0x02 +#define IPAC_MASK_EXB 0x01 + +#define IPAC_ACFG_OD7 0x80 +#define IPAC_ACFG_OD6 0x40 +#define IPAC_ACFG_OD5 0x20 +#define IPAC_ACFG_OD4 0x10 +#define IPAC_ACFG_OD3 0x08 +#define IPAC_ACFG_OD2 0x04 +#define IPAC_ACFG_EL1 0x02 +#define IPAC_ACFG_EL2 0x01 + +#define IPAC_AOE_OE7 0x80 +#define IPAC_AOE_OE6 0x40 +#define IPAC_AOE_OE5 0x20 +#define IPAC_AOE_OE4 0x10 +#define IPAC_AOE_OE3 0x08 +#define IPAC_AOE_OE2 0x04 + +#define IPAC_ARX_AR7 0x80 +#define IPAC_ARX_AR6 0x40 +#define IPAC_ARX_AR5 0x20 +#define IPAC_ARX_AR4 0x10 +#define IPAC_ARX_AR3 0x08 +#define IPAC_ARX_AR2 0x04 + +#define IPAC_ATX_AT7 0x80 +#define IPAC_ATX_AT6 0x40 +#define IPAC_ATX_AT5 0x20 +#define IPAC_ATX_AT4 0x10 +#define IPAC_ATX_AT3 0x08 +#define IPAC_ATX_AT2 0x04 + +#define IPAC_PITA1_ENA 0x80 +#define IPAC_PITA1_DUDD 0x40 + +#define IPAC_PITA2_ENA 0x80 +#define IPAC_PITA2_DUDD 0x40 + +#define IPAC_POTA1_ENA 0x80 +#define IPAC_POTA1_DUDD 0x40 + +#define IPAC_POTA2_ENA 0x80 +#define IPAC_POTA2_DUDD 0x40 + +#define IPAC_PCFG_DPS 0x80 +#define IPAC_PCFG_ACL 0x40 +#define IPAC_PCFG_LED 0x20 +#define IPAC_PCFG_PLD 0x10 +#define IPAC_PCFG_FBS 0x08 +#define IPAC_PCFG_CSL2 0x04 +#define IPAC_PCFG_CSL1 0x02 +#define IPAC_PCFG_CSL0 0x01 + +#define IPAC_SCFG_PRI 0x80 +#define IPAC_SCFG_TXD 0x40 +#define IPAC_SCFG_TLEN 0x20 + +#define IPAC_TIMR2_TMD 0x80 + +#endif /* _I4B_IPAC_H_ */ diff --git a/sys/dev/ic/i4b_isac.c b/sys/dev/ic/i4b_isac.c new file mode 100644 index 00000000000..8e1ce794957 --- /dev/null +++ b/sys/dev/ic/i4b_isac.c @@ -0,0 +1,683 @@ +/* + * Copyright (c) 1997, 2000 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. + * + *--------------------------------------------------------------------------- + * + * i4b_isac.c - i4b siemens isdn chipset driver ISAC handler + * --------------------------------------------------------- + * + * $Id: i4b_isac.c,v 1.1.1.1 2001/01/05 12:50:11 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:36:10 2001] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "opt_i4b.h" +#endif +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <machine/stdarg.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#ifndef __bsdi__ +#include <machine/bus.h> +#endif +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#include <netisdn/i4b_trace.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +static u_char isic_isac_exir_hdlr(register struct l1_softc *sc, u_char exir); +static void isic_isac_ind_hdlr(register struct l1_softc *sc, int ind); + +/*---------------------------------------------------------------------------* + * ISAC interrupt service routine + *---------------------------------------------------------------------------*/ +void +isic_isac_irq(struct l1_softc *sc, int ista) +{ + register u_char c = 0; + NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista); + + if(ista & ISAC_ISTA_EXI) /* extended interrupt */ + { + c |= isic_isac_exir_hdlr(sc, ISAC_READ(I_EXIR)); + } + + if(ista & ISAC_ISTA_RME) /* receive message end */ + { + register int rest; + u_char rsta; + + /* get rx status register */ + + rsta = ISAC_READ(I_RSTA); + + if((rsta & ISAC_RSTA_MASK) != 0x20) + { + int error = 0; + + if(!(rsta & ISAC_RSTA_CRC)) /* CRC error */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit); + } + + if(rsta & ISAC_RSTA_RDO) /* ReceiveDataOverflow */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit); + } + + if(rsta & ISAC_RSTA_RAB) /* ReceiveABorted */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit); + } + + if(error == 0) + { + NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTA = 0x%02x!", sc->sc_unit, rsta); + } + + i4b_Dfreembuf(sc->sc_ibuf); + + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES); + ISACCMDRWRDELAY(); + + return; + } + + rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1)); + + if(rest == 0) + rest = ISAC_FIFO_LEN; + + if(sc->sc_ibuf == NULL) + { + if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL) + sc->sc_ib = sc->sc_ibuf->m_data; + else + panic("isic_isac_irq: RME, i4b_Dgetmbuf returns NULL!\n"); + sc->sc_ilen = 0; + } + + if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest)) + { + ISAC_RDFIFO(sc->sc_ib, rest); + sc->sc_ilen += rest; + + sc->sc_ibuf->m_pkthdr.len = + sc->sc_ibuf->m_len = sc->sc_ilen; + + if(sc->sc_trace & TRACE_D_RX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_D; + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data); + } + + c |= ISAC_CMDR_RMC; + + if(sc->sc_enabled && + (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)) + { + PH_Data_Ind(sc->sc_unit, sc->sc_ibuf); + } + else + { + i4b_Dfreembuf(sc->sc_ibuf); + } + } + else + { + NDBGL1(L1_I_ERR, "RME, input buffer overflow!"); + i4b_Dfreembuf(sc->sc_ibuf); + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + } + + if(ista & ISAC_ISTA_RPF) /* receive fifo full */ + { + if(sc->sc_ibuf == NULL) + { + if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL) + sc->sc_ib= sc->sc_ibuf->m_data; + else + panic("isic_isac_irq: RPF, i4b_Dgetmbuf returns NULL!\n"); + sc->sc_ilen = 0; + } + + if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISAC_FIFO_LEN)) + { + ISAC_RDFIFO(sc->sc_ib, ISAC_FIFO_LEN); + sc->sc_ilen += ISAC_FIFO_LEN; + sc->sc_ib += ISAC_FIFO_LEN; + c |= ISAC_CMDR_RMC; + } + else + { + NDBGL1(L1_I_ERR, "RPF, input buffer overflow!"); + i4b_Dfreembuf(sc->sc_ibuf); + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + } + + if(ista & ISAC_ISTA_XPR) /* transmit fifo empty (XPR bit set) */ + { + if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL)) + { + sc->sc_freeflag = sc->sc_freeflag2; + sc->sc_obuf = sc->sc_obuf2; + sc->sc_op = sc->sc_obuf->m_data; + sc->sc_ol = sc->sc_obuf->m_len; + sc->sc_obuf2 = NULL; +#ifdef NOTDEF + printf("ob2=%x, op=%x, ol=%d, f=%d #", + sc->sc_obuf, + sc->sc_op, + sc->sc_ol, + sc->sc_state); +#endif + } + else + { +#ifdef NOTDEF + printf("ob=%x, op=%x, ol=%d, f=%d #", + sc->sc_obuf, + sc->sc_op, + sc->sc_ol, + sc->sc_state); +#endif + } + + if(sc->sc_obuf) + { + ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISAC_FIFO_LEN)); + + if(sc->sc_ol > ISAC_FIFO_LEN) /* length > 32 ? */ + { + sc->sc_op += ISAC_FIFO_LEN; /* bufferptr+32 */ + sc->sc_ol -= ISAC_FIFO_LEN; /* length - 32 */ + c |= ISAC_CMDR_XTF; /* set XTF bit */ + } + else + { + if(sc->sc_freeflag) + { + i4b_Dfreembuf(sc->sc_obuf); + sc->sc_freeflag = 0; + } + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + + c |= ISAC_CMDR_XTF | ISAC_CMDR_XME; + } + } + else + { + sc->sc_state &= ~ISAC_TX_ACTIVE; + } + } + + if(ista & ISAC_ISTA_CISQ) /* channel status change CISQ */ + { + register u_char ci; + + /* get command/indication rx register*/ + + ci = ISAC_READ(I_CIRR); + + /* if S/Q IRQ, read SQC reg to clr SQC IRQ */ + + if(ci & ISAC_CIRR_SQC) + (void) ISAC_READ(I_SQRR); + + /* C/I code change IRQ (flag already cleared by CIRR read) */ + + if(ci & ISAC_CIRR_CIC0) + isic_isac_ind_hdlr(sc, (ci >> 2) & 0xf); + } + + if(c) + { + ISAC_WRITE(I_CMDR, c); + ISACCMDRWRDELAY(); + } +} + +/*---------------------------------------------------------------------------* + * ISAC L1 Extended IRQ handler + *---------------------------------------------------------------------------*/ +static u_char +isic_isac_exir_hdlr(register struct l1_softc *sc, u_char exir) +{ + u_char c = 0; + + if(exir & ISAC_EXIR_XMR) + { + NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat"); + + c |= ISAC_CMDR_XRES; + } + + if(exir & ISAC_EXIR_XDU) + { + NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun"); + + c |= ISAC_CMDR_XRES; + } + + if(exir & ISAC_EXIR_PCE) + { + NDBGL1(L1_I_ERR, "EXIRQ Protocol Error"); + } + + if(exir & ISAC_EXIR_RFO) + { + NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow"); + + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + + if(exir & ISAC_EXIR_SOV) + { + NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow"); + } + + if(exir & ISAC_EXIR_MOS) + { + NDBGL1(L1_I_ERR, "EXIRQ Monitor Status"); + } + + if(exir & ISAC_EXIR_SAW) + { + /* cannot happen, STCR:TSF is set to 0 */ + + NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake"); + } + + if(exir & ISAC_EXIR_WOV) + { + /* cannot happen, STCR:TSF is set to 0 */ + + NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow"); + } + + return(c); +} + +/*---------------------------------------------------------------------------* + * ISAC L1 Indication handler + *---------------------------------------------------------------------------*/ +static void +isic_isac_ind_hdlr(register struct l1_softc *sc, int ind) +{ + register int event; + + switch(ind) + { + case ISAC_CIRR_IAI8: + NDBGL1(L1_I_CICO, "rx AI8 in state %s", isic_printstate(sc)); + if(sc->sc_bustyp == BUS_TYPE_IOM2) + isic_isac_l1_cmd(sc, CMD_AR8); + event = EV_INFO48; + MPH_Status_Ind(sc->sc_unit, STI_L1STAT, LAYER_ACTIVE); + break; + + case ISAC_CIRR_IAI10: + NDBGL1(L1_I_CICO, "rx AI10 in state %s", isic_printstate(sc)); + if(sc->sc_bustyp == BUS_TYPE_IOM2) + isic_isac_l1_cmd(sc, CMD_AR10); + event = EV_INFO410; + MPH_Status_Ind(sc->sc_unit, STI_L1STAT, LAYER_ACTIVE); + break; + + case ISAC_CIRR_IRSY: + NDBGL1(L1_I_CICO, "rx RSY in state %s", isic_printstate(sc)); + event = EV_RSY; + break; + + case ISAC_CIRR_IPU: + NDBGL1(L1_I_CICO, "rx PU in state %s", isic_printstate(sc)); + event = EV_PU; + break; + + case ISAC_CIRR_IDR: + NDBGL1(L1_I_CICO, "rx DR in state %s", isic_printstate(sc)); + isic_isac_l1_cmd(sc, CMD_DIU); + event = EV_DR; + break; + + case ISAC_CIRR_IDID: + NDBGL1(L1_I_CICO, "rx DID in state %s", isic_printstate(sc)); + event = EV_INFO0; + MPH_Status_Ind(sc->sc_unit, STI_L1STAT, LAYER_IDLE); + break; + + case ISAC_CIRR_IDIS: + NDBGL1(L1_I_CICO, "rx DIS in state %s", isic_printstate(sc)); + event = EV_DIS; + break; + + case ISAC_CIRR_IEI: + NDBGL1(L1_I_CICO, "rx EI in state %s", isic_printstate(sc)); + isic_isac_l1_cmd(sc, CMD_DIU); + event = EV_EI; + break; + + case ISAC_CIRR_IARD: + NDBGL1(L1_I_CICO, "rx ARD in state %s", isic_printstate(sc)); + event = EV_INFO2; + break; + + case ISAC_CIRR_ITI: + NDBGL1(L1_I_CICO, "rx TI in state %s", isic_printstate(sc)); + event = EV_INFO0; + break; + + case ISAC_CIRR_IATI: + NDBGL1(L1_I_CICO, "rx ATI in state %s", isic_printstate(sc)); + event = EV_INFO0; + break; + + case ISAC_CIRR_ISD: + NDBGL1(L1_I_CICO, "rx SD in state %s", isic_printstate(sc)); + event = EV_INFO0; + break; + + default: + NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, isic_printstate(sc)); + event = EV_INFO0; + break; + } + isic_next_state(sc, event); +} + +/*---------------------------------------------------------------------------* + * execute a layer 1 command + *---------------------------------------------------------------------------*/ +void +isic_isac_l1_cmd(struct l1_softc *sc, int command) +{ + u_char cmd; + +#ifdef I4B_SMP_WORKAROUND + + /* XXXXXXXXXXXXXXXXXXX */ + + /* + * patch from Wolfgang Helbig: + * + * Here is a patch that makes i4b work on an SMP: + * The card (TELES 16.3) didn't interrupt on an SMP machine. + * This is a gross workaround, but anyway it works *and* provides + * some information as how to finally fix this problem. + */ + + HSCX_WRITE(0, H_MASK, 0xff); + HSCX_WRITE(1, H_MASK, 0xff); + ISAC_WRITE(I_MASK, 0xff); + DELAY(100); + HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); + HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); + ISAC_WRITE(I_MASK, ISAC_IMASK); + + /* XXXXXXXXXXXXXXXXXXX */ + +#endif /* I4B_SMP_WORKAROUND */ + + if(command < 0 || command > CMD_ILL) + { + NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, isic_printstate(sc)); + return; + } + + if(sc->sc_bustyp == BUS_TYPE_IOM2) + cmd = ISAC_CIX0_LOW; + else + cmd = 0; + + switch(command) + { + case CMD_TIM: + NDBGL1(L1_I_CICO, "tx TIM in state %s", isic_printstate(sc)); + cmd |= (ISAC_CIXR_CTIM << 2); + break; + + case CMD_RS: + NDBGL1(L1_I_CICO, "tx RS in state %s", isic_printstate(sc)); + cmd |= (ISAC_CIXR_CRS << 2); + break; + + case CMD_AR8: + NDBGL1(L1_I_CICO, "tx AR8 in state %s", isic_printstate(sc)); + cmd |= (ISAC_CIXR_CAR8 << 2); + break; + + case CMD_AR10: + NDBGL1(L1_I_CICO, "tx AR10 in state %s", isic_printstate(sc)); + cmd |= (ISAC_CIXR_CAR10 << 2); + break; + + case CMD_DIU: + NDBGL1(L1_I_CICO, "tx DIU in state %s", isic_printstate(sc)); + cmd |= (ISAC_CIXR_CDIU << 2); + break; + } + ISAC_WRITE(I_CIXR, cmd); +} + +/*---------------------------------------------------------------------------* + * L1 ISAC initialization + *---------------------------------------------------------------------------*/ +int +isic_isac_init(struct l1_softc *sc) +{ + ISAC_IMASK = 0xff; /* disable all irqs */ + + ISAC_WRITE(I_MASK, ISAC_IMASK); + + if(sc->sc_bustyp != BUS_TYPE_IOM2) + { + NDBGL1(L1_I_SETUP, "configuring for IOM-1 mode"); + + /* ADF2: Select mode IOM-1 */ + ISAC_WRITE(I_ADF2, 0x00); + + /* SPCR: serial port control register: + * SPU - software power up = 0 + * SAC - SIP port high Z + * SPM - timing mode 0 + * TLP - test loop = 0 + * C1C, C2C - B1 and B2 switched to/from SPa + */ + ISAC_WRITE(I_SPCR, ISAC_SPCR_C1C1|ISAC_SPCR_C2C1); + + /* SQXR: S/Q channel xmit register: + * SQIE - S/Q IRQ enable = 0 + * SQX1-4 - Fa bits = 1 + */ + ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); + + /* ADF1: additional feature reg 1: + * WTC - watchdog = 0 + * TEM - test mode = 0 + * PFS - pre-filter = 0 + * CFS - IOM clock/frame always active + * FSC1/2 - polarity of 8kHz strobe + * ITF - interframe fill = idle + */ + ISAC_WRITE(I_ADF1, ISAC_ADF1_FC2); /* ADF1 */ + + /* STCR: sync transfer control reg: + * TSF - terminal secific functions = 0 + * TBA - TIC bus address = 7 + * STx/SCx = 0 + */ + ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); + + /* MODE: Mode Register: + * MDSx - transparent mode 2 + * TMD - timer mode = external + * RAC - Receiver enabled + * DIMx - digital i/f mode + */ + ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); + } + else + { + NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode"); + + /* ADF2: Select mode IOM-2 */ + ISAC_WRITE(I_ADF2, ISAC_ADF2_IMS); + + /* SPCR: serial port control register: + * SPU - software power up = 0 + * SPM - timing mode 0 + * TLP - test loop = 0 + * C1C, C2C - B1 + C1 and B2 + IC2 monitoring + */ + ISAC_WRITE(I_SPCR, 0x00); + + /* SQXR: S/Q channel xmit register: + * IDC - IOM direction = 0 (master) + * CFS - Config Select = 0 (clock always active) + * CI1E - C/I channel 1 IRQ enable = 0 + * SQIE - S/Q IRQ enable = 0 + * SQX1-4 - Fa bits = 1 + */ + ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); + + /* ADF1: additional feature reg 1: + * WTC - watchdog = 0 + * TEM - test mode = 0 + * PFS - pre-filter = 0 + * IOF - IOM i/f off = 0 + * ITF - interframe fill = idle + */ + ISAC_WRITE(I_ADF1, 0x00); + + /* STCR: sync transfer control reg: + * TSF - terminal secific functions = 0 + * TBA - TIC bus address = 7 + * STx/SCx = 0 + */ + ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); + + /* MODE: Mode Register: + * MDSx - transparent mode 2 + * TMD - timer mode = external + * RAC - Receiver enabled + * DIMx - digital i/f mode + */ + ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); + } + +#ifdef NOTDEF + /* + * XXX a transmitter reset causes an ISAC tx IRQ which will not + * be serviced at attach time under some circumstances leaving + * the associated IRQ line on the ISA bus active. This prevents + * any further interrupts to be serviced because no low -> high + * transition can take place anymore. (-hm) + */ + + /* command register: + * RRES - HDLC receiver reset + * XRES - transmitter reset + */ + ISAC_WRITE(I_CMDR, ISAC_CMDR_RRES|ISAC_CMDR_XRES); + ISACCMDRWRDELAY(); +#endif + + /* enabled interrupts: + * =================== + * RME - receive message end + * RPF - receive pool full + * XPR - transmit pool ready + * CISQ - CI or S/Q channel change + * EXI - extended interrupt + */ + + ISAC_IMASK = ISAC_MASK_RSC | /* auto mode only */ + ISAC_MASK_TIN | /* timer irq */ + ISAC_MASK_SIN; /* sync xfer irq */ + + ISAC_WRITE(I_MASK, ISAC_IMASK); + + return(0); +} diff --git a/sys/dev/ic/i4b_isac.h b/sys/dev/ic/i4b_isac.h new file mode 100644 index 00000000000..62e9affaa56 --- /dev/null +++ b/sys/dev/ic/i4b_isac.h @@ -0,0 +1,391 @@ +/* + * Copyright (c) 1996, 1998 Gary Jennejohn. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * $Id: i4b_isac.h,v 1.1.1.1 2001/01/05 12:50:11 martin Exp $ + * + * last edit-date: [Sun Feb 14 10:27:13 1999] + * + * -hm split up for rewrite of Siemens chipset driver + * + *--------------------------------------------------------------------------- + */ + +#ifndef I4B_ISAC_H_ +#define I4B_ISAC_H_ + +/* + * The ISAC databook specifies a delay of 2.5 DCL clock cycles between + * writes to the ISAC command register CMDR. This is the delay used to + * satisfy this requirement. + */ + +#define I4B_ISAC_CMDRWRDELAY 30 + +#if (I4B_ISAC_CMDRWRDELAY > 0) +#define ISACCMDRWRDELAY() DELAY(I4B_ISAC_CMDRWRDELAY) +#else +#warning "I4B_ISAC_CMDRWRDELAY set to 0!" +#define ISACCMDRWRDELAY() +#endif + +enum ISAC_VERSIONS { + ISAC_VA, /* 2085 A1 or A2, 2086/2186 V1.1 */ + ISAC_VB1, /* 2085 B1 */ + ISAC_VB2, /* 2085 B2 */ + ISAC_VB3, /* 2085 B3/V2.3 */ + ISAC_UNKN /* unknown version */ +}; + +#define ISAC_FIFO_LEN 32 /* 32 bytes FIFO on chip */ + +/* + * definitions of registers and bits for the ISAC ISDN chip. + */ + +typedef struct isac_reg { + + /* 32 byte deep FIFO always first */ + + unsigned char isac_fifo [ISAC_FIFO_LEN]; + + /* most registers can be read/written, but have different names */ + /* so define a union with read/write names to make that clear */ + + union { + struct { + unsigned char isac_ista; + unsigned char isac_star; + unsigned char isac_mode; + unsigned char isac_timr; + unsigned char isac_exir; + unsigned char isac_rbcl; + unsigned char isac_sapr; + unsigned char isac_rsta; + unsigned char dummy_28; + unsigned char isac_rhcr; + unsigned char isac_rbch; + unsigned char isac_star2; + unsigned char dummy_2c; + unsigned char dummy_2d; + unsigned char dummy_2e; + unsigned char dummt_2f; + unsigned char isac_spcr; + unsigned char isac_cirr; + unsigned char isac_mor; + unsigned char isac_sscr; + unsigned char isac_sfcr; + unsigned char isac_c1r; + unsigned char isac_c2r; + unsigned char isac_b1cr; + unsigned char isac_b2cr; + unsigned char isac_adf2; + unsigned char isac_mosr; + unsigned char isac_sqrr; + } isac_r; + struct { + unsigned char isac_mask; + unsigned char isac_cmdr; + unsigned char isac_mode; + unsigned char isac_timr; + unsigned char isac_xad1; + unsigned char isac_xad2; + unsigned char isac_sap1; + unsigned char isac_sap2; + unsigned char isac_tei1; + unsigned char isac_tei2; + unsigned char dummy_2a; + unsigned char isac_star2; + unsigned char dummy_2c; + unsigned char dummy_2d; + unsigned char dummy_2e; + unsigned char dummt_2f; + unsigned char isac_spcr; + unsigned char isac_cixr; + unsigned char isac_mox; + unsigned char isac_sscx; + unsigned char isac_sfcw; + unsigned char isac_c1r; + unsigned char isac_c2r; + unsigned char isac_stcr; + unsigned char isac_adf1; + unsigned char isac_adf2; + unsigned char isac_mocr; + unsigned char isac_sqxr; + } isac_w; + } isac_rw; +} isac_reg_t; + +#define REG_OFFSET(type, field) (int)(&(((type *)0)->field)) + +/* ISAC read registers */ + +#define i_ista isac_rw.isac_r.isac_ista +#define I_ISTA REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_ista) +#define i_star isac_rw.isac_r.isac_star +#define I_STAR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_star) +#define i_mode isac_rw.isac_r.isac_mode +#define I_MODE REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_mode) +#define i_timr isac_rw.isac_r.isac_timr +#define I_TIMR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_timr) +#define i_exir isac_rw.isac_r.isac_exir +#define I_EXIR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_exir) +#define i_rbcl isac_rw.isac_r.isac_rbcl +#define I_RBCL REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_rbcl) +#define i_sapr isac_rw.isac_r.isac_sapr +#define I_SAPR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_sapr) +#define i_rsta isac_rw.isac_r.isac_rsta +#define I_RSTA REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_rsta) +#define i_rhcr isac_rw.isac_r.isac_rhcr +#define I_RHCR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_rhcr) +#define i_rbch isac_rw.isac_r.isac_rbch +#define I_RBCH REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_rbch) +#define i_star2 isac_rw.isac_r.isac_star2 +#define I_STAR2 REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_star2) +#define i_spcr isac_rw.isac_r.isac_spcr +#define I_SPCR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_spcr) +#define i_cirr isac_rw.isac_r.isac_cirr +#define I_CIRR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_cirr) +#define i_mor isac_rw.isac_r.isac_mor +#define I_MOR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_mor) +#define i_sscr isac_rw.isac_r.isac_sscr +#define I_SSCR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_sscr) +#define i_sfcr isac_rw.isac_r.isac_sfcr +#define I_SFCR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_sfcr) +#define i_c1r isac_rw.isac_r.isac_c1r +#define I_C1R REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_c1r) +#define i_c2r isac_rw.isac_r.isac_c2r +#define I_C2R REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_c2r) +#define i_b1cr isac_rw.isac_r.isac_b1cr +#define I_B1CR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_b1cr) +#define i_b2cr isac_rw.isac_r.isac_b2cr +#define I_B2CR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_b2cr) +#define i_adf2 isac_rw.isac_r.isac_adf2 +#define I_ADF2 REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_adf2) +#define i_mosr isac_rw.isac_r.isac_mosr +#define I_MOSR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_mosr) +#define i_sqrr isac_rw.isac_r.isac_sqrr +#define I_SQRR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_sqrr) + +/* ISAC write registers - isac_mode, isac_timr, isac_star2, isac_spcr, */ +/* isac_c1r, isac_c2r, isac_adf2 see read registers */ + +#define i_mask isac_rw.isac_w.isac_mask +#define I_MASK REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_mask) +#define i_cmdr isac_rw.isac_w.isac_cmdr +#define I_CMDR REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_cmdr) +#define i_xad1 isac_rw.isac_w.isac_xad1 +#define I_XAD1 REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_xad1) +#define i_xad2 isac_rw.isac_w.isac_xad2 +#define I_XAD2 REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_xad2) +#define i_sap1 isac_rw.isac_w.isac_sap1 +#define I_SAP1 REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_sap1) +#define i_sap2 isac_rw.isac_w.isac_sap2 +#define I_SAP2 REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_sap2) +#define i_tei1 isac_rw.isac_w.isac_tei1 +#define i_tei2 isac_rw.isac_w.isac_tei2 +#define i_cixr isac_rw.isac_w.isac_cixr +#define I_CIXR REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_cixr) +#define I_CIX0 I_CIXR +#define i_mox isac_rw.isac_w.isac_mox +#define I_MOX REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_mox) +#define i_sscx isac_rw.isac_w.isac_sscx +#define I_SSCX REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_sscx) +#define i_sfcw isac_rw.isac_w.isac_sfcw +#define I_SFCW REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_sfcw) +#define i_stcr isac_rw.isac_w.isac_stcr +#define I_STCR REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_stcr) +#define i_adf1 isac_rw.isac_w.isac_adf1 +#define I_ADF1 REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_adf1) +#define i_mocr isac_rw.isac_w.isac_mocr +#define I_MOCR REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_mocr) +#define i_sqxr isac_rw.isac_w.isac_sqxr +#define I_SQXR REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_sqxr) + +#define ISAC_ISTA_RME 0x80 +#define ISAC_ISTA_RPF 0x40 +#define ISAC_ISTA_RSC 0x20 +#define ISAC_ISTA_XPR 0x10 +#define ISAC_ISTA_TIN 0x08 +#define ISAC_ISTA_CISQ 0x04 +#define ISAC_ISTA_SIN 0x02 +#define ISAC_ISTA_EXI 0x01 + +#define ISAC_MASK_RME 0x80 +#define ISAC_MASL_RPF 0x40 +#define ISAC_MASK_RSC 0x20 +#define ISAC_MASK_XPR 0x10 +#define ISAC_MASK_TIN 0x08 +#define ISAC_MASK_CISQ 0x04 +#define ISAC_MASK_SIN 0x02 +#define ISAC_MASK_EXI 0x01 +#define ISAC_MASK_ALL 0xff + +#define ISAC_STAR_XDOV 0x80 +#define ISAC_STAR_XFW 0x40 +#define ISAC_STAR_XRNR 0x20 +#define ISAC_STAR_RRNR 0x10 +#define ISAC_STAR_MBR 0x08 +#define ISAC_STAR_MAC1 0x04 +#define ISAC_STAR_BVS 0x02 +#define ISAC_STAR_MAC0 0x01 + +#define ISAC_CMDR_RMC 0x80 +#define ISAC_CMDR_RRES 0x40 +#define ISAC_CMDR_RNR 0x20 +#define ISAC_CMDR_STI 0x10 +#define ISAC_CMDR_XTF 0x08 +#define ISAC_CMDR_XIF 0x04 +#define ISAC_CMDR_XME 0x02 +#define ISAC_CMDR_XRES 0x01 + +#define ISAC_MODE_MDS2 0x80 +#define ISAC_MODE_MDS1 0x40 +#define ISAC_MODE_MDS0 0x20 +#define ISAC_MODE_TMD 0x10 +#define ISAC_MODE_RAC 0x08 +#define ISAC_MODE_DIM2 0x04 +#define ISAC_MODE_DIM1 0x02 +#define ISAC_MODE_DIM0 0x01 + +#define ISAC_EXIR_XMR 0x80 +#define ISAC_EXIR_XDU 0x40 +#define ISAC_EXIR_PCE 0x20 +#define ISAC_EXIR_RFO 0x10 +#define ISAC_EXIR_SOV 0x08 +#define ISAC_EXIR_MOS 0x04 +#define ISAC_EXIR_SAW 0x02 +#define ISAC_EXIR_WOV 0x01 + +#define ISAC_RSTA_RDA 0x80 +#define ISAC_RSTA_RDO 0x40 +#define ISAC_RSTA_CRC 0x20 +#define ISAC_RSTA_RAB 0x10 +#define ISAC_RSTA_SA1 0x08 +#define ISAC_RSTA_SA0 0x04 +#define ISAC_RSTA_CR 0x02 +#define ISAC_RSTA_TA 0x01 + +#define ISAC_RSTA_MASK 0x70 /* the interesting bits */ + +#define ISAC_RBCH_XAC 0x80 +#define ISAC_RBCH_VN1 0x40 +#define ISAC_RBCH_VN0 0x20 +#define ISAC_RBCH_OV 0x10 +/* the other 4 bits are the high bits of the receive byte count */ + +#define ISAC_SPCR_SPU 0x80 +#define ISAC_SPCR_SAC 0x40 +#define ISAC_SPCR_SPM 0x20 +#define ISAC_SPCR_TLP 0x10 +#define ISAC_SPCR_C1C1 0x08 +#define ISAC_SPCR_C1C0 0x04 +#define ISAC_SPCR_C2C1 0x02 +#define ISAC_SPCR_C2C0 0x01 + +#define ISAC_CIRR_SQC 0x80 +#define ISAC_CIRR_BAS 0x40 +/* bits 5-2 CODR */ +#define ISAC_CIRR_CIC0 0x02 +/* bit 0 is always 0 */ +/* C/I codes from bits 5-2 (>> 2 & 0xf) */ +/* the indications */ +#define ISAC_CIRR_IPU 0x07 +#define ISAC_CIRR_IDR 0x00 +#define ISAC_CIRR_ISD 0x02 +#define ISAC_CIRR_IDIS 0x03 +#define ISAC_CIRR_IEI 0x06 +#define ISAC_CIRR_IRSY 0x04 +#define ISAC_CIRR_IARD 0x08 +#define ISAC_CIRR_ITI 0x0a +#define ISAC_CIRR_IATI 0x0b +#define ISAC_CIRR_IAI8 0x0c +#define ISAC_CIRR_IAI10 0x0d +#define ISAC_CIRR_IDID 0x0f + +#define ISAC_CI_MASK 0x0f + +#define ISAC_CIXR_RSS 0x80 +#define ISAC_CIXR_BAC 0x40 +/* bits 5-2 CODX */ +#define ISAC_CIXR_TCX 0x02 +#define ISAC_CIXR_ECX 0x01 +/* in IOM-2 mode the low bits are always 1 */ +#define ISAC_CIX0_LOW 0x03 +/* C/I codes from bits 5-2 (>> 2 & 0xf) */ +/* the commands */ +#define ISAC_CIXR_CTIM 0 +#define ISAC_CIXR_CRS 0x01 +#define ISAC_CIXR_CSCZ 0x04 +#define ISAC_CIXR_CSSZ 0x02 +#define ISAC_CIXR_CAR8 0x08 +#define ISAC_CIXR_CAR10 0x09 +#define ISAC_CIXR_CARL 0x0a +#define ISAC_CIXR_CDIU 0x0f + +#define ISAC_STCR_TSF 0x80 +#define ISAC_STCR_TBA2 0x40 +#define ISAC_STCR_TBA1 0x20 +#define ISAC_STCR_TBA0 0x10 +#define ISAC_STCR_ST1 0x08 +#define ISAC_STCR_ST0 0x04 +#define ISAC_STCR_SC1 0x02 +#define ISAC_STCR_SC0 0x01 + +#define ISAC_ADF1_WTC1 0x80 +#define ISAC_ADF1_WTC2 0x40 +#define ISAC_ADF1_TEM 0x20 +#define ISAC_ADF1_PFS 0x10 +#define ISAC_ADF1_CFS 0x08 +#define ISAC_ADF1_FC2 0x04 +#define ISAC_ADF1_FC1 0x02 +#define ISAC_ADF1_ITF 0x01 + +#define ISAC_ADF2_IMS 0x80 +/* all other bits are 0 */ + +/* bits 7-5 are always 0 */ +#define ISAC_SQRR_SYN 0x10 +#define ISAC_SQRR_SQR1 0x08 +#define ISAC_SQRR_SQR2 0x04 +#define ISAC_SQRR_SQR3 0x02 +#define ISAC_SQRR_SQR4 0x01 + +#define ISAC_SQXR_IDC 0x80 +#define ISAC_SQXR_CFS 0x40 +#define ISAC_SQXR_CI1E 0x20 +#define ISAC_SQXR_SQIE 0x10 +#define ISAC_SQXR_SQX1 0x08 +#define ISAC_SQXR_SQX2 0x04 +#define ISAC_SQXR_SQX3 0x02 +#define ISAC_SQXR_SQX4 0x01 + +#endif /* I4B_ISAC_H_ */ diff --git a/sys/dev/ic/i4b_isic.c b/sys/dev/ic/i4b_isic.c new file mode 100644 index 00000000000..8978f9fa8a7 --- /dev/null +++ b/sys/dev/ic/i4b_isic.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 1997, 2000 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. + * + *--------------------------------------------------------------------------- + * + * i4b_isic.c - global isic stuff + * ============================== + * + * $Id: i4b_isic.c,v 1.1.1.1 2001/01/05 12:50:11 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:36:10 2001] + * + *---------------------------------------------------------------------------*/ + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <sys/device.h> +#if defined(__NetBSD__) && defined(amiga) +#include <machine/bus.h> +#else +#ifndef __bsdi__ +#include <dev/isa/isavar.h> +#endif +#endif +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#include <netisdn/i4b_trace.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_ipac.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> +#include <netisdn/i4b_global.h> + +#ifdef __bsdi__ +static int isicmatch(struct device *parent, struct cfdata *cf, void *aux); +static void isicattach(struct device *parent, struct device *self, void *aux); +struct cfdriver isiccd = + { NULL, "isic", isicmatch, isicattach, DV_IFNET, + sizeof(struct l1_softc) }; + +int isa_isicmatch(struct device *parent, struct cfdata *cf, struct isa_attach_args *); +int isapnp_isicmatch(struct device *parent, struct cfdata *cf, struct isa_attach_args *); +int isa_isicattach(struct device *parent, struct device *self, struct isa_attach_args *ia); + +static int +isicmatch(struct device *parent, struct cfdata *cf, void *aux) +{ + struct isa_attach_args *ia = (struct isa_attach_args *) aux; + if (ia->ia_bustype == BUS_PCMCIA) { + ia->ia_irq = IRQNONE; + /* return 1; Not yet */ + return 0; /* for now */ + } + if (ia->ia_bustype == BUS_PNP) { + return isapnp_isicmatch(parent, cf, ia); + } + return isa_isicmatch(parent, cf, ia); +} + +static void +isicattach(struct device *parent, struct device *self, void *aux) +{ + struct isa_attach_args *ia = (struct isa_attach_args *) aux; + struct l1_softc *sc = (struct l1_softc *)self; + + sc->sc_flags = sc->sc_dev.dv_flags; + isa_isicattach(parent, self, ia); + isa_establish(&sc->sc_id, &sc->sc_dev); + sc->sc_ih.ih_fun = isicintr; + sc->sc_ih.ih_arg = (void *)sc; + intr_establish(ia->ia_irq, &sc->sc_ih, DV_NET); + /* Could add a shutdown hook here... */ +} +#endif + +#ifdef __FreeBSD__ +void isicintr_sc(struct l1_softc *sc); +#if !(defined(__FreeBSD_version)) || (defined(__FreeBSD_version) && __FreeBSD_version >= 300006) +void isicintr(int unit); +#endif +#else +/* XXX - hack, going away soon! */ +struct l1_softc *l1_sc[ISIC_MAXUNIT]; +#endif + +/*---------------------------------------------------------------------------* + * isic - device driver interrupt routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +void +isicintr_sc(struct l1_softc *sc) +{ + isicintr(sc->sc_unit); +} + +void +isicintr(int unit) +{ + register struct l1_softc *sc = &l1_sc[unit]; +#else +int +isicintr(void *arg) +{ + struct l1_softc *sc = arg; +#endif + + if(sc->sc_ipac == 0) /* HSCX/ISAC interupt routine */ + { + u_char was_hscx_irq = 0; + u_char was_isac_irq = 0; + + register u_char hscx_irq_stat; + register u_char isac_irq_stat; + + for(;;) + { + /* get hscx irq status from hscx b ista */ + hscx_irq_stat = + HSCX_READ(HSCX_CH_B, H_ISTA) & ~HSCX_B_IMASK; + + /* get isac irq status */ + isac_irq_stat = ISAC_READ(I_ISTA); + + /* do as long as there are pending irqs in the chips */ + if(!hscx_irq_stat && !isac_irq_stat) + break; + + if(hscx_irq_stat & (HSCX_ISTA_RME | HSCX_ISTA_RPF | + HSCX_ISTA_RSC | HSCX_ISTA_XPR | + HSCX_ISTA_TIN | HSCX_ISTA_EXB)) + { + isic_hscx_irq(sc, hscx_irq_stat, + HSCX_CH_B, + hscx_irq_stat & HSCX_ISTA_EXB); + was_hscx_irq = 1; + } + + if(hscx_irq_stat & (HSCX_ISTA_ICA | HSCX_ISTA_EXA)) + { + isic_hscx_irq(sc, + HSCX_READ(HSCX_CH_A, H_ISTA) & ~HSCX_A_IMASK, + HSCX_CH_A, + hscx_irq_stat & HSCX_ISTA_EXA); + was_hscx_irq = 1; + } + + if(isac_irq_stat) + { + isic_isac_irq(sc, isac_irq_stat); /* isac handler */ + was_isac_irq = 1; + } + } + + HSCX_WRITE(0, H_MASK, 0xff); + ISAC_WRITE(I_MASK, 0xff); + HSCX_WRITE(1, H_MASK, 0xff); + + if (sc->clearirq) + { + DELAY(80); + sc->clearirq(sc); + } else + DELAY(100); + + HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); + ISAC_WRITE(I_MASK, ISAC_IMASK); + HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); +#ifndef __FreeBSD__ + return(was_hscx_irq || was_isac_irq); +#endif + } + else /* IPAC interrupt routine */ + { + register u_char ipac_irq_stat; + register u_char was_ipac_irq = 0; + + for(;;) + { + /* get global irq status */ + + ipac_irq_stat = (IPAC_READ(IPAC_ISTA)) & 0x3f; + + /* check hscx a */ + + if(ipac_irq_stat & (IPAC_ISTA_ICA | IPAC_ISTA_EXA)) + { + /* HSCX A interrupt */ + isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA), + HSCX_CH_A, + ipac_irq_stat & IPAC_ISTA_EXA); + was_ipac_irq = 1; + } + if(ipac_irq_stat & (IPAC_ISTA_ICB | IPAC_ISTA_EXB)) + { + /* HSCX B interrupt */ + isic_hscx_irq(sc, HSCX_READ(HSCX_CH_B, H_ISTA), + HSCX_CH_B, + ipac_irq_stat & IPAC_ISTA_EXB); + was_ipac_irq = 1; + } + if(ipac_irq_stat & IPAC_ISTA_ICD) + { + /* ISAC interrupt */ + isic_isac_irq(sc, ISAC_READ(I_ISTA)); + was_ipac_irq = 1; + } + if(ipac_irq_stat & IPAC_ISTA_EXD) + { + /* force ISAC interrupt handling */ + isic_isac_irq(sc, ISAC_ISTA_EXI); + was_ipac_irq = 1; + } + + /* do as long as there are pending irqs in the chip */ + if(!ipac_irq_stat) + break; + } +#ifdef NOTDEF + if(was_ipac_irq == 0) + NDBGL1(L1_ERROR, "WARNING: unit %d, No IRQ from IPAC!", sc->sc_unit); +#endif + IPAC_WRITE(IPAC_MASK, 0xff); + DELAY(50); + IPAC_WRITE(IPAC_MASK, 0xc0); + +#ifndef __FreeBSD__ + return(was_ipac_irq); +#endif + } +} + +/*---------------------------------------------------------------------------* + * isic_recovery - try to recover from irq lockup + *---------------------------------------------------------------------------*/ +void +isic_recover(struct l1_softc *sc) +{ + u_char byte; + + /* get hscx irq status from hscx b ista */ + + byte = HSCX_READ(HSCX_CH_B, H_ISTA); + + NDBGL1(L1_ERROR, "HSCX B: ISTA = 0x%x", byte); + + if(byte & HSCX_ISTA_ICA) + NDBGL1(L1_ERROR, "HSCX A: ISTA = 0x%x", (u_char)HSCX_READ(HSCX_CH_A, H_ISTA)); + + if(byte & HSCX_ISTA_EXB) + NDBGL1(L1_ERROR, "HSCX B: EXIR = 0x%x", (u_char)HSCX_READ(HSCX_CH_B, H_EXIR)); + + if(byte & HSCX_ISTA_EXA) + NDBGL1(L1_ERROR, "HSCX A: EXIR = 0x%x", (u_char)HSCX_READ(HSCX_CH_A, H_EXIR)); + + /* get isac irq status */ + + byte = ISAC_READ(I_ISTA); + + NDBGL1(L1_ERROR, " ISAC: ISTA = 0x%x", byte); + + if(byte & ISAC_ISTA_EXI) + NDBGL1(L1_ERROR, " ISAC: EXIR = 0x%x", (u_char)ISAC_READ(I_EXIR)); + + if(byte & ISAC_ISTA_CISQ) + { + byte = ISAC_READ(I_CIRR); + + NDBGL1(L1_ERROR, " ISAC: CISQ = 0x%x", byte); + + if(byte & ISAC_CIRR_SQC) + NDBGL1(L1_ERROR, " ISAC: SQRR = 0x%x", (u_char)ISAC_READ(I_SQRR)); + } + + NDBGL1(L1_ERROR, "HSCX B: IMASK = 0x%x", HSCX_B_IMASK); + NDBGL1(L1_ERROR, "HSCX A: IMASK = 0x%x", HSCX_A_IMASK); + + HSCX_WRITE(0, H_MASK, 0xff); + HSCX_WRITE(1, H_MASK, 0xff); + DELAY(100); + HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); + HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); + DELAY(100); + + NDBGL1(L1_ERROR, " ISAC: IMASK = 0x%x", ISAC_IMASK); + + ISAC_WRITE(I_MASK, 0xff); + DELAY(100); + ISAC_WRITE(I_MASK, ISAC_IMASK); +} diff --git a/sys/dev/ic/i4b_isicbchan.c b/sys/dev/ic/i4b_isicbchan.c new file mode 100644 index 00000000000..685c1a14bfc --- /dev/null +++ b/sys/dev/ic/i4b_isicbchan.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 1997, 2000 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. + * + *--------------------------------------------------------------------------- + * + * i4b_bchan.c - B channel handling L1 procedures + * ---------------------------------------------- + * + * $Id: i4b_isicbchan.c,v 1.1.1.1 2001/01/05 12:50:12 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:36:11 2001] + * + *---------------------------------------------------------------------------*/ + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <machine/stdarg.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#ifndef __bsdi__ +#include <machine/bus.h> +#endif +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#include <netisdn/i4b_trace.h> + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> +#include <netisdn/i4b_global.h> + +static void isic_bchannel_start __P((int unit, int h_chan)); +static void isic_bchannel_stat __P((int unit, int h_chan, bchan_statistics_t *bsp)); + +static void isic_set_linktab(int unit, int channel, drvr_link_t *dlt); +static isdn_link_t *isic_ret_linktab(int unit, int channel); + +/*---------------------------------------------------------------------------* + * initialize one B channels rx/tx data structures and init/deinit HSCX + *---------------------------------------------------------------------------*/ +void +isic_bchannel_setup(int unit, int h_chan, int bprot, int activate) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + + int s = SPLI4B(); + + if(activate == 0) + { + /* deactivation */ + isic_hscx_init(sc, h_chan, activate); + } + + NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s", + sc->sc_unit, h_chan, activate ? "activate" : "deactivate"); + + /* general part */ + + chan->unit = sc->sc_unit; /* unit number */ + chan->channel = h_chan; /* B channel */ + chan->bprot = bprot; /* B channel protocol */ + chan->state = HSCX_IDLE; /* B channel state */ + + /* receiver part */ + + i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */ + + chan->rx_queue.ifq_maxlen = IFQ_MAXLEN; + + chan->rxcount = 0; /* reset rx counter */ + + i4b_Bfreembuf(chan->in_mbuf); /* clean rx mbuf */ + + chan->in_mbuf = NULL; /* reset mbuf ptr */ + chan->in_cbptr = NULL; /* reset mbuf curr ptr */ + chan->in_len = 0; /* reset mbuf data len */ + + /* transmitter part */ + + i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */ + + chan->tx_queue.ifq_maxlen = IFQ_MAXLEN; + + chan->txcount = 0; /* reset tx counter */ + + i4b_Bfreembuf(chan->out_mbuf_head); /* clean tx mbuf */ + + chan->out_mbuf_head = NULL; /* reset head mbuf ptr */ + chan->out_mbuf_cur = NULL; /* reset current mbuf ptr */ + chan->out_mbuf_cur_ptr = NULL; /* reset current mbuf data ptr */ + chan->out_mbuf_cur_len = 0; /* reset current mbuf data cnt */ + + if(activate != 0) + { + /* activation */ + isic_hscx_init(sc, h_chan, activate); + } + + splx(s); +} + +/*---------------------------------------------------------------------------* + * start transmission on a b channel + *---------------------------------------------------------------------------*/ +static void +isic_bchannel_start(int unit, int h_chan) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + + register l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + register int next_len; + register int len; + + int s; + int activity = -1; + int cmd = 0; + + s = SPLI4B(); /* enter critical section */ + if(chan->state & HSCX_TX_ACTIVE) /* already running ? */ + { + splx(s); + return; /* yes, leave */ + } + + /* get next mbuf from queue */ + + IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head); + + if(chan->out_mbuf_head == NULL) /* queue empty ? */ + { + splx(s); /* leave critical section */ + return; /* yes, exit */ + } + + /* init current mbuf values */ + + chan->out_mbuf_cur = chan->out_mbuf_head; + chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; + chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; + + /* activity indicator for timeout handling */ + + if(chan->bprot == BPROT_NONE) + { + if(!(isic_hscx_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len))) + activity = ACT_TX; + } + else + { + activity = ACT_TX; + } + + chan->state |= HSCX_TX_ACTIVE; /* we start transmitting */ + + if(sc->sc_trace & TRACE_B_TX) /* if trace, send mbuf to trace dev */ + { + i4b_trace_hdr_t hdr; + hdr.unit = unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); + } + + len = 0; /* # of chars put into HSCX tx fifo this time */ + + /* + * fill the HSCX tx fifo with data from the current mbuf. if + * current mbuf holds less data than HSCX fifo length, try to + * get the next mbuf from (a possible) mbuf chain. if there is + * not enough data in a single mbuf or in a chain, then this + * is the last mbuf and we tell the HSCX that it has to send + * CRC and closing flag + */ + + while((len < sc->sc_bfifolen) && chan->out_mbuf_cur) + { + /* + * put as much data into the HSCX fifo as is + * available from the current mbuf + */ + + if((len + chan->out_mbuf_cur_len) >= sc->sc_bfifolen) + next_len = sc->sc_bfifolen - len; + else + next_len = chan->out_mbuf_cur_len; + +#ifdef NOTDEF + printf("b:mh=%x, mc=%x, mcp=%x, mcl=%d l=%d nl=%d # ", + chan->out_mbuf_head, + chan->out_mbuf_cur, + chan->out_mbuf_cur_ptr, + chan->out_mbuf_cur_len, + len, + next_len); +#endif + + /* wait for tx fifo write enabled */ + + isic_hscx_waitxfw(sc, h_chan); + + /* write what we have from current mbuf to HSCX fifo */ + + HSCX_WRFIFO(h_chan, chan->out_mbuf_cur_ptr, next_len); + + len += next_len; /* update # of bytes written */ + chan->txcount += next_len; /* statistics */ + chan->out_mbuf_cur_ptr += next_len; /* data ptr */ + chan->out_mbuf_cur_len -= next_len; /* data len */ + + /* + * in case the current mbuf (of a possible chain) data + * has been put into the fifo, check if there is a next + * mbuf in the chain. If there is one, get ptr to it + * and update the data ptr and the length + */ + + if((chan->out_mbuf_cur_len <= 0) && + ((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL)) + { + chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; + chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; + + if(sc->sc_trace & TRACE_B_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); + } + } + } + + /* + * if there is either still data in the current mbuf and/or + * there is a successor on the chain available issue just + * a XTF (transmit) command to HSCX. if ther is no more + * data available from the current mbuf (-chain), issue + * an XTF and an XME (message end) command which will then + * send the CRC and the closing HDLC flag sequence + */ + + if(chan->out_mbuf_cur && (chan->out_mbuf_cur_len > 0)) + { + /* + * more data available, send current fifo out. + * next xfer to HSCX tx fifo is done in the + * HSCX interrupt routine. + */ + + cmd |= HSCX_CMDR_XTF; + } + else + { + /* end of mbuf chain */ + + if(chan->bprot == BPROT_NONE) + cmd |= HSCX_CMDR_XTF; + else + cmd |= HSCX_CMDR_XTF | HSCX_CMDR_XME; + + i4b_Bfreembuf(chan->out_mbuf_head); /* free mbuf chain */ + + chan->out_mbuf_head = NULL; + chan->out_mbuf_cur = NULL; + chan->out_mbuf_cur_ptr = NULL; + chan->out_mbuf_cur_len = 0; + } + + /* call timeout handling routine */ + + if(activity == ACT_RX || activity == ACT_TX) + (*chan->drvr_linktab->bch_activity)(chan->drvr_linktab->unit, activity); + + if(cmd) + isic_hscx_cmd(sc, h_chan, cmd); + + splx(s); +} + +/*---------------------------------------------------------------------------* + * fill statistics struct + *---------------------------------------------------------------------------*/ +static void +isic_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + int s; + + s = SPLI4B(); + + bsp->outbytes = chan->txcount; + bsp->inbytes = chan->rxcount; + + chan->txcount = 0; + chan->rxcount = 0; + + splx(s); +} + +/*---------------------------------------------------------------------------* + * return the address of isic drivers linktab + *---------------------------------------------------------------------------*/ +static isdn_link_t * +isic_ret_linktab(int unit, int channel) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[channel]; + + return(&chan->isdn_linktab); +} + +/*---------------------------------------------------------------------------* + * set the driver linktab in the b channel softc + *---------------------------------------------------------------------------*/ +static void +isic_set_linktab(int unit, int channel, drvr_link_t *dlt) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[channel]; + + chan->drvr_linktab = dlt; +} + +/*---------------------------------------------------------------------------* + * initialize our local linktab + *---------------------------------------------------------------------------*/ +void +isic_init_linktab(struct l1_softc *sc) +{ + l1_bchan_state_t *chan = &sc->sc_chan[HSCX_CH_A]; + isdn_link_t *lt = &chan->isdn_linktab; + + /* make sure the hardware driver is known to layer 4 */ + ctrl_types[CTRL_PASSIVE].set_linktab = isic_set_linktab; + ctrl_types[CTRL_PASSIVE].get_linktab = isic_ret_linktab; + + /* local setup */ + lt->unit = sc->sc_unit; + lt->channel = HSCX_CH_A; + lt->bch_config = isic_bchannel_setup; + lt->bch_tx_start = isic_bchannel_start; + lt->bch_stat = isic_bchannel_stat; + lt->tx_queue = &chan->tx_queue; + + /* used by non-HDLC data transfers, i.e. telephony drivers */ + lt->rx_queue = &chan->rx_queue; + + /* used by HDLC data transfers, i.e. ipr and isp drivers */ + lt->rx_mbuf = &chan->in_mbuf; + + chan = &sc->sc_chan[HSCX_CH_B]; + lt = &chan->isdn_linktab; + + lt->unit = sc->sc_unit; + lt->channel = HSCX_CH_B; + lt->bch_config = isic_bchannel_setup; + lt->bch_tx_start = isic_bchannel_start; + lt->bch_stat = isic_bchannel_stat; + lt->tx_queue = &chan->tx_queue; + + /* used by non-HDLC data transfers, i.e. telephony drivers */ + lt->rx_queue = &chan->rx_queue; + + /* used by HDLC data transfers, i.e. ipr and isp drivers */ + lt->rx_mbuf = &chan->in_mbuf; +} + +/*---------------------------------------------------------------------------* + * telephony silence detection + *---------------------------------------------------------------------------*/ + +#define TEL_IDLE_MIN (BCH_MAX_DATALEN/2) + +int +isic_hscx_silence(unsigned char *data, int len) +{ + register int i = 0; + register int j = 0; + + /* count idle bytes */ + + for(;i < len; i++) + { + if((*data >= 0xaa) && (*data <= 0xac)) + j++; + data++; + } + +#ifdef NOTDEF + printf("isic_hscx_silence: got %d silence bytes in frame\n", j); +#endif + + if(j < (TEL_IDLE_MIN)) + return(0); + else + return(1); + +} + diff --git a/sys/dev/ic/i4b_isicl1.c b/sys/dev/ic/i4b_isicl1.c new file mode 100644 index 00000000000..e6503f55d48 --- /dev/null +++ b/sys/dev/ic/i4b_isicl1.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 1997, 2000 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. + * + *--------------------------------------------------------------------------- + * + * i4b_l1.c - isdn4bsd layer 1 handler + * ----------------------------------- + * + * $Id: i4b_isicl1.c,v 1.1.1.1 2001/01/05 12:50:12 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:36:11 2001] + * + *---------------------------------------------------------------------------*/ + +#include <sys/param.h> +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <machine/stdarg.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#ifndef __bsdi__ +#include <machine/bus.h> +#endif +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#include <netisdn/i4b_trace.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> +#include <netisdn/i4b_global.h> + +unsigned int i4b_l1_debug = L1_DEBUG_DEFAULT; + +static int ph_data_req(int, struct mbuf *, int); +static int ph_activate_req(int); + +/* from i4btrc driver i4b_trace.c */ +extern int get_trace_data_from_l1(int unit, int what, int len, char *buf); + +/* from layer 2 */ +extern int i4b_ph_data_ind(int unit, struct mbuf *m); +extern int i4b_ph_activate_ind(int unit); +extern int i4b_ph_deactivate_ind(int unit); +extern int i4b_mph_status_ind(int, int, int); + +/* layer 1 lme */ +static int i4b_mph_command_req(int, int, void*); + +/* jump table */ +struct i4b_l1l2_func i4b_l1l2_func = { + + /* Layer 1 --> Layer 2 */ + + (int (*)(int, struct mbuf *)) i4b_ph_data_ind, + (int (*)(int)) i4b_ph_activate_ind, + (int (*)(int)) i4b_ph_deactivate_ind, + + /* Layer 2 --> Layer 1 */ + + (int (*)(int, struct mbuf *, int)) ph_data_req, + (int (*)(int)) ph_activate_req, + + /* Layer 1 --> upstream, ISDN trace data */ + + (int (*)(i4b_trace_hdr_t *, int, u_char *)) get_trace_data_from_l1, + + /* Driver control and status information */ + + (int (*)(int, int, int)) i4b_mph_status_ind, + (int (*)(int, int, void*)) i4b_mph_command_req, +}; + +/*---------------------------------------------------------------------------* + * + * L2 -> L1: PH-DATA-REQUEST + * ========================= + * + * parms: + * unit physical interface unit number + * m mbuf containing L2 frame to be sent out + * freeflag MBUF_FREE: free mbuf here after having sent + * it out + * MBUF_DONTFREE: mbuf is freed by Layer 2 + * returns: + * ==0 fail, nothing sent out + * !=0 ok, frame sent out + * + *---------------------------------------------------------------------------*/ +static int +ph_data_req(int unit, struct mbuf *m, int freeflag) +{ + u_char cmd; + int s; + +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + +#ifdef NOTDEF + NDBGL1(L1_PRIM, "PH-DATA-REQUEST, unit %d, freeflag=%d", unit, freeflag); +#endif + + if(m == NULL) /* failsafe */ + return (0); + + s = SPLI4B(); + + if(sc->sc_I430state == ST_F3) /* layer 1 not running ? */ + { + NDBGL1(L1_I_ERR, "still in state F3!"); + ph_activate_req(unit); + } + + if(sc->sc_state & ISAC_TX_ACTIVE) + { + if(sc->sc_obuf2 == NULL) + { + sc->sc_obuf2 = m; /* save mbuf ptr */ + + if(freeflag) + sc->sc_freeflag2 = 1; /* IRQ must mfree */ + else + sc->sc_freeflag2 = 0; /* IRQ must not mfree */ + + NDBGL1(L1_I_MSG, "using 2nd ISAC TX buffer, state = %s", isic_printstate(sc)); + + if(sc->sc_trace & TRACE_D_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = unit; + hdr.type = TRC_CH_D; + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, m->m_len, m->m_data); + } + splx(s); + return(1); + } + + NDBGL1(L1_I_ERR, "No Space in TX FIFO, state = %s", isic_printstate(sc)); + + if(freeflag == MBUF_FREE) + i4b_Dfreembuf(m); + + splx(s); + return (0); + } + + if(sc->sc_trace & TRACE_D_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = unit; + hdr.type = TRC_CH_D; + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, m->m_len, m->m_data); + } + + sc->sc_state |= ISAC_TX_ACTIVE; /* set transmitter busy flag */ + + NDBGL1(L1_I_MSG, "ISAC_TX_ACTIVE set"); + + sc->sc_freeflag = 0; /* IRQ must NOT mfree */ + + ISAC_WRFIFO(m->m_data, min(m->m_len, ISAC_FIFO_LEN)); /* output to TX fifo */ + + if(m->m_len > ISAC_FIFO_LEN) /* message > 32 bytes ? */ + { + sc->sc_obuf = m; /* save mbuf ptr */ + sc->sc_op = m->m_data + ISAC_FIFO_LEN; /* ptr for irq hdl */ + sc->sc_ol = m->m_len - ISAC_FIFO_LEN; /* length for irq hdl */ + + if(freeflag) + sc->sc_freeflag = 1; /* IRQ must mfree */ + + cmd = ISAC_CMDR_XTF; + } + else + { + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + + if(freeflag) + i4b_Dfreembuf(m); + + cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; + } + + ISAC_WRITE(I_CMDR, cmd); + ISACCMDRWRDELAY(); + + splx(s); + + return(1); +} + +/*---------------------------------------------------------------------------* + * + * L2 -> L1: PH-ACTIVATE-REQUEST + * ============================= + * + * parms: + * unit physical interface unit number + * + * returns: + * ==0 + * !=0 + * + *---------------------------------------------------------------------------*/ +static int +ph_activate_req(int unit) +{ + +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + + NDBGL1(L1_PRIM, "unit %d", unit); + isic_next_state(sc, EV_PHAR); + return(0); +} + +/*---------------------------------------------------------------------------* + * command from the upper layers + *---------------------------------------------------------------------------*/ +static int +i4b_mph_command_req(int unit, int command, void *parm) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + + switch(command) + { + case CMR_DOPEN: /* daemon running */ + NDBGL1(L1_PRIM, "unit %d, command = CMR_DOPEN", unit); + sc->sc_enabled = 1; + break; + + case CMR_DCLOSE: /* daemon not running */ + NDBGL1(L1_PRIM, "unit %d, command = CMR_DCLOSE", unit); + sc->sc_enabled = 0; + break; + + case CMR_SETTRACE: + NDBGL1(L1_PRIM, "unit %d, command = CMR_SETTRACE, parm = %p", unit, parm); + sc->sc_trace = (unsigned int)parm; + break; + + default: + NDBGL1(L1_ERROR, "ERROR, unknown command = %d, unit = %d, parm = %p", command, unit, parm); + break; + } + + return(0); +} diff --git a/sys/dev/ic/i4b_isicl1.h b/sys/dev/ic/i4b_isicl1.h new file mode 100644 index 00000000000..235d45c0cf5 --- /dev/null +++ b/sys/dev/ic/i4b_isicl1.h @@ -0,0 +1,528 @@ +/* + * Copyright (c) 1997, 2000 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. + * + *---------------------------------------------------------------------------* + * + * i4b_l1.h - isdn4bsd layer 1 header file + * --------------------------------------- + * + * $Id: i4b_isicl1.h,v 1.1.1.1 2001/01/05 12:50:13 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:36:11 2001] + * + *---------------------------------------------------------------------------*/ + +#ifndef I4B_L1_H_ +#define I4B_L1_H_ + +#ifdef __bsdi__ +#include <sys/device.h> /* XXX */ +#ifndef ISA_NPORT_CHECK /* Double yuck XXX */ +#include <i386/isa/isavar.h> /* XXX */ +#endif +#endif + +#include <netisdn/i4b_l3l4.h> + +#define ISIC_MAXUNIT 4 + +/*--------------------------------------------------------------------------- + * kernel config file flags definition + *---------------------------------------------------------------------------*/ +#define FLAG_TELES_S0_8 1 +#define FLAG_TELES_S0_16 2 +#define FLAG_TELES_S0_163 3 +#define FLAG_AVM_A1 4 +#define FLAG_TELES_S0_163_PnP 5 +#define FLAG_CREATIX_S0_PnP 6 +#define FLAG_USR_ISDN_TA_INT 7 +#define FLAG_DRN_NGO 8 +#define FLAG_SWS 9 +#define FLAG_AVM_A1_PCMCIA 10 +#define FLAG_DYNALINK 11 +#define FLAG_BLMASTER 12 +#define FLAG_ELSA_QS1P_ISA 13 +#define FLAG_ELSA_QS1P_PCI 14 +#define FLAG_SIEMENS_ITALK 15 +#define FLAG_ELSA_MLIMC 16 +#define FLAG_ELSA_MLMCALL 17 +#define FLAG_ITK_IX1 18 +#define FLAG_AVMA1PCI 19 +#define FLAG_ELSA_PCC16 20 +#define FLAG_AVM_PNP 21 +#define FLAG_SIEMENS_ISURF2 22 +#define FLAG_ASUSCOM_IPAC 23 + +#define SEC_DELAY 1000000 /* one second DELAY for DELAY*/ + +#define MAX_DFRAME_LEN 264 /* max length of a D frame */ + +#ifndef __bsdi__ +#define min(a,b) ((a)<(b)?(a):(b)) +#endif + +#if !defined(__FreeBSD__) && !defined(__bsdi__) +/* We try to map as few as possible as small as possible io and/or + memory regions. Each card defines its own interpretation of this + mapping array. At probe time we have a fixed size array, later + (when the card type is known) we allocate a minimal array + dynamically. */ + +#define ISIC_MAX_IO_MAPS 49 /* no cardtype needs more yet */ + +/* one entry in mapping array */ +struct isic_io_map { + bus_space_tag_t t; /* which bus-space is this? */ + bus_space_handle_t h; /* handle of mapped bus space region */ + bus_size_t offset; /* offset into region */ + bus_size_t size; /* size of region, zero if not ours + (i.e.: don't ever unmap it!) */ +}; + +/* this is passed around at probe time (no struct l1_softc yet) */ +struct isic_attach_args { + int ia_flags; /* flags from config file */ + int ia_num_mappings; /* number of io mappings provided */ + struct isic_io_map ia_maps[ISIC_MAX_IO_MAPS]; +}; +#endif + +#ifdef __FreeBSD__ +extern int next_isic_unit; +#endif + +/*---------------------------------------------------------------------------* + * isic_Bchan: the state of one B channel + *---------------------------------------------------------------------------*/ +typedef struct +{ + int unit; /* cards unit number */ + int channel; /* which channel is this*/ + +#if defined(__FreeBSD__) || defined(__bsdi__) + caddr_t hscx; /* HSCX address */ +#endif + + u_char hscx_mask; /* HSCX interrupt mask */ + + int bprot; /* B channel protocol */ + + int state; /* this channels state */ +#define HSCX_IDLE 0x00 /* channel idle */ +#define HSCX_TX_ACTIVE 0x01 /* tx running */ + + /* receive data from ISDN */ + + struct ifqueue rx_queue; /* receiver queue */ + + int rxcount; /* rx statistics counter*/ + + struct mbuf *in_mbuf; /* rx input buffer */ + u_char *in_cbptr; /* curr buffer pointer */ + int in_len; /* rx input buffer len */ + + /* transmit data to ISDN */ + + struct ifqueue tx_queue; /* transmitter queue */ + + int txcount; /* tx statistics counter*/ + + struct mbuf *out_mbuf_head; /* first mbuf in possible chain */ + struct mbuf *out_mbuf_cur; /* current mbuf in possbl chain */ + unsigned char *out_mbuf_cur_ptr; /* data pointer into mbuf */ + int out_mbuf_cur_len; /* remaining bytes in mbuf */ + + /* link between b channel and driver */ + + isdn_link_t isdn_linktab; /* b channel addresses */ + drvr_link_t *drvr_linktab; /* ptr to driver linktab*/ + + /* statistics */ + + /* RSTA */ + + int stat_VFR; /* HSCX RSTA Valid FRame */ + int stat_RDO; /* HSCX RSTA Rx Data Overflow */ + int stat_CRC; /* HSCX RSTA CRC */ + int stat_RAB; /* HSCX RSTA Rx message ABorted */ + + /* EXIR */ + + int stat_XDU; /* HSCX EXIR tx data underrun */ + int stat_RFO; /* HSCX EXIR rx frame overflow */ + +} l1_bchan_state_t; + +/*---------------------------------------------------------------------------* + * l1_softc: the state of the layer 1 of the D channel + *---------------------------------------------------------------------------*/ +struct l1_softc +{ +#if !defined(__FreeBSD__) + /* We are inherited from this class. All drivers must have this + as their first entry in struct softc. */ + struct device sc_dev; +#endif + + int sc_unit; /* unit number */ + int sc_irq; /* interrupt vector */ + +#ifdef __FreeBSD__ + int sc_port; /* port base address */ +#elif defined(__bsdi__) + struct isadev sc_id; /* ISA/PCI device */ + struct intrhand sc_ih; /* interrupt vectoring */ + int sc_flags; + int sc_port; + caddr_t sc_maddr; + int sc_abustype; /* PCI, ISA etcetera */ +#else + u_int sc_maddr; /* "memory address" for card config register */ + int sc_num_mappings; /* number of io mappings provided */ + struct isic_io_map *sc_maps; + +#define MALLOC_MAPS(sc) \ + (sc)->sc_maps = (struct isic_io_map*)malloc(sizeof((sc)->sc_maps[0])*(sc)->sc_num_mappings, M_DEVBUF, 0) +#endif + + int sc_cardtyp; /* CARD_TYPEP_xxxx */ + + int sc_bustyp; /* IOM1 or IOM2 */ +#define BUS_TYPE_IOM1 0x01 +#define BUS_TYPE_IOM2 0x02 + + int sc_trace; /* output protocol data for tracing */ + unsigned int sc_trace_dcount;/* d channel trace frame counter */ + unsigned int sc_trace_bcount;/* b channel trace frame counter */ + + int sc_state; /* ISAC state flag */ +#define ISAC_IDLE 0x00 /* state = idle */ +#define ISAC_TX_ACTIVE 0x01 /* state = transmitter active */ + + int sc_init_tries; /* no of out tries to access S0 */ + +#if defined(__FreeBSD__) || defined(__bsdi__) + caddr_t sc_vmem_addr; /* card RAM virtual memory base */ + caddr_t sc_isac; /* ISAC port base addr */ +#define ISAC_BASE (sc->sc_isac) + + caddr_t sc_ipacbase; /* IPAC port base addr */ +#define IPAC_BASE (sc->sc_ipacbase) +#endif + + u_char sc_isac_mask; /* ISAC IRQ mask */ +#define ISAC_IMASK (sc->sc_isac_mask) + + l1_bchan_state_t sc_chan[2]; /* B-channel state */ +#define HSCX_A_BASE (sc->sc_chan[0].hscx) +#define HSCX_A_IMASK (sc->sc_chan[0].hscx_mask) +#define HSCX_B_BASE (sc->sc_chan[1].hscx) +#define HSCX_B_IMASK (sc->sc_chan[1].hscx_mask) + + struct mbuf *sc_ibuf; /* input buffer mgmt */ + u_short sc_ilen; + u_char *sc_ib; + /* this is for the irq TX routine */ + struct mbuf *sc_obuf; /* pointer to an mbuf with TX frame */ + u_char *sc_op; /* ptr to next chunk of frame to tx */ + int sc_ol; /* length of remaining frame to tx */ + int sc_freeflag; /* m_freem mbuf if set */ + + struct mbuf *sc_obuf2; /* pointer to an mbuf with TX frame */ + int sc_freeflag2; /* m_freem mbuf if set */ + + int sc_isac_version; /* version number of ISAC */ + int sc_hscx_version; /* version number of HSCX */ + int sc_ipac_version; /* version number of IPAC */ + + int sc_I430state; /* I.430 state F3 .... F8 */ + + int sc_I430T3; /* I.430 Timer T3 running */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + struct callout_handle sc_T3_callout; +#endif +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 + struct callout sc_T3_callout; +#endif + + int sc_I430T4; /* Timer T4 running */ + +#if defined(__FreeBSD__) && __FreeBSD__ >=3 + struct callout_handle sc_T4_callout; +#endif +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 + struct callout sc_T4_callout; +#endif + + /* + * byte fields for the AVM Fritz!Card PCI. These are packed into + * a u_int in the driver. + */ + u_char avma1pp_cmd; + u_char avma1pp_txl; + u_char avma1pp_prot; + + int sc_enabled; /* daemon is running */ + + int sc_ipac; /* flag, running on ipac */ + int sc_bfifolen; /* length of b channel fifos */ + +#if defined(__FreeBSD__) || defined(__bsdi__) + + u_char (*readreg)(u_char *, u_int); + void (*writereg)(u_char *, u_int, u_int); + void (*readfifo)(void *, const void *, size_t); + void (*writefifo)(void *, const void *, size_t); + void (*clearirq)(void *); + +#define ISAC_READ(r) (*sc->readreg)(ISAC_BASE, (r)) +#define ISAC_WRITE(r,v) (*sc->writereg)(ISAC_BASE, (r), (v)); +#define ISAC_RDFIFO(b,s) (*sc->readfifo)((b), ISAC_BASE, (s)) +#define ISAC_WRFIFO(b,s) (*sc->writefifo)(ISAC_BASE, (b), (s)) + +#define HSCX_READ(n,r) (*sc->readreg)(sc->sc_chan[(n)].hscx, (r)) +#define HSCX_WRITE(n,r,v) (*sc->writereg)(sc->sc_chan[(n)].hscx, (r), (v)) +#define HSCX_RDFIFO(n,b,s) (*sc->readfifo)((b), sc->sc_chan[(n)].hscx, (s)) +#define HSCX_WRFIFO(n,b,s) (*sc->writefifo)(sc->sc_chan[(n)].hscx, (b), (s)) + +#define IPAC_READ(r) (*sc->readreg)(IPAC_BASE, (r)) +#define IPAC_WRITE(r,v) (*sc->writereg)(IPAC_BASE, (r), (v)); + +#else /* ! __FreeBSD__ */ + +#define ISIC_WHAT_ISAC 0 +#define ISIC_WHAT_HSCXA 1 +#define ISIC_WHAT_HSCXB 2 +#define ISIC_WHAT_IPAC 3 + + u_int8_t (*readreg) __P((struct l1_softc *sc, int what, bus_size_t offs)); + void (*writereg) __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); + void (*readfifo) __P((struct l1_softc *sc, int what, void *buf, size_t size)); + void (*writefifo) __P((struct l1_softc *sc, int what, const void *data, size_t size)); + void (*clearirq) __P((struct l1_softc *sc)); + +#define ISAC_READ(r) (*sc->readreg)(sc, ISIC_WHAT_ISAC, (r)) +#define ISAC_WRITE(r,v) (*sc->writereg)(sc, ISIC_WHAT_ISAC, (r), (v)) +#define ISAC_RDFIFO(b,s) (*sc->readfifo)(sc, ISIC_WHAT_ISAC, (b), (s)) +#define ISAC_WRFIFO(b,s) (*sc->writefifo)(sc, ISIC_WHAT_ISAC, (b), (s)) + +#define HSCX_READ(n,r) (*sc->readreg)(sc, ISIC_WHAT_HSCXA+(n), (r)) +#define HSCX_WRITE(n,r,v) (*sc->writereg)(sc, ISIC_WHAT_HSCXA+(n), (r), (v)) +#define HSCX_RDFIFO(n,b,s) (*sc->readfifo)(sc, ISIC_WHAT_HSCXA+(n), (b), (s)) +#define HSCX_WRFIFO(n,b,s) (*sc->writefifo)(sc, ISIC_WHAT_HSCXA+(n), (b), (s)) + +#define IPAC_READ(r) (*sc->readreg)(sc, ISIC_WHAT_IPAC, (r)) +#define IPAC_WRITE(r, v) (*sc->writereg)(sc, ISIC_WHAT_IPAC, (r), (v)) + +#endif /* __FreeBSD__ */ +}; + +/*---------------------------------------------------------------------------* + * possible I.430/ISAC states + *---------------------------------------------------------------------------*/ +enum I430states { + ST_F3, /* F3 Deactivated */ + ST_F4, /* F4 Awaiting Signal */ + ST_F5, /* F5 Identifying Input */ + ST_F6, /* F6 Synchronized */ + ST_F7, /* F7 Activated */ + ST_F8, /* F8 Lost Framing */ + ST_ILL, /* Illegal State */ + N_STATES +}; + +/*---------------------------------------------------------------------------* + * possible I.430/ISAC events + *---------------------------------------------------------------------------*/ +enum I430events { + EV_PHAR, /* PH ACTIVATE REQUEST */ + EV_T3, /* Timer 3 expired */ + EV_INFO0, /* receiving INFO0 */ + EV_RSY, /* receiving any signal */ + EV_INFO2, /* receiving INFO2 */ + EV_INFO48, /* receiving INFO4 pri 8/9 */ + EV_INFO410, /* receiving INFO4 pri 10/11 */ + EV_DR, /* Deactivate Request */ + EV_PU, /* Power UP */ + EV_DIS, /* Disconnected (only 2085) */ + EV_EI, /* Error Indication */ + EV_ILL, /* Illegal Event */ + N_EVENTS +}; + +enum I430commands { + CMD_TIM, /* Timing */ + CMD_RS, /* Reset */ + CMD_AR8, /* Activation request pri 8 */ + CMD_AR10, /* Activation request pri 10 */ + CMD_DIU, /* Deactivate Indication Upstream */ + CMD_ILL /* Illegal command */ +}; + +#define N_COMMANDS CMD_ILL + +#ifdef __FreeBSD__ + +extern struct l1_softc l1_sc[]; + +extern void isic_recover(struct l1_softc *sc); +extern int isic_realattach(struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_avma1 ( struct isa_device *dev ); +extern int isic_attach_fritzpcmcia ( struct isa_device *dev ); +extern int isic_attach_Cs0P ( struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_Dyn ( struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_s016 ( struct isa_device *dev ); +extern int isic_attach_s0163 ( struct isa_device *dev ); +extern int isic_attach_s0163P ( struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_s08 ( struct isa_device *dev ); +extern int isic_attach_usrtai ( struct isa_device *dev ); +extern int isic_attach_itkix1 ( struct isa_device *dev ); +extern int isic_attach_drnngo ( struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_sws ( struct isa_device *dev ); +extern int isic_attach_Eqs1pi(struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_avm_pnp(struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_siemens_isurf(struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_Eqs1pp(int unit, unsigned int iobase1, unsigned int iobase2); +extern int isic_attach_asi(struct isa_device *dev, unsigned int iobase2); +extern void isic_bchannel_setup (int unit, int hscx_channel, int bprot, int activate ); +extern int isic_hscx_fifo(l1_bchan_state_t *, struct l1_softc *); +extern void isic_hscx_init ( struct l1_softc *sc, int hscx_channel, int activate ); +extern void isic_hscx_irq ( struct l1_softc *sc, u_char ista, int hscx_channel, u_char ex_irq ); +extern int isic_hscx_silence ( unsigned char *data, int len ); +extern void isic_hscx_cmd( struct l1_softc *sc, int h_chan, unsigned char cmd ); +extern void isic_hscx_waitxfw( struct l1_softc *sc, int h_chan ); +extern void isic_init_linktab ( struct l1_softc *sc ); +extern int isic_isac_init ( struct l1_softc *sc ); +extern void isic_isac_irq ( struct l1_softc *sc, int r ); +extern void isic_isac_l1_cmd ( struct l1_softc *sc, int command ); +extern void isic_next_state ( struct l1_softc *sc, int event ); +extern char *isic_printstate ( struct l1_softc *sc ); +extern int isic_probe_avma1 ( struct isa_device *dev ); +extern int isic_probe_avma1_pcmcia ( struct isa_device *dev ); +extern int isic_probe_avm_pnp ( struct isa_device *dev, unsigned int iobase2); +extern int isic_probe_siemens_isurf ( struct isa_device *dev, unsigned int iobase2); +extern int isic_probe_Cs0P ( struct isa_device *dev, unsigned int iobase2); +extern int isic_probe_Dyn ( struct isa_device *dev, unsigned int iobase2); +extern int isic_probe_s016 ( struct isa_device *dev ); +extern int isic_probe_s0163 ( struct isa_device *dev ); +extern int isic_probe_s0163P ( struct isa_device *dev, unsigned int iobase2); +extern int isic_probe_s08 ( struct isa_device *dev ); +extern int isic_probe_usrtai ( struct isa_device *dev ); +extern int isic_probe_itkix1 ( struct isa_device *dev ); +extern int isic_probe_drnngo ( struct isa_device *dev, unsigned int iobase2); +extern int isic_probe_sws ( struct isa_device *dev ); +extern int isic_probe_Eqs1pi(struct isa_device *dev, unsigned int iobase2); +extern int isic_probe_asi(struct isa_device *dev, unsigned int iobase2); + +#elif defined(__bsdi__) + +extern struct l1_softc *l1_sc[]; +#define isic_find_sc(unit) (l1_sc[(unit)]) + +#define ATTACHARGS struct device *, struct device *, struct isa_attach_args * +#define MATCHARGS struct device *, struct cfdata *, struct isa_attach_args * +extern int isa_isicmatch(MATCHARGS); +extern int isa_isicattach(ATTACHARGS); +extern int isicintr(void *); +extern void isic_recover(struct l1_softc *sc); +extern int isic_realattach(ATTACHARGS); +extern int isic_attach_avma1(ATTACHARGS); +extern int isic_attach_fritzpcmcia(ATTACHARGS); +extern int isic_attach_Cs0P(ATTACHARGS); +extern int isic_attach_Dyn(ATTACHARGS); +extern int isic_attach_s016(ATTACHARGS); +extern int isic_attach_s0163(ATTACHARGS); +extern int isic_attach_s0163P(ATTACHARGS); +extern int isic_attach_s08(ATTACHARGS); +extern int isic_attach_usrtai(ATTACHARGS); +extern int isic_attach_itkix1(ATTACHARGS); +extern int isic_attach_drnngo(ATTACHARGS); +extern int isic_attach_sws(ATTACHARGS); +extern int isic_attach_Eqs1pi(ATTACHARGS); +extern int isic_attach_Eqs1pp(ATTACHARGS); +extern void isic_bchannel_setup(int unit, int hscx_channel, int bprot, int activate ); +extern void isic_hscx_init(struct l1_softc *sc, int hscx_channel, int activate ); +extern void isic_hscx_irq(struct l1_softc *sc, u_char ista, int hscx_channel, u_char ex_irq ); +extern int isic_hscx_silence(unsigned char *data, int len ); +extern void isic_hscx_cmd(struct l1_softc *sc, int h_chan, unsigned char cmd ); +extern void isic_hscx_waitxfw(struct l1_softc *sc, int h_chan ); +extern void isic_init_linktab(struct l1_softc *sc ); +extern int isic_isac_init(struct l1_softc *sc ); +extern void isic_isac_irq(struct l1_softc *sc, int r ); +extern void isic_isac_l1_cmd(struct l1_softc *sc, int command ); +extern void isic_next_state(struct l1_softc *sc, int event ); +extern char *isic_printstate(struct l1_softc *sc ); +extern int isic_probe_avma1(MATCHARGS); +extern int isic_probe_avma1_pcmcia(MATCHARGS); +extern int isic_probe_Cs0P(MATCHARGS); +extern int isic_probe_Dyn(MATCHARGS); +extern int isic_probe_s016(MATCHARGS); +extern int isic_probe_s0163(MATCHARGS); +extern int isic_probe_s0163P(MATCHARGS); +extern int isic_probe_s08(MATCHARGS); +extern int isic_probe_usrtai(MATCHARGS); +extern int isic_probe_itkix1(MATCHARGS); +extern int isic_probe_drnngo(MATCHARGS); +extern int isic_probe_sws(MATCHARGS); +extern int isic_probe_Eqs1pi(MATCHARGS); + +#undef MATCHARGS +#undef ATTACHARGS +#else /* not FreeBSD/__bsdi__ */ + +extern void isic_recover __P((struct l1_softc *sc)); +extern int isicintr __P((void *)); +extern int isicprobe __P((struct isic_attach_args *ia)); +extern int isic_attach_avma1 __P((struct l1_softc *sc)); +extern int isic_attach_s016 __P((struct l1_softc *sc)); +extern int isic_attach_s0163 __P((struct l1_softc *sc)); +extern int isic_attach_s08 __P((struct l1_softc *sc)); +extern int isic_attach_usrtai __P((struct l1_softc *sc)); +extern int isic_attach_itkix1 __P((struct l1_softc *sc)); +extern void isic_bchannel_setup __P((int unit, int hscx_channel, int bprot, int activate)); +extern void isic_hscx_init __P((struct l1_softc *sc, int hscx_channel, int activate)); +extern void isic_hscx_irq __P((struct l1_softc *sc, u_char ista, int hscx_channel, u_char ex_irq)); +extern int isic_hscx_silence __P(( unsigned char *data, int len )); +extern void isic_hscx_cmd __P(( struct l1_softc *sc, int h_chan, unsigned char cmd )); +extern void isic_hscx_waitxfw __P(( struct l1_softc *sc, int h_chan )); +extern void isic_init_linktab __P((struct l1_softc *sc)); +extern int isic_isac_init __P((struct l1_softc *sc)); +extern void isic_isac_irq __P((struct l1_softc *sc, int r)); +extern void isic_isac_l1_cmd __P((struct l1_softc *sc, int command)); +extern void isic_next_state __P((struct l1_softc *sc, int event)); +extern char * isic_printstate __P((struct l1_softc *sc)); +extern int isic_probe_avma1 __P((struct isic_attach_args *ia)); +extern int isic_probe_s016 __P((struct isic_attach_args *ia)); +extern int isic_probe_s0163 __P((struct isic_attach_args *ia)); +extern int isic_probe_s08 __P((struct isic_attach_args *ia)); +extern int isic_probe_usrtai __P((struct isic_attach_args *ia)); +extern int isic_probe_itkix1 __P((struct isic_attach_args *ia)); + +extern struct l1_softc *l1_sc[]; + +#define isic_find_sc(unit) (l1_sc[(unit)]) + +#endif /* __FreeBSD__ */ + +#endif /* I4B_L1_H_ */ diff --git a/sys/dev/ic/i4b_isicl1fsm.c b/sys/dev/ic/i4b_isicl1fsm.c new file mode 100644 index 00000000000..ac5c2ffe9e5 --- /dev/null +++ b/sys/dev/ic/i4b_isicl1fsm.c @@ -0,0 +1,531 @@ +/* + * Copyright (c) 1997, 2000 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. + * + *--------------------------------------------------------------------------- + * + * i4b_l1fsm.c - isdn4bsd layer 1 I.430 state machine + * -------------------------------------------------- + * + * $Id: i4b_isicl1fsm.c,v 1.1.1.1 2001/01/05 12:50:13 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:36:11 2001] + * + *---------------------------------------------------------------------------*/ + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#include <machine/stdarg.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#ifndef __bsdi__ +#include <machine/bus.h> +#endif +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + + +static char *state_text[N_STATES] = { + "F3 Deactivated", + "F4 Awaiting Signal", + "F5 Identifying Input", + "F6 Synchronized", + "F7 Activated", + "F8 Lost Framing", + "Illegal State" +}; + +static char *event_text[N_EVENTS] = { + "EV_PHAR PH_ACT_REQ", + "EV_T3 Timer 3 expired", + "EV_INFO0 INFO0 received", + "EV_RSY Level Detected", + "EV_INFO2 INFO2 received", + "EV_INFO48 INFO4 received", + "EV_INFO410 INFO4 received", + "EV_DR Deactivate Req", + "EV_PU Power UP", + "EV_DIS Disconnected", + "EV_EI Error Ind", + "Illegal Event" +}; + +/* Function prototypes */ + +static void timer3_expired (struct l1_softc *sc); +static void T3_start (struct l1_softc *sc); +static void T3_stop (struct l1_softc *sc); +static void F_T3ex (struct l1_softc *sc); +static void timer4_expired (struct l1_softc *sc); +static void T4_start (struct l1_softc *sc); +static void T4_stop (struct l1_softc *sc); +static void F_AI8 (struct l1_softc *sc); +static void F_AI10 (struct l1_softc *sc); +static void F_I01 (struct l1_softc *sc); +static void F_I02 (struct l1_softc *sc); +static void F_I03 (struct l1_softc *sc); +static void F_I2 (struct l1_softc *sc); +static void F_ill (struct l1_softc *sc); +static void F_NULL (struct l1_softc *sc); + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 expire function + *---------------------------------------------------------------------------*/ +static void +timer3_expired(struct l1_softc *sc) +{ + if(sc->sc_I430T3) + { + NDBGL1(L1_T_ERR, "state = %s", isic_printstate(sc)); + sc->sc_I430T3 = 0; + + /* XXX try some recovery here XXX */ + + isic_recover(sc); + + sc->sc_init_tries++; /* increment retry count */ + +/*XXX*/ if(sc->sc_init_tries > 4) + { + int s = SPLI4B(); + + sc->sc_init_tries = 0; + + if(sc->sc_obuf2 != NULL) + { + i4b_Dfreembuf(sc->sc_obuf2); + sc->sc_obuf2 = NULL; + } + if(sc->sc_obuf != NULL) + { + i4b_Dfreembuf(sc->sc_obuf); + sc->sc_obuf = NULL; + sc->sc_freeflag = 0; + sc->sc_op = NULL; + sc->sc_ol = 0; + } + + splx(s); + + MPH_Status_Ind(sc->sc_unit, STI_NOL1ACC, 0); + } + + isic_next_state(sc, EV_T3); + } + else + { + NDBGL1(L1_T_ERR, "expired without starting it ...."); + } +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 start + *---------------------------------------------------------------------------*/ +static void +T3_start(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc)); + sc->sc_I430T3 = 1; + + START_TIMER(sc->sc_T3_callout, timer3_expired, sc, 2*hz); +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 stop + *---------------------------------------------------------------------------*/ +static void +T3_stop(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc)); + + sc->sc_init_tries = 0; /* init connect retry count */ + + if(sc->sc_I430T3) + { + sc->sc_I430T3 = 0; + STOP_TIMER(sc->sc_T3_callout, timer3_expired, sc); + } +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 expiry + *---------------------------------------------------------------------------*/ +static void +F_T3ex(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_T3ex executing"); + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + PH_Deact_Ind(sc->sc_unit); +} + +/*---------------------------------------------------------------------------* + * Timer T4 expire function + *---------------------------------------------------------------------------*/ +static void +timer4_expired(struct l1_softc *sc) +{ + if(sc->sc_I430T4) + { + NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc)); + sc->sc_I430T4 = 0; + MPH_Status_Ind(sc->sc_unit, STI_PDEACT, 0); + } + else + { + NDBGL1(L1_T_ERR, "expired without starting it ...."); + } +} + +/*---------------------------------------------------------------------------* + * Timer T4 start + *---------------------------------------------------------------------------*/ +static void +T4_start(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc)); + sc->sc_I430T4 = 1; + + START_TIMER(sc->sc_T4_callout, timer4_expired, sc, hz); +} + +/*---------------------------------------------------------------------------* + * Timer T4 stop + *---------------------------------------------------------------------------*/ +static void +T4_stop(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc)); + + if(sc->sc_I430T4) + { + sc->sc_I430T4 = 0; + STOP_TIMER(sc->sc_T4_callout, timer4_expired, sc); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received AI8 + *---------------------------------------------------------------------------*/ +static void +F_AI8(struct l1_softc *sc) +{ + T4_stop(sc); + + NDBGL1(L1_F_MSG, "FSM function F_AI8 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + PH_Act_Ind(sc->sc_unit); + + T3_stop(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO4_8; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received AI10 + *---------------------------------------------------------------------------*/ +static void +F_AI10(struct l1_softc *sc) +{ + T4_stop(sc); + + NDBGL1(L1_F_MSG, "FSM function F_AI10 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + PH_Act_Ind(sc->sc_unit); + + T3_stop(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO4_10; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in states F3 .. F5 + *---------------------------------------------------------------------------*/ +static void +F_I01(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I01 executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in state F6 + *---------------------------------------------------------------------------*/ +static void +F_I02(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I02 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + PH_Deact_Ind(sc->sc_unit); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in state F7 or F8 + *---------------------------------------------------------------------------*/ +static void +F_I03(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I03 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + PH_Deact_Ind(sc->sc_unit); + + T4_start(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: activate request + *---------------------------------------------------------------------------*/ +static void +F_AR(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_AR executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO1_8; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_TE; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } + + isic_isac_l1_cmd(sc, CMD_AR8); + + T3_start(sc); +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO2 + *---------------------------------------------------------------------------*/ +static void +F_I2(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I2 executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO2; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } + +} + +/*---------------------------------------------------------------------------* + * illegal state default action + *---------------------------------------------------------------------------*/ +static void +F_ill(struct l1_softc *sc) +{ + NDBGL1(L1_F_ERR, "FSM function F_ill executing"); +} + +/*---------------------------------------------------------------------------* + * No action + *---------------------------------------------------------------------------*/ +static void +F_NULL(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_NULL executing"); +} + + +/*---------------------------------------------------------------------------* + * layer 1 state transition table + *---------------------------------------------------------------------------*/ +struct isic_state_tab { + void (*func) (struct l1_softc *sc); /* function to execute */ + int newstate; /* next state */ +} isic_state_tab[N_EVENTS][N_STATES] = { + +/* STATE: F3 F4 F5 F6 F7 F8 ILLEGAL STATE */ +/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* EV_PHAR x*/ {{F_AR, ST_F4}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_ill, ST_ILL}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_T3 x*/ {{F_NULL, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_INFO0 */ {{F_I01, ST_F3}, {F_I01, ST_F4}, {F_I01, ST_F5}, {F_I02, ST_F3}, {F_I03, ST_F3}, {F_I03, ST_F3}, {F_ill, ST_ILL}}, +/* EV_RSY x*/ {{F_NULL, ST_F3}, {F_NULL, ST_F5}, {F_NULL, ST_F5}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_INFO2 */ {{F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_ill, ST_ILL}}, +/* EV_INFO48*/ {{F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_NULL, ST_F7}, {F_AI8, ST_F7}, {F_ill, ST_ILL}}, +/* EV_INFO41*/ {{F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_NULL, ST_F7}, {F_AI10, ST_F7}, {F_ill, ST_ILL}}, +/* EV_DR */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_PU */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_DIS */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}, +/* EV_EI */ {{F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_ill, ST_ILL}}, +/* EV_ILL */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}} +}; + +/*---------------------------------------------------------------------------* + * event handler + *---------------------------------------------------------------------------*/ +void +isic_next_state(struct l1_softc *sc, int event) +{ + int currstate, newstate; + + if(event >= N_EVENTS) + panic("i4b_l1fsm.c: event >= N_EVENTS\n"); + + currstate = sc->sc_I430state; + + if(currstate >= N_STATES) + panic("i4b_l1fsm.c: currstate >= N_STATES\n"); + + newstate = isic_state_tab[event][currstate].newstate; + + if(newstate >= N_STATES) + panic("i4b_l1fsm.c: newstate >= N_STATES\n"); + + NDBGL1(L1_F_MSG, "FSM event [%s]: [%s => %s]", event_text[event], + state_text[currstate], + state_text[newstate]); + + (*isic_state_tab[event][currstate].func)(sc); + + if(newstate == ST_ILL) + { + newstate = ST_F3; + NDBGL1(L1_F_ERR, "FSM Illegal State ERROR, oldstate = %s, newstate = %s, event = %s!", + state_text[currstate], + state_text[newstate], + event_text[event]); + } + + sc->sc_I430state = newstate; +} + +/*---------------------------------------------------------------------------* + * return pointer to current state description + *---------------------------------------------------------------------------*/ +char * +isic_printstate(struct l1_softc *sc) +{ + return((char *) state_text[sc->sc_I430state]); +} + diff --git a/sys/dev/isa/i4b_avm_a1.c b/sys/dev/isa/i4b_avm_a1.c new file mode 100644 index 00000000000..9f080016160 --- /dev/null +++ b/sys/dev/isa/i4b_avm_a1.c @@ -0,0 +1,507 @@ +/* + * Copyright (c) 1996 Andrew Gordon. All rights reserved. + * + * Copyright (c) 1997, 1999 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * i4b_avm_a1.c - AVM A1/Fritz passive card driver for isdn4bsd + * ------------------------------------------------------------ + * + * $Id: i4b_avm_a1.c,v 1.1.1.1 2001/01/05 12:50:15 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:37:22 2001] + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicisa.h" +#ifdef ISICISA_AVM_A1 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <netisdn/i4b_global.h> + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#ifndef __FreeBSD__ +static u_int8_t avma1_read_reg __P((struct l1_softc *sc, int what, bus_size_t offs)); +static void avma1_write_reg __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void avma1_read_fifo __P((struct l1_softc *sc, int what, void *buf, size_t size)); +static void avma1_write_fifo __P((struct l1_softc *sc, int what, const void *data, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * AVM A1 and AVM Fritz! Card special registers + *---------------------------------------------------------------------------*/ + +#define AVM_CONF_REG 0x1800 /* base offset for config register */ +#define AVM_CONF_IRQ 0x1801 /* base offset for IRQ register */ + /* config register write */ +#define AVM_CONF_WR_RESET 0x01 /* 1 = RESET ISAC and HSCX */ +#define AVM_CONF_WR_CCL 0x02 /* 1 = clear counter low nibble */ +#define AVM_CONF_WR_CCH 0x04 /* 1 = clear counter high nibble */ +#define AVM_CONF_WR_IRQEN 0x08 /* 1 = enable IRQ */ +#define AVM_CONF_WR_TEST 0x10 /* test bit */ + /* config register read */ +#define AVM_CONF_RD_IIRQ 0x01 /* 0 = ISAC IRQ active */ +#define AVM_CONF_RD_HIRQ 0x02 /* 0 = HSCX IRQ active */ +#define AVM_CONF_RD_CIRQ 0x04 /* 0 = counter IRQ active */ +#define AVM_CONF_RD_ZER1 0x08 /* unused, always read 0 */ +#define AVM_CONF_RD_TEST 0x10 /* test bit read back */ +#define AVM_CONF_RD_ZER2 0x20 /* unused, always read 0 */ + +/*---------------------------------------------------------------------------* + * AVM read fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1_read_fifo(void *buf, const void *base, size_t len) +{ + insb((int)base - 0x3e0, (u_char *)buf, (u_int)len); +} +#else +static void +avma1_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+4].t; + bus_space_handle_t h = sc->sc_maps[what+4].h; + bus_space_read_multi_1(t, h, 0, buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM write fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1_write_fifo(void *base, const void *buf, size_t len) +{ + outsb((int)base - 0x3e0, (u_char *)buf, (u_int)len); +} +#else +static void +avma1_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+4].t; + bus_space_handle_t h = sc->sc_maps[what+4].h; + bus_space_write_multi_1(t, h, 0, (u_int8_t*)buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM write register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1_write_reg(u_char *base, u_int offset, u_int v) +{ + outb((int)base + offset, (u_char)v); +} +#else +static void +avma1_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_space_write_1(t, h, offs, data); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM read register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static u_char +avma1_read_reg(u_char *base, u_int offset) +{ + return (inb((int)base + offset)); +} +#else +static u_int8_t +avma1_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + return bus_space_read_1(t, h, offs); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_avma1 - probe for AVM A1 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_probe_avma1(struct isa_device *dev) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + u_char savebyte; + u_char byte; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for AVM A1/Fritz!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq)-1) + { + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for AVM A1/Fritz!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for AVM A1/Fritz!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + + dev->id_msize = 0; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0x200: + case 0x240: + case 0x300: + case 0x340: + break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for AVM A1/Fritz!\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + sc->clearirq = NULL; + sc->readreg = avma1_read_reg; + sc->writereg = avma1_write_reg; + + sc->readfifo = avma1_read_fifo; + sc->writefifo = avma1_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_AVMA1; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t)dev->id_iobase + 0x1400 - 0x20; + + HSCX_A_BASE = (caddr_t)dev->id_iobase + 0x400 - 0x20; + HSCX_B_BASE = (caddr_t)dev->id_iobase + 0xc00 - 0x20; + + /* + * Read HSCX A/B VSTR. + * Expected value for AVM A1 is 0x04 or 0x05 and for the + * AVM Fritz!Card is 0x05 in the least significant bits. + */ + + if( (((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(0, H_VSTR) & 0xf) != 0x4)) || + (((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x4)) ) + { + printf("isic%d: HSCX VSTR test failed for AVM A1/Fritz\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + /* AVM A1 or Fritz! control register bits: */ + /* read write */ + /* 0x01 hscx irq* RESET */ + /* 0x02 isac irq* clear counter1 */ + /* 0x04 counter irq* clear counter2 */ + /* 0x08 always 0 irq enable */ + /* 0x10 read test bit set test bit */ + /* 0x20 always 0 unused */ + + /* + * XXX the following test may be destructive, to prevent the + * worst case, we save the byte first, and in case the test + * fails, we write back the saved byte ..... + */ + + savebyte = inb(dev->id_iobase + AVM_CONF_REG); + + /* write low to test bit */ + + outb(dev->id_iobase + AVM_CONF_REG, 0x00); + + /* test bit and next higher and lower bit must be 0 */ + + if((byte = inb(dev->id_iobase + AVM_CONF_REG) & 0x38) != 0x00) + { + printf("isic%d: Error, probe-1 failed, 0x%02x should be 0x00 for AVM A1/Fritz!\n", + dev->id_unit, byte); + outb(dev->id_iobase + AVM_CONF_REG, savebyte); + return (0); + } + + /* write high to test bit */ + + outb(dev->id_iobase + AVM_CONF_REG, 0x10); + + /* test bit must be high, next higher and lower bit must be 0 */ + + if((byte = inb(dev->id_iobase + AVM_CONF_REG) & 0x38) != 0x10) + { + printf("isic%d: Error, probe-2 failed, 0x%02x should be 0x10 for AVM A1/Fritz!\n", + dev->id_unit, byte); + outb(dev->id_iobase + AVM_CONF_REG, savebyte); + return (0); + } + + return (1); +} + +#else + +int +isic_probe_avma1(struct isic_attach_args *ia) +{ + u_int8_t savebyte, v1, v2; + + /* + * Read HSCX A/B VSTR. + * Expected value for AVM A1 is 0x04 or 0x05 and for the + * AVM Fritz!Card is 0x05 in the least significant bits. + */ + + v1 = bus_space_read_1(ia->ia_maps[ISIC_WHAT_HSCXA+1].t, ia->ia_maps[ISIC_WHAT_HSCXA+1].h, H_VSTR) & 0x0f; + v2 = bus_space_read_1(ia->ia_maps[ISIC_WHAT_HSCXB+1].t, ia->ia_maps[ISIC_WHAT_HSCXB+1].h, H_VSTR) & 0x0f; + if (v1 != v2 || (v1 != 0x05 && v1 != 0x04)) + return 0; + + /* AVM A1 or Fritz! control register bits: */ + /* read write */ + /* 0x01 hscx irq* RESET */ + /* 0x02 isac irq* clear counter1 */ + /* 0x04 counter irq* clear counter2 */ + /* 0x08 always 0 irq enable */ + /* 0x10 read test bit set test bit */ + /* 0x20 always 0 unused */ + + /* + * XXX the following test may be destructive, to prevent the + * worst case, we save the byte first, and in case the test + * fails, we write back the saved byte ..... + */ + + savebyte = bus_space_read_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0); + + /* write low to test bit */ + + bus_space_write_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0, 0); + + /* test bit and next higher and lower bit must be 0 */ + + if((bus_space_read_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0) & 0x38) != 0x00) + { + bus_space_write_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0, savebyte); + return 0; + } + + /* write high to test bit */ + + bus_space_write_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0, 0x10); + + /* test bit must be high, next higher and lower bit must be 0 */ + + if((bus_space_read_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0) & 0x38) != 0x10) + { + bus_space_write_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0, savebyte); + return 0; + } + + return (1); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_avma1 - attach AVM A1 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_attach_avma1(struct isa_device *dev) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + + /* reset the HSCX and ISAC chips */ + + outb(dev->id_iobase + AVM_CONF_REG, 0x00); + DELAY(SEC_DELAY / 10); + + outb(dev->id_iobase + AVM_CONF_REG, AVM_CONF_WR_RESET); + DELAY(SEC_DELAY / 10); + + outb(dev->id_iobase + AVM_CONF_REG, 0x00); + DELAY(SEC_DELAY / 10); + + /* setup IRQ */ + + outb(dev->id_iobase + AVM_CONF_IRQ, (ffs(sc->sc_irq)) - 1); + DELAY(SEC_DELAY / 10); + + /* enable IRQ, disable counter IRQ */ + + outb(dev->id_iobase + AVM_CONF_REG, AVM_CONF_WR_IRQEN | + AVM_CONF_WR_CCH | AVM_CONF_WR_CCL); + DELAY(SEC_DELAY / 10); + + return (1); +} + +#else + +int +isic_attach_avma1(struct l1_softc *sc) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + + sc->clearirq = NULL; + sc->readreg = avma1_read_reg; + sc->writereg = avma1_write_reg; + + sc->readfifo = avma1_read_fifo; + sc->writefifo = avma1_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_AVMA1; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* reset the HSCX and ISAC chips */ + + bus_space_write_1(t, h, 0, 0x00); + DELAY(SEC_DELAY / 10); + + bus_space_write_1(t, h, 0, AVM_CONF_WR_RESET); + DELAY(SEC_DELAY / 10); + + bus_space_write_1(t, h, 0, 0x00); + DELAY(SEC_DELAY / 10); + + /* setup IRQ */ + + bus_space_write_1(t, h, 1, sc->sc_irq); + DELAY(SEC_DELAY / 10); + + /* enable IRQ, disable counter IRQ */ + + bus_space_write_1(t, h, 0, AVM_CONF_WR_IRQEN | + AVM_CONF_WR_CCH | AVM_CONF_WR_CCL); + DELAY(SEC_DELAY / 10); + + return (1); +} +#endif + +#endif /* ISICISA_AVM_A1 */ diff --git a/sys/dev/isa/i4b_itk_ix1.c b/sys/dev/isa/i4b_itk_ix1.c new file mode 100644 index 00000000000..11a78d737bb --- /dev/null +++ b/sys/dev/isa/i4b_itk_ix1.c @@ -0,0 +1,496 @@ +/* + * Copyright (c) 1998, 1999, 2001 Martin Husemann <martin@duskware.de> + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + *--------------------------------------------------------------------------- + * + * i4b_itk_ix1.c - ITK ix1 micro passive card driver for isdn4bsd + * -------------------------------------------------------------- + * + * $Id: i4b_itk_ix1.c,v 1.1.1.1 2001/01/05 12:50:16 martin Exp $ + * + * last edit-date: [Fri Jan 5 12:31:50 2001] + * + * mh - created + * mh - fixed FreeBSD problems reported by Kevin Sheehan + * mh - added probe routine + * + *--------------------------------------------------------------------------- + * + * The ITK ix1 micro ISDN card is an ISA card with one region + * of four io ports mapped and a fixed irq all jumpered on the card. + * Access to the board is straight forward and simmilar to + * the ELSA and DYNALINK cards. If a PCI version of this card + * exists all we need is probably a pci-bus attachment, all + * this low level routines should work imediately. + * + * To reset the card: + * - write 0x01 to ITK_CONFIG + * - wait >= 10 ms + * - write 0x00 to ITK_CONFIG + * + * To read or write data: + * - write address to ITK_ALE port + * - read data from or write data to ITK_ISAC_DATA port or ITK_HSCX_DATA port + * The two HSCX channel registers are offset by HSCXA (0x00) and HSCXB (0x40). + * + * The probe routine was derived by trial and error from a representative + * sample of two cards ;-) The standard way (checking HSCX versions) + * was extended by reading a zero from a non existant HSCX register (register + * 0xff). Reading the config register gives varying results, so this doesn't + * seem to be used as an id register (like the Teles S0/16.3). + * + * If the probe fails for your card use "options ITK_PROBE_DEBUG" to get + * additional debug output. + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicisa.h" + +#ifdef ISICISA_ITKIX1 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_global.h> + +/* Register offsets */ +#define ITK_ISAC_DATA 0 +#define ITK_HSCX_DATA 1 +#define ITK_ALE 2 +#define ITK_CONFIG 3 + +/* Size of IO range to allocate for this card */ +#define ITK_IO_SIZE 4 + +/* Register offsets for the two HSCX channels */ +#define HSCXA 0 +#define HSCXB 0x40 + +/* + * Local function prototypes + */ +#ifdef __FreeBSD__ +/* FreeBSD version */ +static void itkix1_read_fifo(void *buf, const void *base, size_t len); +static void itkix1_write_fifo(void *base, const void *buf, size_t len); +static void itkix1_write_reg(u_char *base, u_int offset, u_int v); +static u_char itkix1_read_reg(u_char *base, u_int offset); +#else +/* NetBSD/OpenBSD version */ +static void itkix1_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size); +static void itkix1_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size); +static void itkix1_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data); +static u_int8_t itkix1_read_reg(struct l1_softc *sc, int what, bus_size_t offs); +#endif + +/* + * Probe for card + */ +#ifdef __FreeBSD__ +int +isic_probe_itkix1(struct isa_device *dev) +{ + u_int8_t hd, hv1, hv2, saveale; + int ret; + + /* save old value of this port, we're stomping over it */ + saveale = inb(dev->id_iobase + ITK_ALE); + + /* select invalid register */ + outb(dev->id_iobase + ITK_ALE, 0xff); + /* get HSCX data for this non existent register */ + hd = inb(dev->id_iobase + ITK_HSCX_DATA); + /* get HSCX version info */ + outb(dev->id_iobase + ITK_ALE, HSCXA + H_VSTR); + hv1 = inb(dev->id_iobase + ITK_HSCX_DATA); + outb(dev->id_iobase + ITK_ALE, HSCXB + H_VSTR); + hv2 = inb(dev->id_iobase + ITK_HSCX_DATA); + + /* succeed if version bits are OK and we got a zero from the + * non existent register. we found verison 0x05 and 0x04 + * out there... */ + ret = (hd == 0) + && (((hv1 & 0x0f) == 0x05) || ((hv1 & 0x0f) == 0x04)) + && (((hv2 & 0x0f) == 0x05) || ((hv2 & 0x0f) == 0x04)); + + /* retstore save value if we fail (if we succeed the old value + * has no meaning) */ + if (!ret) + outb(dev->id_iobase + ITK_ALE, saveale); + +#ifdef ITK_PROBE_DEBUG + printf("\nITK ix1 micro probe: hscx = 0x%02x, v1 = 0x%02x, v2 = 0x%02x, would have %s\n", + hd, hv1, hv2, ret ? "succeeded" : "failed"); + return 1; +#else + return ret; +#endif +} +#else +int +isic_probe_itkix1(struct isic_attach_args *ia) +{ + bus_space_tag_t t = ia->ia_maps[0].t; + bus_space_handle_t h = ia->ia_maps[0].h; + u_int8_t hd, hv1, hv2, saveale; + int ret; + + /* save old value of this port, we're stomping over it */ + saveale = bus_space_read_1(t, h, ITK_ALE); + + /* select invalid register */ + bus_space_write_1(t, h, ITK_ALE, 0xff); + /* get HSCX data for this non existent register */ + hd = bus_space_read_1(t, h, ITK_HSCX_DATA); + /* get HSCX version info */ + bus_space_write_1(t, h, ITK_ALE, HSCXA + H_VSTR); + hv1 = bus_space_read_1(t, h, ITK_HSCX_DATA); + bus_space_write_1(t, h, ITK_ALE, HSCXB + H_VSTR); + hv2 = bus_space_read_1(t, h, ITK_HSCX_DATA); + + ret = (hd == 0) && ((hv1 & 0x0f) == 0x05) && ((hv2 & 0x0f) == 0x05); + /* succeed if version bits are OK and we got a zero from the + * non existent register. we found verison 0x05 and 0x04 + * out there... */ + ret = (hd == 0) + && (((hv1 & 0x0f) == 0x05) || ((hv1 & 0x0f) == 0x04)) + && (((hv2 & 0x0f) == 0x05) || ((hv2 & 0x0f) == 0x04)); + + /* retstore save value if we fail (if we succeed the old value + * has no meaning) */ + if (!ret) + bus_space_write_1(t, h, ITK_ALE, saveale); + +#ifdef ITK_PROBE_DEBUG + printf("\nITK ix1 micro probe: hscx = 0x%02x, v1 = 0x%02x, v2 = 0x%02x, would have %s\n", + hd, hv1, hv2, ret ? "succeeded" : "failed"); + return 1; +#else + return ret; +#endif +} +#endif + +/* + * Attach card + */ +#ifdef __FreeBSD__ +int +isic_attach_itkix1(struct isa_device *dev) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + u_int8_t hv1, hv2; + + sc->sc_irq = dev->id_irq; + + dev->id_msize = 0; + + /* check if we got an iobase */ + sc->sc_port = dev->id_iobase; + + /* setup access routines */ + sc->clearirq = NULL; + sc->readreg = itkix1_read_reg; + sc->writereg = itkix1_write_reg; + sc->readfifo = itkix1_read_fifo; + sc->writefifo = itkix1_write_fifo; + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_ITKIX1; + + /* setup IOM bus type */ + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + ISAC_BASE = (caddr_t) sc->sc_port; + HSCX_A_BASE = (caddr_t) sc->sc_port + 1; + HSCX_B_BASE = (caddr_t) sc->sc_port + 2; + + /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1) or 0x04 (V2.0). */ + hv1 = HSCX_READ(0, H_VSTR) & 0xf; + hv2 = HSCX_READ(1, H_VSTR) & 0xf; + if((hv1 != 0x05 && hv1 != 0x04) || (hv2 != 0x05 && hv2 != 0x04)) + { + printf("isic%d: HSCX VSTR test failed for ITK ix1 micro\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + outb((dev->id_iobase)+ITK_CONFIG, 1); + DELAY(SEC_DELAY / 10); + outb((dev->id_iobase)+ITK_CONFIG, 0); + DELAY(SEC_DELAY / 10); + return(1); +} + +#else + +int isic_attach_itkix1(struct l1_softc *sc) +{ + u_int8_t hv1, hv2; + + /* setup access routines */ + sc->clearirq = NULL; + sc->readreg = itkix1_read_reg; + sc->writereg = itkix1_write_reg; + sc->readfifo = itkix1_read_fifo; + sc->writefifo = itkix1_write_fifo; + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_ITKIX1; + + /* setup IOM bus type */ + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1) or 0x04 (V2.0). */ + hv1 = HSCX_READ(0, H_VSTR) & 0xf; + hv2 = HSCX_READ(2, H_VSTR) & 0xf; + if((hv1 != 0x05 && hv1 != 0x04) || (hv2 != 0x05 && hv2 != 0x04)) + { + printf("%s: HSCX VSTR test failed for ITK ix1 micro\n", + sc->sc_dev.dv_xname); + printf("%s: HSC0: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(0, H_VSTR)); + printf("%s: HSC1: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(1, H_VSTR)); + return 0; + } + + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ITK_CONFIG, 1); + DELAY(SEC_DELAY / 10); + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ITK_CONFIG, 0); + DELAY(SEC_DELAY / 10); + return 1; +} + +#endif + +#ifdef __FreeBSD__ +static void +itkix1_read_fifo(void *buf, const void *base, size_t len) +{ + u_int port = (u_int)base & ~0x0003; + switch ((u_int)base & 3) { + case 0: /* ISAC */ + outb(port+ITK_ALE, 0); + insb(port+ITK_ISAC_DATA, (u_char *)buf, (u_int)len); + break; + case 1: /* HSCXA */ + outb(port+ITK_ALE, HSCXA); + insb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len); + break; + case 2: /* HSCXB */ + outb(port+ITK_ALE, HSCXB); + insb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len); + break; + } +} +#else +static void +itkix1_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ITK_ALE, 0); + bus_space_read_multi_1(t, h, ITK_ISAC_DATA, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ITK_ALE, HSCXA); + bus_space_read_multi_1(t, h, ITK_HSCX_DATA, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ITK_ALE, HSCXB); + bus_space_read_multi_1(t, h, ITK_HSCX_DATA, buf, size); + break; + } +} +#endif + +#ifdef __FreeBSD__ +static void +itkix1_write_fifo(void *base, const void *buf, size_t len) +{ + u_int port = (u_int)base & ~0x0003; + switch ((u_int)base & 3) { + case 0: /* ISAC */ + outb(port+ITK_ALE, 0); + outsb(port+ITK_ISAC_DATA, (u_char *)buf, (u_int)len); + break; + case 1: /* HSCXA */ + outb(port+ITK_ALE, HSCXA); + outsb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len); + break; + case 2: /* HSCXB */ + outb(port+ITK_ALE, HSCXB); + outsb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len); + break; + } +} +#else +static void itkix1_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ITK_ALE, 0); + bus_space_write_multi_1(t, h, ITK_ISAC_DATA, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ITK_ALE, HSCXA); + bus_space_write_multi_1(t, h, ITK_HSCX_DATA, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ITK_ALE, HSCXB); + bus_space_write_multi_1(t, h, ITK_HSCX_DATA, (u_int8_t*)buf, size); + break; + } +} +#endif + +#ifdef __FreeBSD__ +static void +itkix1_write_reg(u_char *base, u_int offset, u_int v) +{ + u_int port = (u_int)base & ~0x0003; + switch ((u_int)base & 3) { + case 0: /* ISAC */ + outb(port+ITK_ALE, offset); + outb(port+ITK_ISAC_DATA, (u_char)v); + break; + case 1: /* HSCXA */ + outb(port+ITK_ALE, HSCXA+offset); + outb(port+ITK_HSCX_DATA, (u_char)v); + break; + case 2: /* HSCXB */ + outb(port+ITK_ALE, HSCXB+offset); + outb(port+ITK_HSCX_DATA, (u_char)v); + break; + } +} +#else +static void itkix1_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ITK_ALE, offs); + bus_space_write_1(t, h, ITK_ISAC_DATA, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ITK_ALE, HSCXA+offs); + bus_space_write_1(t, h, ITK_HSCX_DATA, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ITK_ALE, HSCXB+offs); + bus_space_write_1(t, h, ITK_HSCX_DATA, data); + break; + } +} +#endif + +#ifdef __FreeBSD__ +static u_char +itkix1_read_reg(u_char *base, u_int offset) +{ + u_int port = (u_int)base & ~0x0003; + switch ((u_int)base & 3) { + case 0: /* ISAC */ + outb(port+ITK_ALE, offset); + return (inb(port+ITK_ISAC_DATA)); + case 1: /* HSCXA */ + outb(port+ITK_ALE, HSCXA+offset); + return (inb(port+ITK_HSCX_DATA)); + case 2: /* HSCXB */ + outb(port+ITK_ALE, HSCXB+offset); + return (inb(port+ITK_HSCX_DATA)); + } +} +#else +static u_int8_t itkix1_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ITK_ALE, offs); + return bus_space_read_1(t, h, ITK_ISAC_DATA); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ITK_ALE, HSCXA+offs); + return bus_space_read_1(t, h, ITK_HSCX_DATA); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ITK_ALE, HSCXB+offs); + return bus_space_read_1(t, h, ITK_HSCX_DATA); + } + return 0; +} +#endif + +#endif /* ISICISA_ITKIX1 */ diff --git a/sys/dev/isa/i4b_tel_s016.c b/sys/dev/isa/i4b_tel_s016.c new file mode 100644 index 00000000000..fe510c726fe --- /dev/null +++ b/sys/dev/isa/i4b_tel_s016.c @@ -0,0 +1,455 @@ +/* + * Copyright (c) 1996 Arne Helme. All rights reserved. + * + * Copyright (c) 1996 Gary Jennejohn. All rights reserved. + * + * Copyright (c) 1997, 1999 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for Teles S0/16 and clones + * ================================================================= + * + * $Id: i4b_tel_s016.c,v 1.1.1.1 2001/01/05 12:50:16 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:37:22 2001] + * + * -hm clean up + * -hm checked with a Creatix ISDN-S0 (PCB version: mp 130.1) + * -hm more cleanup + * -hm NetBSD patches from Martin + * -hm converting asm -> C + * + *---------------------------------------------------------------------------*/ + + +#include "opt_isicisa.h" +#ifdef ISICISA_TEL_S0_16 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <machine/md_var.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +static u_char intr_no[] = { 1, 1, 0, 2, 4, 6, 1, 1, 1, 0, 8, 10, 12, 1, 1, 14 }; + +#ifndef __FreeBSD__ +static u_int8_t tels016_read_reg __P((struct l1_softc *sc, int what, bus_size_t offs)); +static void tels016_write_reg __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void tels016_read_fifo __P((struct l1_softc *sc, int what, void *buf, size_t size)); +static void tels016_write_fifo __P((struct l1_softc *sc, int what, const void *data, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16 write register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels016_write_reg(u_char *base, u_int i, u_int v) +{ + if(i & 0x01) + i |= 0x200; + base[i] = v; +} + +#else + +static const bus_size_t offset[] = { 0x100, 0x180, 0x1c0 }; + +static void +tels016_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + + offs += offset[what]; + if (offs & 0x01) + offs |= 0x200; + + bus_space_write_1(t, h, offs, data); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16 read register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +tels016_read_reg(u_char *base, u_int i) +{ + if(i & 0x1) + i |= 0x200; + return(base[i]); +} + +#else + +static u_int8_t +tels016_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + + offs += offset[what]; + + if(offs & 0x01) + offs |= 0x200; + + return bus_space_read_1(t, h, offs); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16 fifo read/write routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels016_memcpyb(void *to, const void *from, size_t len) +{ + for(;len > 0; len--) + *((unsigned char *)to)++ = *((unsigned char *)from)++; +} + +#else + +static void +tels016_write_fifo(struct l1_softc *sc, int what, const void *data, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + bus_space_write_region_1(t, h, offset[what], data, size); +} + +static void +tels016_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + bus_space_read_region_1(t, h, offset[what], buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_s016 - probe for Teles S0/16 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_probe_s016(struct isa_device *dev) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + u_char byte; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles S0/16!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + if((intr_no[ffs(dev->id_irq) - 1]) == 1) + { + printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/16!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + } + sc->sc_irq = dev->id_irq; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0xd80: + case 0xe80: + case 0xf80: + break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for Teles S0/16!\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + /* check if valid memory addr */ + + switch((unsigned int)kvtop(dev->id_maddr)) + { + case 0xc0000: + case 0xc2000: + case 0xc4000: + case 0xc6000: + case 0xc8000: + case 0xca000: + case 0xcc000: + case 0xce000: + case 0xd0000: + case 0xd2000: + case 0xd4000: + case 0xd6000: + case 0xd8000: + case 0xda000: + case 0xdc000: + case 0xde000: + break; + + default: + printf("isic%d: Error, invalid mem addr 0x%lx for Teles S0/16!\n", + dev->id_unit, kvtop(dev->id_maddr)); + return(0); + break; + } + sc->sc_vmem_addr = (caddr_t) dev->id_maddr; + dev->id_msize = 0x1000; + + /* check card signature */ + + if((byte = inb(sc->sc_port)) != 0x51) + { + printf("isic%d: Error, signature 1 0x%x != 0x51 for Teles S0/16!\n", + dev->id_unit, byte); + return(0); + } + + if((byte = inb(sc->sc_port + 1)) != 0x93) + { + printf("isic%d: Error, signature 2 0x%x != 0x93 for Teles S0/16!\n", + dev->id_unit, byte); + return(0); + } + + byte = inb(sc->sc_port + 2); + + if((byte != 0x1e) && (byte != 0x1f)) + { + printf("isic%d: Error, signature 3 0x%x != 0x1e or 0x1f for Teles S0/16!\n", + dev->id_unit, byte); + return(0); + } + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels016_read_reg; + sc->writereg = tels016_write_reg; + + sc->readfifo = tels016_memcpyb; + sc->writefifo = tels016_memcpyb; + + /* setup card type */ + + sc->sc_cardtyp= CARD_TYPEP_16; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM1; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC base addr */ + + ISAC_BASE = (caddr_t) ((dev->id_maddr) + 0x100); + + /* setup HSCX base addr */ + + HSCX_A_BASE = (caddr_t) ((dev->id_maddr) + 0x180); + HSCX_B_BASE = (caddr_t) ((dev->id_maddr) + 0x1c0); + + return (1); +} + +#else + +int +isic_probe_s016(struct isic_attach_args *ia) +{ + bus_space_tag_t t = ia->ia_maps[0].t; + bus_space_handle_t h = ia->ia_maps[0].h; + u_int8_t b0, b1, b2; + + b0 = bus_space_read_1(t, h, 0); + b1 = bus_space_read_1(t, h, 1); + b2 = bus_space_read_1(t, h, 2); + + if (b0 == 0x51 && b1 == 0x93 && (b2 == 0x1e || b2 == 0x1f)) + return 1; + + return 0; +} +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_s016 - attach Teles S0/16 and compatibles + *---------------------------------------------------------------------------*/ +int +#ifdef __FreeBSD__ +isic_attach_s016(struct isa_device *dev) +#else +isic_attach_s016(struct l1_softc *sc) +#endif +{ + +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[dev->id_unit]; +#endif + + u_long irq; + +#ifndef __FreeBSD__ + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels016_read_reg; + sc->writereg = tels016_write_reg; + + sc->readfifo = tels016_read_fifo; + sc->writefifo = tels016_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp= CARD_TYPEP_16; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM1; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + +#endif + +#ifdef __FreeBSD__ + if((irq = intr_no[ffs(dev->id_irq) - 1]) == 1) + { + printf("isic%d: Attach error, invalid IRQ [%d] specified for Teles S0/16!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + } +#else + irq = intr_no[sc->sc_irq]; +#endif + + /* configure IRQ */ + +#ifdef __FreeBSD__ + irq |= ((u_long) sc->sc_vmem_addr) >> 9; + + DELAY(SEC_DELAY / 10); + outb(sc->sc_port + 4, irq); + + DELAY(SEC_DELAY / 10); + outb(sc->sc_port + 4, irq | 0x01); + + DELAY(SEC_DELAY / 5); + + /* set card bit off */ + + sc->sc_vmem_addr[0x80] = 0; + DELAY(SEC_DELAY / 5); + + /* set card bit on */ + + sc->sc_vmem_addr[0x80] = 1; + DELAY(SEC_DELAY / 5); + +#else + + irq |= ((sc->sc_maddr >> 9) & 0x000000f0); + + DELAY(SEC_DELAY / 10); + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, 4, irq); + + DELAY(SEC_DELAY / 10); + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, 4, irq | 0x01); + + DELAY(SEC_DELAY / 5); + + /* set card bit off */ + + bus_space_write_1(sc->sc_maps[1].t, sc->sc_maps[1].h, 0x80, 0); + DELAY(SEC_DELAY / 5); + + /* set card bit on */ + + bus_space_write_1(sc->sc_maps[1].t, sc->sc_maps[1].h, 0x80, 1); + DELAY(SEC_DELAY / 5); +#endif + + return (1); +} + +#endif /* ISICISA_TEL_S0_16 */ + diff --git a/sys/dev/isa/i4b_tel_s0163.c b/sys/dev/isa/i4b_tel_s0163.c new file mode 100644 index 00000000000..2f0eddda56a --- /dev/null +++ b/sys/dev/isa/i4b_tel_s0163.c @@ -0,0 +1,602 @@ +/* + * Copyright (c) 1996 Arne Helme. All rights reserved. + * + * Copyright (c) 1996 Gary Jennejohn. All rights reserved. + * + * Copyright (c) 1997, 1999 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for Teles S0/16.3 + * ======================================================== + * + * $Id: i4b_tel_s0163.c,v 1.1.1.1 2001/01/05 12:50:14 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:37:22 2001] + * + * -hm clean up + * -hm more cleanup + * -hm NetBSD patches from Martin + * -hm VSTR detection for older 16.3 cards + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicisa.h" +#ifdef ISICISA_TEL_S0_16_3 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#elif defined(__bsdi__) + /* XXX */ +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +static u_char intr_no[] = { 1, 1, 0, 2, 4, 6, 1, 1, 1, 0, 8, 10, 12, 1, 1, 14 }; + +#if !defined(__FreeBSD__) && !defined(__bsdi__) +static u_int8_t tels0163_read_reg __P((struct l1_softc *sc, int what, bus_size_t offs)); +static void tels0163_write_reg __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void tels0163_read_fifo __P((struct l1_softc *sc, int what, void *buf, size_t size)); +static void tels0163_write_fifo __P((struct l1_softc *sc, int what, const void *data, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 read fifo routine + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD__) || defined(__bsdi__) + +static void +tels0163_read_fifo(void *buf, const void *base, size_t len) +{ + insb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +tels0163_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_read_multi_1(t, h, o + 0x1e, buf, size); +} + +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 write fifo routine + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD__) || defined(__bsdi__) + +static void +tels0163_write_fifo(void *base, const void *buf, size_t len) +{ + outsb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +tels0163_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_multi_1(t, h, o + 0x1e, (u_int8_t*)buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 ISAC put register routine + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD__) || defined(__bsdi__) + +static void +tels0163_write_reg(u_char *base, u_int offset, u_int v) +{ + outb((int)base + offset, (u_char)v); +} + +#else + +static void +tels0163_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_1(t, h, o + offs - 0x20, data); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 ISAC get register routine + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD__) || defined(__bsdi__) + +static u_char +tels0163_read_reg(u_char *base, u_int offset) +{ + return (inb((int)base + offset)); +} + +#else + +static u_int8_t +tels0163_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + return bus_space_read_1(t, h, o + offs - 0x20); +} + +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_s0163 - probe for Teles S0/16.3 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_probe_s0163(struct isa_device *dev) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + u_char byte; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles S0/16.3!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + if((intr_no[ffs(dev->id_irq) - 1]) == 1) + { + printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/16.3!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Teles S0/16.3!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + + dev->id_msize = 0; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0xd80: + case 0xe80: + case 0xf80: + break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for Teles S0/16.3!\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + if(((byte = inb(sc->sc_port)) != 0x51) && (byte != 0x10)) + { + printf("isic%d: Error, signature 1 0x%x != 0x51 or 0x10 for Teles S0/16.3!\n", + dev->id_unit, byte); + return(0); + } + + if((byte = inb(sc->sc_port + 1)) != 0x93) + { + printf("isic%d: Error, signature 2 0x%x != 0x93 for Teles S0/16.3!\n", + dev->id_unit, byte); + return(0); + } + + if(((byte = inb(sc->sc_port + 2)) != 0x1c) && (byte != 0x1f)) + { + printf("isic%d: Error, signature 3 0x%x != (0x1c||0x1f) for Teles S0/16.3!\n", + dev->id_unit, byte); + return(0); + } + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels0163_read_reg; + sc->writereg = tels0163_write_reg; + + sc->readfifo = tels0163_read_fifo; + sc->writefifo = tels0163_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp= CARD_TYPEP_16_3; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + switch(dev->id_iobase) + { + case 0xd80: + ISAC_BASE = (caddr_t) 0x960; + HSCX_A_BASE = (caddr_t) 0x160; + HSCX_B_BASE = (caddr_t) 0x560; + break; + + case 0xe80: + ISAC_BASE = (caddr_t) 0xa60; + HSCX_A_BASE = (caddr_t) 0x260; + HSCX_B_BASE = (caddr_t) 0x660; + break; + + case 0xf80: + ISAC_BASE = (caddr_t) 0xb60; + HSCX_A_BASE = (caddr_t) 0x360; + HSCX_B_BASE = (caddr_t) 0x760; + break; + } + + /* + * Read HSCX A/B VSTR. Expected value for the S0/16.3 card is + * 0x05 or 0x04 (for older 16.3's) in the least significant bits. + */ + + if( (((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(0, H_VSTR) & 0xf) != 0x4)) || + (((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x4)) ) + { + printf("isic%d: HSCX VSTR test failed for Teles S0/16.3\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +#elif defined(__bsdi__) + +static int +set_softc(struct l1_softc *sc, struct isa_attach_args *ia, int unit) +{ + sc->sc_irq = ia->ia_irq; + + /* check if we got an iobase */ + + switch(ia->ia_iobase) + { + case 0xd80: + case 0xe80: + case 0xf80: + break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for Teles S0/16.3!\n", + unit, ia->ia_iobase); + return(0); + break; + } + sc->sc_port = ia->ia_iobase; + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels0163_read_reg; + sc->writereg = tels0163_write_reg; + + sc->readfifo = tels0163_read_fifo; + sc->writefifo = tels0163_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp= CARD_TYPEP_16_3; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + switch(ia->ia_iobase) + { + case 0xd80: + ISAC_BASE = (caddr_t) 0x960; + HSCX_A_BASE = (caddr_t) 0x160; + HSCX_B_BASE = (caddr_t) 0x560; + break; + + case 0xe80: + ISAC_BASE = (caddr_t) 0xa60; + HSCX_A_BASE = (caddr_t) 0x260; + HSCX_B_BASE = (caddr_t) 0x660; + break; + + case 0xf80: + ISAC_BASE = (caddr_t) 0xb60; + HSCX_A_BASE = (caddr_t) 0x360; + HSCX_B_BASE = (caddr_t) 0x760; + break; + } + return 1; +} + +int +isic_probe_s0163(struct device *dev, struct cfdata *cf, + struct isa_attach_args *ia) +{ + u_char byte; + struct l1_softc dummysc, *sc = &dummysc; + + if((intr_no[ffs(ia->ia_irq) - 1]) == 1) + { + printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/16.3!\n", + cf->cf_unit, ffs(ia->ia_irq)-1); + return(0); + } + + /* check if memory addr specified */ + + if(ia->ia_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Teles S0/16.3!\n", + cf->cf_unit, (u_long)ia->ia_maddr); + return 0; + } + + /* Set up a temporary softc for the probe */ + + if (set_softc(sc, ia, cf->cf_unit) == 0) + return 0; + + if((byte = inb(sc->sc_port)) != 0x51) + { + printf("isic%d: Error, signature 1 0x%x != 0x51 for Teles S0/16.3!\n", + cf->cf_unit, byte); + return(0); + } + + if((byte = inb(sc->sc_port + 1)) != 0x93) + { + printf("isic%d: Error, signature 2 0x%x != 0x93 for Teles S0/16.3!\n", + cf->cf_unit, byte); + return(0); + } + + if(((byte = inb(sc->sc_port + 2)) != 0x1c) && (byte != 0x1f)) + { + printf("isic%d: Error, signature 3 0x%x != (0x1c||0x1f) for Teles S0/16.3!\n", + cf->cf_unit, byte); + return(0); + } + + /* + * Read HSCX A/B VSTR. Expected value for the S0/16.3 card is + * 0x05 or 0x04 (for older 16.3's) in the least significant bits. + */ + + if( (((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(0, H_VSTR) & 0xf) != 0x4)) || + (((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x4)) ) + { + printf("isic%d: HSCX VSTR test failed for Teles S0/16.3\n", + cf->cf_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + cf->cf_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + cf->cf_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + + +#else + +int +isic_probe_s0163(struct isic_attach_args *ia) +{ + bus_space_tag_t t = ia->ia_maps[0].t; + bus_space_handle_t h = ia->ia_maps[0].h; + u_int8_t b0, b1, b2; + + b0 = bus_space_read_1(t, h, 0); + b1 = bus_space_read_1(t, h, 1); + b2 = bus_space_read_1(t, h, 2); + + if (b0 == 0x51 && b1 == 0x93 && (b2 == 0x1c || b2 == 0x1f)) + return 1; + + return 0; +} +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_s0163 - attach Teles S0/16.3 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_attach_s0163(struct isa_device *dev) +{ + u_char irq; + + if((irq = intr_no[ffs(dev->id_irq) - 1]) == 1) + { + printf("isic%d: Attach error, invalid IRQ [%d] specified for Teles S0/16.3!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + } + + /* configure IRQ */ + + DELAY(SEC_DELAY / 10); + outb(dev->id_iobase + 4, irq); + + DELAY(SEC_DELAY / 10); + outb(dev->id_iobase + 4, irq | 0x01); + + return (1); +} + +#elif defined(__bsdi__) + +extern int +isic_attach_s0163(struct device *parent, struct device *self, struct isa_attach_args *ia) +{ + u_char irq; + struct l1_softc *sc = (struct l1_softc *)self; + int unit = sc->sc_dev.dv_unit; + + /* Commit the probed attachement values */ + + if (set_softc(sc, ia, unit) == 0) + panic("isic_attach_s0163: set_softc"); + + if (((unsigned)sc->sc_unit) >= NISIC) + panic("attach isic%d; NISIC=%d", sc->sc_unit, NISIC); + l1_sc[sc->sc_unit] = sc; + irq = intr_no[ffs(sc->sc_irq) - 1]; + /* configure IRQ */ + + DELAY(SEC_DELAY / 10); + outb(sc->sc_port + 4, irq); + + DELAY(SEC_DELAY / 10); + outb(sc->sc_port + 4, irq | 0x01); + + return 1; +} +#else + +int +isic_attach_s0163(struct l1_softc *sc) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + u_int8_t irq = intr_no[sc->sc_irq]; + + /* configure IRQ */ + + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, 4, irq); + + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, 4, irq | 0x01); + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels0163_read_reg; + sc->writereg = tels0163_write_reg; + + sc->readfifo = tels0163_read_fifo; + sc->writefifo = tels0163_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp= CARD_TYPEP_16_3; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + return (1); +} +#endif + +#endif /* ISICISA_TEL_S0_16_3 */ + diff --git a/sys/dev/isa/i4b_tel_s08.c b/sys/dev/isa/i4b_tel_s08.c new file mode 100644 index 00000000000..28839b03934 --- /dev/null +++ b/sys/dev/isa/i4b_tel_s08.c @@ -0,0 +1,388 @@ +/* + * Copyright (c) 1996 Arne Helme. All rights reserved. + * + * Copyright (c) 1996 Gary Jennejohn. All rights reserved. + * + * Copyright (c) 1997, 1999 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for Teles S0/8 and clones + * ================================================================ + * + * $Id: i4b_tel_s08.c,v 1.1.1.1 2001/01/05 12:50:16 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:37:22 2001] + * + * -hm clean up + * -hm more cleanup + * -hm NetBSD patches from Martin + * -hm making it finally work (checked with board revision 1.2) + * -hm converting asm -> C + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicisa.h" +#ifdef ISICISA_TEL_S0_8 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <machine/md_var.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +#ifndef __FreeBSD__ +static u_int8_t tels08_read_reg __P((struct l1_softc *sc, int what, bus_size_t offs)); +static void tels08_write_reg __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void tels08_write_fifo __P((struct l1_softc *sc, int what, const void *data, size_t size)); +static void tels08_read_fifo __P((struct l1_softc *sc, int what, void *buf, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/8 write register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels08_write_reg(u_char *base, u_int i, u_int v) +{ + if(i & 0x01) + i |= 0x200; + base[i] = v; +} + +#else + +static const bus_size_t offset[] = { 0x100, 0x180, 0x1c0 }; + +static void +tels08_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + + offs += offset[what]; + + if (offs & 0x01) + offs |= 0x200; + + bus_space_write_1(t, h, offs, data); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/8 read register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +tels08_read_reg(u_char *base, u_int i) +{ + if(i & 0x1) + i |= 0x200; + return(base[i]); +} + +#else + +static u_int8_t +tels08_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + + offs += offset[what]; + + if (offs & 0x01) + offs |= 0x200; + + return bus_space_read_1(t, h, offs); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/8 fifo read/write access + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels08_memcpyb(void *to, const void *from, size_t len) +{ + for(;len > 0; len--) + *((unsigned char *)to)++ = *((unsigned char *)from)++; +} + +#else + +static void +tels08_write_fifo(struct l1_softc *sc, int what, const void *data, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_region_1(t, h, offset[what], data, size); +} + +static void +tels08_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_read_region_1(t, h, offset[what], buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_s08 - probe for Teles S0/8 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +int +isic_probe_s08(struct isa_device *dev) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles S0/8!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq)-1) + { + case 2: + case 9: /* XXX */ + case 3: + case 4: + case 5: + case 6: + case 7: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/8!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if we got an iobase */ + + if(dev->id_iobase > 0) + { + printf("isic%d: Error, iobase specified for Teles S0/8!\n", + dev->id_unit); + return(0); + } + + /* check if inside memory range of 0xA0000 .. 0xDF000 */ + + if( (kvtop(dev->id_maddr) < 0xa0000) || + (kvtop(dev->id_maddr) > 0xdf000) ) + { + printf("isic%d: Error, mem addr 0x%lx outside 0xA0000-0xDF000 for Teles S0/8!\n", + dev->id_unit, kvtop(dev->id_maddr)); + return(0); + } + + sc->sc_vmem_addr = (caddr_t) dev->id_maddr; + dev->id_msize = 0x1000; + + /* setup ISAC access routines */ + + sc->clearirq = NULL; + sc->readreg = tels08_read_reg; + sc->writereg = tels08_write_reg; + + sc->readfifo = tels08_memcpyb; + sc->writefifo = tels08_memcpyb; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_8; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM1; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC base addr */ + + ISAC_BASE = (caddr_t)((dev->id_maddr) + 0x100); + + /* setup HSCX base addr */ + + HSCX_A_BASE = (caddr_t)((dev->id_maddr) + 0x180); + HSCX_B_BASE = (caddr_t)((dev->id_maddr) + 0x1c0); + + return (1); +} + +#else + +int +isic_probe_s08(struct isic_attach_args *ia) +{ + /* no real sensible probe is easy - write to fifo memory + and read back to verify there is memory doesn't work, + because you talk to tx fifo and rcv fifo. So, just check + HSCX version, which at least fails if no card present + at the given location. */ + bus_space_tag_t t = ia->ia_maps[0].t; + bus_space_handle_t h = ia->ia_maps[0].h; + u_int8_t v1, v2; + + /* HSCX A VSTR */ + v1 = bus_space_read_1(t, h, offset[1] + H_VSTR) & 0x0f; + if (v1 != HSCX_VA1 && v1 != HSCX_VA2 && v1 != HSCX_VA3 && v1 != HSCX_V21) + return 0; + + /* HSCX B VSTR */ + v2 = bus_space_read_1(t, h, offset[2] + H_VSTR) & 0x0f; + if (v2 != HSCX_VA1 && v2 != HSCX_VA2 && v2 != HSCX_VA3 && v2 != HSCX_V21) + return 0; + + /* both HSCX channels should have the same version... */ + if (v1 != v2) + return 0; + + return 1; +} +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_s08 - attach Teles S0/8 and compatibles + *---------------------------------------------------------------------------*/ +int +#ifdef __FreeBSD__ +isic_attach_s08(struct isa_device *dev) +#else +isic_attach_s08(struct l1_softc *sc) +#endif +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[dev->id_unit]; +#else + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; +#endif + + /* set card off */ + +#ifdef __FreeBSD__ + sc->sc_vmem_addr[0x80] = 0; +#else + bus_space_write_1(t, h, 0x80, 0); +#endif + + DELAY(SEC_DELAY / 5); + + /* set card on */ + +#ifdef __FreeBSD__ + sc->sc_vmem_addr[0x80] = 1; +#else + bus_space_write_1(t, h, 0x80, 1); +#endif + + DELAY(SEC_DELAY / 5); + +#ifndef __FreeBSD__ + + /* setup ISAC access routines */ + + sc->clearirq = NULL; + sc->readreg = tels08_read_reg; + sc->writereg = tels08_write_reg; + sc->readfifo = tels08_read_fifo; + sc->writefifo = tels08_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_8; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM1; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + +#endif + + return (1); +} + +#endif /* ISICISA_TEL_S0_8 */ + diff --git a/sys/dev/isa/i4b_usr_sti.c b/sys/dev/isa/i4b_usr_sti.c new file mode 100644 index 00000000000..460a81f4986 --- /dev/null +++ b/sys/dev/isa/i4b_usr_sti.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 1997, 1999 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. + * + *--------------------------------------------------------------------------- + * + * i4b_usr_sti.c - USRobotics Sportster ISDN TA intern (Tina-pp) + * ------------------------------------------------------------- + * + * $Id: i4b_usr_sti.c,v 1.1.1.1 2001/01/05 12:50:14 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:37:22 2001] + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicisa.h" +#ifdef ISICISA_USR_STI + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_global.h> + +/*---------------------------------------------------------------------------* + * USR Sportster TA intern special registers + *---------------------------------------------------------------------------*/ +#define USR_HSCXA_OFF 0x0000 +#define USR_HSCXB_OFF 0x4000 +#define USR_INTL_OFF 0x8000 +#define USR_ISAC_OFF 0xc000 + +#define USR_RES_BIT 0x80 /* 0 = normal, 1 = reset ISAC/HSCX */ +#define USR_INTE_BIT 0x40 /* 0 = IRQ disabled, 1 = IRQ's enabled */ +#define USR_IL_MASK 0x07 /* IRQ level config */ + +static u_char intr_no[] = { 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 3, 4, 5, 0, 6, 7 }; + +#ifdef __FreeBSD__ + +#define ADDR(reg) \ + (((reg/4) * 1024) + ((reg%4) * 2)) + +/*---------------------------------------------------------------------------* + * USRobotics read fifo routine + *---------------------------------------------------------------------------*/ +static void +usrtai_read_fifo(void *buf, const void *base, size_t len) +{ + register int offset = 0; + + for(;len > 0; len--, offset++) + *((u_char *)buf + offset) = inb((int)base + ADDR(offset)); +} + +/*---------------------------------------------------------------------------* + * USRobotics write fifo routine + *---------------------------------------------------------------------------*/ +static void +usrtai_write_fifo(void *base, const void *buf, size_t len) +{ + register int offset = 0; + + for(;len > 0; len--, offset++) + outb((int)base + ADDR(offset), *((u_char *)buf + offset)); +} + +/*---------------------------------------------------------------------------* + * USRobotics write register routine + *---------------------------------------------------------------------------*/ +static void +usrtai_write_reg(u_char *base, u_int offset, u_int v) +{ + outb((int)base + ADDR(offset), (u_char)v); +} + +/*---------------------------------------------------------------------------* + * USRobotics read register routine + *---------------------------------------------------------------------------*/ +static u_char +usrtai_read_reg(u_char *base, u_int offset) +{ + return(inb((int)base + ADDR(offset))); +} + +/*---------------------------------------------------------------------------* + * isic_probe_usrtai - probe for USR + *---------------------------------------------------------------------------*/ +int +isic_probe_usrtai(struct isa_device *dev) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= MAXUNIT for USR Sportster TA!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + if((intr_no[ffs(dev->id_irq) - 1]) == 0) + { + printf("isic%d: Error, invalid IRQ [%d] specified for USR Sportster TA!\n", + dev->id_unit, (ffs(dev->id_irq))-1); + return(0); + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for USR Sportster TA!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + dev->id_msize = 0; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0x200: + case 0x208: + case 0x210: + case 0x218: + case 0x220: + case 0x228: + case 0x230: + case 0x238: + case 0x240: + case 0x248: + case 0x250: + case 0x258: + case 0x260: + case 0x268: + case 0x270: + case 0x278: + break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for USR Sportster TA!\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + /* setup ISAC access routines */ + + sc->clearirq = NULL; + sc->readreg = usrtai_read_reg; + sc->writereg = usrtai_write_reg; + + sc->readfifo = usrtai_read_fifo; + sc->writefifo = usrtai_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_USRTA; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t)dev->id_iobase + USR_ISAC_OFF; + HSCX_A_BASE = (caddr_t)dev->id_iobase + USR_HSCXA_OFF; + HSCX_B_BASE = (caddr_t)dev->id_iobase + USR_HSCXB_OFF; + + /* + * Read HSCX A/B VSTR. Expected value for USR Sportster TA based + * boards is 0x05 in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for USR Sportster TA\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +/*---------------------------------------------------------------------------* + * isic_attach_usrtai - attach USR + *---------------------------------------------------------------------------*/ +int +isic_attach_usrtai(struct isa_device *dev) +{ + u_char irq = 0; + + /* reset the HSCX and ISAC chips */ + + outb(dev->id_iobase + USR_INTL_OFF, USR_RES_BIT); + DELAY(SEC_DELAY / 10); + + outb(dev->id_iobase + USR_INTL_OFF, 0x00); + DELAY(SEC_DELAY / 10); + + /* setup IRQ */ + + if((irq = intr_no[ffs(dev->id_irq) - 1]) == 0) + { + printf("isic%d: Attach error, invalid IRQ [%d] specified for USR Sportster TA!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + } + + /* configure and enable irq */ + + outb(dev->id_iobase + USR_INTL_OFF, irq | USR_INTE_BIT); + DELAY(SEC_DELAY / 10); + + return (1); +} + +#else /* end of FreeBSD, start NetBSD */ + +/* + * Use of sc->sc_maps: + * 0 : config register + * 1 - 16 : HSCX A registers + * 17 - 32 : HSCX B registers + * 33 - 48 : ISAC registers + */ + +#define USR_REG_OFFS(reg) ((reg % 4) * 2) +#define USR_HSCXA_MAP(reg) ((reg / 4) + 1) +#define USR_HSCXB_MAP(reg) ((reg / 4) + 17) +#define USR_ISAC_MAP(reg) ((reg / 4) + 33) + +static int map_base[] = { 33, 1, 17, 0 }; /* ISAC, HSCX A, HSCX B */ + +/*---------------------------------------------------------------------------* + * USRobotics read fifo routine + *---------------------------------------------------------------------------*/ +static void +usrtai_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + int map, off, offset; + u_char * p = buf; + bus_space_tag_t t; + bus_space_handle_t h; + + for (offset = 0; size > 0; size--, offset++) { + map = map_base[what] + (offset / 4); + t = sc->sc_maps[map].t; + h = sc->sc_maps[map].h; + off = USR_REG_OFFS(offset); + + *p++ = bus_space_read_1(t, h, off); + } +} + +/*---------------------------------------------------------------------------* + * USRobotics write fifo routine + *---------------------------------------------------------------------------*/ +static void +usrtai_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + int map, off, offset; + const u_char * p = buf; + bus_space_tag_t t; + bus_space_handle_t h; + u_char v; + + for (offset = 0; size > 0; size--, offset++) { + map = map_base[what] + (offset / 4); + t = sc->sc_maps[map].t; + h = sc->sc_maps[map].h; + off = USR_REG_OFFS(offset); + + v = *p++; + bus_space_write_1(t, h, off, v); + } +} + +/*---------------------------------------------------------------------------* + * USRobotics write register routine + *---------------------------------------------------------------------------*/ +static void +usrtai_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + int map = map_base[what] + (offs / 4), + off = USR_REG_OFFS(offs); + bus_space_tag_t t = sc->sc_maps[map].t; + bus_space_handle_t h = sc->sc_maps[map].h; + + bus_space_write_1(t, h, off, data); +} + +/*---------------------------------------------------------------------------* + * USRobotics read register routine + *---------------------------------------------------------------------------*/ +static u_char +usrtai_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + int map = map_base[what] + (offs / 4), + off = USR_REG_OFFS(offs); + bus_space_tag_t t = sc->sc_maps[map].t; + bus_space_handle_t h = sc->sc_maps[map].h; + + return bus_space_read_1(t, h, off); +} + +/*---------------------------------------------------------------------------* + * isic_probe_usrtai - probe for USR + *---------------------------------------------------------------------------*/ +int +isic_probe_usrtai(struct isic_attach_args *ia) +{ + /* + * Read HSCX A/B VSTR. Expected value for IOM2 based + * boards is 0x05 in the least significant bits. + */ + + if(((bus_space_read_1(ia->ia_maps[USR_HSCXA_MAP(H_VSTR)].t, ia->ia_maps[USR_HSCXA_MAP(H_VSTR)].h, USR_REG_OFFS(H_VSTR)) & 0x0f) != 0x05) || + ((bus_space_read_1(ia->ia_maps[USR_HSCXB_MAP(H_VSTR)].t, ia->ia_maps[USR_HSCXB_MAP(H_VSTR)].h, USR_REG_OFFS(H_VSTR)) & 0x0f) != 0x05)) + return 0; + + return (1); +} + +/*---------------------------------------------------------------------------* + * isic_attach_usrtai - attach USR + *---------------------------------------------------------------------------*/ +int +isic_attach_usrtai(struct l1_softc *sc) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + u_char irq = intr_no[sc->sc_irq]; + + sc->clearirq = NULL; + sc->readreg = usrtai_read_reg; + sc->writereg = usrtai_write_reg; + + sc->readfifo = usrtai_read_fifo; + sc->writefifo = usrtai_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_USRTA; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* reset the HSCX and ISAC chips */ + + bus_space_write_1(t, h, 0, USR_RES_BIT); + DELAY(SEC_DELAY / 10); + + bus_space_write_1(t, h, 0, 0x00); + DELAY(SEC_DELAY / 10); + + /* setup IRQ */ + + bus_space_write_1(t, h, 0, irq | USR_INTE_BIT); + DELAY(SEC_DELAY / 10); + + return (1); +} + +#endif /* __FreeBSD__ */ + +#endif /* ISICISA_USR_STI */ diff --git a/sys/dev/isa/isa_isic.c b/sys/dev/isa/isa_isic.c new file mode 100644 index 00000000000..6ea94543674 --- /dev/null +++ b/sys/dev/isa/isa_isic.c @@ -0,0 +1,1299 @@ +/* + * Copyright (c) 1997-1999 Martin Husemann. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * isa_isic.c - ISA bus frontend for i4b_isic driver + * -------------------------------------------------- + * + * $Id: isa_isic.c,v 1.1.1.1 2001/01/05 12:50:14 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:37:22 2001] + * + * -mh original implementation + * -hm NetBSD patches from Martin + * + *---------------------------------------------------------------------------*/ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/systm.h> +#include <sys/malloc.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/isa/isavar.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_ioctl.h> +#endif + +#include "opt_isicisa.h" + +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#include <netisdn/i4b_trace.h> + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_ipac.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> +#include <netisdn/i4b_global.h> + +#if defined(__OpenBSD__) +#define __BROKEN_INDIRECT_CONFIG +#endif + +/* local functions */ +#ifdef __BROKEN_INDIRECT_CONFIG +static int isa_isic_probe __P((struct device *, void *, void *)); +#else +static int isa_isic_probe __P((struct device *, struct cfdata *, void *)); +#endif + +static void isa_isic_attach __P((struct device *, struct device *, void *)); +static int setup_io_map __P((int flags, bus_space_tag_t iot, + bus_space_tag_t memt, bus_size_t iobase, bus_size_t maddr, + int *num_mappings, struct isic_io_map *maps, int *iosize, + int *msize)); +static void args_unmap __P((int *num_mappings, struct isic_io_map *maps)); + +struct cfattach isa_isic_ca = { + sizeof(struct l1_softc), isa_isic_probe, isa_isic_attach +}; + +#define ISIC_FMT "%s: " +#define ISIC_PARM sc->sc_dev.dv_xname +#define TERMFMT "\n" + +/* + * Probe card + */ +static int +#ifdef __BROKEN_INDIRECT_CONFIG +isa_isic_probe(parent, match, aux) +#else +isa_isic_probe(parent, cf, aux) +#endif + struct device *parent; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *cf; +#endif + void *aux; +{ +#ifdef __BROKEN_INDIRECT_CONFIG + struct cfdata *cf = ((struct device*)match)->dv_cfdata; +#endif + struct isa_attach_args *ia = aux; + bus_space_tag_t memt = ia->ia_memt, iot = ia->ia_iot; + int flags = cf->cf_flags; + struct isic_attach_args args; + int ret = 0; + +#if 0 + printf("isic%d: enter isa_isic_probe\n", cf->cf_unit); +#endif + + /* check irq */ + if (ia->ia_irq == IRQUNK) { + printf("isic%d: config error: no IRQ specified\n", cf->cf_unit); + return 0; + } + + /* setup MI attach args */ + bzero(&args, sizeof(args)); + args.ia_flags = flags; + + /* if card type specified setup io map for that card */ + switch(flags) + { + case FLAG_TELES_S0_8: + case FLAG_TELES_S0_16: + case FLAG_TELES_S0_163: + case FLAG_AVM_A1: + case FLAG_USR_ISDN_TA_INT: + case FLAG_ITK_IX1: + if (setup_io_map(flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &ia->ia_msize)) { + ret = 0; + goto done; + } + break; + + default: + /* no io map now, will figure card type later */ + break; + } + + /* probe card */ + switch(flags) + { +#ifdef DYNALINK +#ifdef __bsdi__ + case FLAG_DYNALINK: + ret = isic_probe_Dyn(&args); + break; +#endif +#endif + +#ifdef ISICISA_TEL_S0_8 + case FLAG_TELES_S0_8: + ret = isic_probe_s08(&args); + break; +#endif + +#ifdef ISICISA_TEL_S0_16 + case FLAG_TELES_S0_16: + ret = isic_probe_s016(&args); + break; +#endif + +#ifdef ISICISA_TEL_S0_16_3 + case FLAG_TELES_S0_163: + ret = isic_probe_s0163(&args); + break; +#endif + +#ifdef ISICISA_AVM_A1 + case FLAG_AVM_A1: + ret = isic_probe_avma1(&args); + break; +#endif + +#ifdef ISICISA_USR_STI + case FLAG_USR_ISDN_TA_INT: + ret = isic_probe_usrtai(&args); + break; +#endif + +#ifdef ISICISA_ITKIX1 + case FLAG_ITK_IX1: + ret = isic_probe_itkix1(&args); + break; +#endif + + default: + /* No card type given, try to figure ... */ + if (ia->ia_iobase == IOBASEUNK) { + ret = 0; +#ifdef ISICISA_TEL_S0_8 + /* only Teles S0/8 will work without IO */ + args.ia_flags = FLAG_TELES_S0_8; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_s08(&args); + } +#endif /* ISICISA_TEL_S0_8 */ + } else if (ia->ia_maddr == MADDRUNK) { + ret = 0; +#ifdef ISICISA_TEL_S0_16_3 + /* no shared memory, only a 16.3 based card, + AVM A1, the usr sportster or an ITK would work */ + args.ia_flags = FLAG_TELES_S0_163; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_s0163(&args); + if (ret) + break; + } +#endif /* ISICISA_TEL_S0_16_3 */ +#ifdef ISICISA_AVM_A1 + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_AVM_A1; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_avma1(&args); + if (ret) + break; + } +#endif /* AVM_A1 */ +#ifdef ISICISA_USR_STI + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_USR_ISDN_TA_INT; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_usrtai(&args); + if (ret) + break; + } +#endif /* ISICISA_USR_STI */ + +#ifdef ISICISA_ITKIX1 + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_ITK_IX1; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_itkix1(&args); + if (ret) + break; + } +#endif /* ISICISA_ITKIX1 */ + + } else { +#ifdef ISICISA_TEL_S0_16_3 + /* could be anything */ + args.ia_flags = FLAG_TELES_S0_163; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_s0163(&args); + if (ret) + break; + } +#endif /* ISICISA_TEL_S0_16_3 */ +#ifdef ISICISA_TEL_S0_16 + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_TELES_S0_16; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_s016(&args); + if (ret) + break; + } +#endif /* ISICISA_TEL_S0_16 */ +#ifdef ISICISA_AVM_A1 + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_AVM_A1; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_avma1(&args); + if (ret) + break; + } +#endif /* ISICISA_AVM_A1 */ +#ifdef ISICISA_TEL_S0_8 + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_TELES_S0_8; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_s08(&args); + } +#endif /* ISICISA_TEL_S0_8 */ + } + break; + } + +done: + /* unmap resources */ + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + +#if 0 + printf("isic%d: exit isa_isic_probe, return = %d\n", cf->cf_unit, ret); +#endif + + return ret; +} + +static int +isicattach(int flags, struct l1_softc *sc) +{ + int ret = 0; + char *drvid; + +#ifdef __FreeBSD__ + + struct l1_softc *sc = &l1_sc[dev->id_unit]; +#define PARM dev +#define PARM2 dev, iobase2 +#define FLAGS dev->id_flags + +#elif defined(__bsdi__) + + struct l1_softc *sc = (struct l1_softc *)self; +#define PARM parent, self, ia +#define PARM2 parent, self, ia +#define FLAGS sc->sc_flags + +#else + +#define PARM sc +#define PARM2 sc +#define FLAGS flags + +#endif /* __FreeBSD__ */ + + static char *ISACversion[] = { + "2085 Version A1/A2 or 2086/2186 Version 1.1", + "2085 Version B1", + "2085 Version B2", + "2085 Version V2.3 (B3)", + "Unknown Version" + }; + + static char *HSCXversion[] = { + "82525 Version A1", + "Unknown (0x01)", + "82525 Version A2", + "Unknown (0x03)", + "82525 Version A3", + "82525 or 21525 Version 2.1", + "Unknown Version" + }; + + /* done in bus specific attach code for other OS */ + +#ifdef __FreeBSD__ + if(dev->id_unit != next_isic_unit) + { +/*XXX*/ printf("isicattach: Error: new unit (%d) != next_isic_unit (%d)!\n", dev->id_unit, next_isic_unit); + return(0); + } + + sc->sc_unit = dev->id_unit; +#else + l1_sc[sc->sc_unit] = sc; +#endif + + /* card dependent setup */ + switch(FLAGS) + { +#ifdef DYNALINK +#if defined(__bsdi__) || defined(__FreeBSD__) + case FLAG_DYNALINK: + ret = isic_attach_Dyn(PARM2); + break; +#endif +#endif + +#ifdef TEL_S0_8 + case FLAG_TELES_S0_8: + ret = isic_attach_s08(PARM); + break; +#endif + +#ifdef TEL_S0_16 + case FLAG_TELES_S0_16: + ret = isic_attach_s016(PARM); + break; +#endif + +#ifdef TEL_S0_16_3 + case FLAG_TELES_S0_163: + ret = isic_attach_s0163(PARM); + break; +#endif + +#ifdef AVM_A1 + case FLAG_AVM_A1: + ret = isic_attach_avma1(PARM); + break; +#endif + +#ifdef USR_STI + case FLAG_USR_ISDN_TA_INT: + ret = isic_attach_usrtai(PARM); + break; +#endif + +#ifdef ITKIX1 + case FLAG_ITK_IX1: + ret = isic_attach_itkix1(PARM); + break; +#endif + +#ifdef ELSA_PCC16 + case FLAG_ELSA_PCC16: + ret = isic_attach_Eqs1pi(dev, 0); + break; +#endif + +#ifdef amiga + case FLAG_BLMASTER: + ret = 1; /* full detection was done in caller */ + break; +#endif + +/* ====================================================================== + * Only P&P cards follow below!!! + */ + +#ifdef __FreeBSD__ /* we've already splitted all non-ISA stuff + out of this ISA specific part for the other + OS */ + +#ifdef AVM_A1_PCMCIA + case FLAG_AVM_A1_PCMCIA: + ret = isic_attach_fritzpcmcia(PARM); + break; +#endif + +#ifdef TEL_S0_16_3_P + case FLAG_TELES_S0_163_PnP: + ret = isic_attach_s0163P(PARM2); + break; +#endif + +#ifdef CRTX_S0_P + case FLAG_CREATIX_S0_PnP: + ret = isic_attach_Cs0P(PARM2); + break; +#endif + +#ifdef DRN_NGO + case FLAG_DRN_NGO: + ret = isic_attach_drnngo(PARM2); + break; +#endif + +#ifdef SEDLBAUER + case FLAG_SWS: + ret = isic_attach_sws(PARM); + break; +#endif + +#ifdef ELSA_QS1ISA + case FLAG_ELSA_QS1P_ISA: + ret = isic_attach_Eqs1pi(PARM2); + break; +#endif + +#ifdef AVM_PNP + case FLAG_AVM_PNP: + ret = isic_attach_avm_pnp(PARM2); + ret = 0; + break; +#endif + +#ifdef SIEMENS_ISURF2 + case FLAG_SIEMENS_ISURF2: + ret = isic_attach_siemens_isurf(PARM2); + break; +#endif + +#ifdef ASUSCOM_IPAC + case FLAG_ASUSCOM_IPAC: + ret = isic_attach_asi(PARM2); + break; +#endif + +#endif /* __FreeBSD__ / P&P specific part */ + + default: + break; + } + + if(ret == 0) + return(0); + + if(sc->sc_ipac) + { + sc->sc_ipac_version = IPAC_READ(IPAC_ID); + + switch(sc->sc_ipac_version) + { + case IPAC_V11: + case IPAC_V12: + break; + + default: + printf("isic%d: Error, IPAC version %d unknown!\n", + sc->sc_unit, ret); + return(0); + break; + } + } + else + { + sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; + + switch(sc->sc_isac_version) + { + case ISAC_VA: + case ISAC_VB1: + case ISAC_VB2: + case ISAC_VB3: + break; + + default: + printf(ISIC_FMT "Error, ISAC version %d unknown!\n", + ISIC_PARM, sc->sc_isac_version); + return(0); + break; + } + + sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; + + switch(sc->sc_hscx_version) + { + case HSCX_VA1: + case HSCX_VA2: + case HSCX_VA3: + case HSCX_V21: + break; + + default: + printf(ISIC_FMT "Error, HSCX version %d unknown!\n", + ISIC_PARM, sc->sc_hscx_version); + return(0); + break; + } + } + + /* ISAC setup */ + + isic_isac_init(sc); + + /* HSCX setup */ + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* setup linktab */ + + isic_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + +#if defined(__FreeBSD__) && __FreeBSD__ >=3 + callout_handle_init(&sc->sc_T3_callout); + callout_handle_init(&sc->sc_T4_callout); +#endif + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 + callout_init(&sc->sc_T3_callout); + callout_init(&sc->sc_T4_callout); +#endif + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + /* announce manufacturer and card type */ + + switch(FLAGS) + { + case FLAG_TELES_S0_8: + drvid = "Teles S0/8 or Niccy 1008"; + break; + + case FLAG_TELES_S0_16: + drvid = "Teles S0/16, Creatix ISDN S0-16 or Niccy 1016"; + break; + + case FLAG_TELES_S0_163: + drvid = "Teles S0/16.3"; + break; + + case FLAG_AVM_A1: + drvid = "AVM A1 or AVM Fritz!Card"; + break; + + case FLAG_AVM_A1_PCMCIA: + drvid = "AVM PCMCIA Fritz!Card"; + break; + + case FLAG_TELES_S0_163_PnP: + drvid = "Teles S0/PnP"; + break; + + case FLAG_CREATIX_S0_PnP: + drvid = "Creatix ISDN S0-16 P&P"; + break; + + case FLAG_USR_ISDN_TA_INT: + drvid = "USRobotics Sportster ISDN TA intern"; + break; + + case FLAG_DRN_NGO: + drvid = "Dr. Neuhaus NICCY Go@"; + break; + + case FLAG_DYNALINK: + drvid = "Dynalink IS64PH"; + break; + + case FLAG_SWS: + drvid = "Sedlbauer WinSpeed"; + break; + + case FLAG_BLMASTER: + /* board announcement was done by caller */ + drvid = (char *)0; + break; + + case FLAG_ELSA_QS1P_ISA: + drvid = "ELSA QuickStep 1000pro (ISA)"; + break; + + case FLAG_ITK_IX1: + drvid = "ITK ix1 micro"; + break; + + case FLAG_ELSA_PCC16: + drvid = "ELSA PCC-16"; + break; + + case FLAG_ASUSCOM_IPAC: + drvid = "Asuscom ISDNlink 128K PnP"; + break; + + case FLAG_SIEMENS_ISURF2: + drvid = "Siemens I-Surf 2.0"; + break; + + default: + drvid = "ERROR, unknown flag used"; + break; + } +#ifndef __FreeBSD__ + printf("\n"); +#endif + if (drvid) + printf(ISIC_FMT "%s\n", ISIC_PARM, drvid); + + /* announce chip versions */ + + if(sc->sc_ipac) + { + if(sc->sc_ipac_version == IPAC_V11) + printf(ISIC_FMT "IPAC PSB2115 Version 1.1\n", ISIC_PARM); + else + printf(ISIC_FMT "IPAC PSB2115 Version 1.2\n", ISIC_PARM); + } + else + { + if(sc->sc_isac_version >= ISAC_UNKN) + { + printf(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_isac_version); + sc->sc_isac_version = ISAC_UNKN; + } + else + { + printf(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT, + ISIC_PARM, + ISACversion[sc->sc_isac_version], + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + } + +#ifdef __FreeBSD__ + printf("(Addr=0x%lx)\n", (u_long)ISAC_BASE); +#endif + + if(sc->sc_hscx_version >= HSCX_UNKN) + { + printf(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_hscx_version); + sc->sc_hscx_version = HSCX_UNKN; + } + else + { + printf(ISIC_FMT "HSCX %s" TERMFMT, + ISIC_PARM, + HSCXversion[sc->sc_hscx_version]); + } + +#ifdef __FreeBSD__ + printf("(AddrA=0x%lx, AddrB=0x%lx)\n", (u_long)HSCX_A_BASE, (u_long)HSCX_B_BASE); + +#endif /* __FreeBSD__ */ + } + +#ifdef __FreeBSD__ + next_isic_unit++; + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300003 + + /* set the interrupt handler - no need to change isa_device.h */ + dev->id_intr = (inthand2_t *)isicintr; + +#endif + +#endif /* __FreeBSD__ */ + + return(1); +#undef PARM +#undef FLAGS +} + +/* + * Attach the card + */ +static void +isa_isic_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct l1_softc *sc = (void *)self; + struct isa_attach_args *ia = aux; + int flags = sc->sc_dev.dv_cfdata->cf_flags; + int ret = 0; + struct isic_attach_args args; + + /* Setup parameters */ + sc->sc_unit = sc->sc_dev.dv_unit; + sc->sc_irq = ia->ia_irq; + sc->sc_maddr = ia->ia_maddr; + sc->sc_num_mappings = 0; + sc->sc_maps = NULL; + switch(flags) + { + case FLAG_TELES_S0_8: + case FLAG_TELES_S0_16: + case FLAG_TELES_S0_163: + case FLAG_AVM_A1: + case FLAG_USR_ISDN_TA_INT: + setup_io_map(flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &(sc->sc_num_mappings), NULL, NULL, NULL); + MALLOC_MAPS(sc); + setup_io_map(flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &(sc->sc_num_mappings), &(sc->sc_maps[0]), NULL, NULL); + break; + + default: + /* No card type given, try to figure ... */ + + /* setup MI attach args */ + bzero(&args, sizeof(args)); + args.ia_flags = flags; + + /* Probe cards */ + if (ia->ia_iobase == IOBASEUNK) { + ret = 0; +#ifdef ISICISA_TEL_S0_8 + /* only Teles S0/8 will work without IO */ + args.ia_flags = FLAG_TELES_S0_8; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_s08(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* ISICISA_TEL_S0_8 */ + } else if (ia->ia_maddr == MADDRUNK) { + /* no shared memory, only a 16.3 based card, + AVM A1, the usr sportster or an ITK would work */ + ret = 0; +#ifdef ISICISA_TEL_S0_16_3 + args.ia_flags = FLAG_TELES_S0_163; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_s0163(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* ISICISA_TEL_S0_16_3 */ +#ifdef ISICISA_AVM_A1 + args.ia_flags = FLAG_AVM_A1; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_avma1(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* ISICISA_AVM_A1 */ +#ifdef ISICISA_USR_STI + args.ia_flags = FLAG_USR_ISDN_TA_INT; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_usrtai(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* ISICISA_USR_STI */ +#ifdef ISICISA_ITKIX1 + args.ia_flags = FLAG_ITK_IX1; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_itkix1(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* ISICISA_ITKIX1 */ + } else { + /* could be anything */ + ret = 0; +#ifdef ISICISA_TEL_S0_16_3 + args.ia_flags = FLAG_TELES_S0_163; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_s0163(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* ISICISA_TEL_S0_16_3 */ +#ifdef ISICISA_TEL_S0_16 + args.ia_flags = FLAG_TELES_S0_16; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_s016(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* ISICISA_TEL_S0_16 */ +#ifdef ISICISA_AVM_A1 + args.ia_flags = FLAG_AVM_A1; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_avma1(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* ISICISA_AVM_A1 */ +#ifdef ISICISA_TEL_S0_8 + args.ia_flags = FLAG_TELES_S0_8; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_s08(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* ISICISA_TEL_S0_8 */ + } + break; + + found: + flags = args.ia_flags; + sc->sc_num_mappings = args.ia_num_mappings; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + if (ret) { + MALLOC_MAPS(sc); + setup_io_map(flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &(sc->sc_num_mappings), &(sc->sc_maps[0]), NULL, NULL); + } else { + printf(": could not determine card type - not configured!\n"); + return; + } + break; + } + +#if defined(__OpenBSD__) + isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, isicintr, sc, sc->sc_dev.dv_xname); + + /* MI initialization of card */ + isicattach(flags, sc); + +#else + + /* MI initialization of card */ + isicattach(flags, sc); + + /* + * Try to get a level-triggered interrupt first. If that doesn't + * work (like on NetBSD/Atari, try to establish an edge triggered + * interrupt. + */ + if (isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_LEVEL, + IPL_NET, isicintr, sc) == NULL) { + if(isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, isicintr, sc) == NULL) { + args_unmap(&(sc->sc_num_mappings), &(sc->sc_maps[0])); + free((sc)->sc_maps, M_DEVBUF); + } + else { + /* + * XXX: This is a hack that probably needs to be + * solved by setting an interrupt type in the sc + * structure. I don't feel familiar enough with the + * code to do this currently. Feel free to contact + * me about it (leo@netbsd.org). + */ + isicintr(sc); + } + } +#endif +} + +/* + * Setup card specific io mapping. Return 0 on success, + * any other value on config error. + * Be prepared to get NULL as maps array. + * Make sure to keep *num_mappings in sync with the real + * mappings already setup when returning! + */ +static int +setup_io_map(flags, iot, memt, iobase, maddr, num_mappings, maps, iosize, msize) + int flags, *num_mappings, *iosize, *msize; + bus_size_t iobase, maddr; + bus_space_tag_t iot, memt; + struct isic_io_map *maps; +{ + /* nothing mapped yet */ + *num_mappings = 0; + + /* which resources do we need? */ + switch(flags) + { + case FLAG_TELES_S0_8: + if (maddr == MADDRUNK) { + printf("isic: config error: no shared memory specified for Teles S0/8!\n"); + return 1; + } + if (iosize) *iosize = 0; /* no i/o ports */ + if (msize) *msize = 0x1000; /* shared memory size */ + + /* this card uses a single memory mapping */ + if (maps == NULL) { + *num_mappings = 1; + return 0; + } + *num_mappings = 0; + maps[0].t = memt; + maps[0].offset = 0; + maps[0].size = 0x1000; + if (bus_space_map(maps[0].t, maddr, + maps[0].size, 0, &maps[0].h)) { + return 1; + } + (*num_mappings)++; + break; + + case FLAG_TELES_S0_16: + if (iobase == IOBASEUNK) { + printf("isic: config error: no i/o address specified for Teles S0/16!\n"); + return 1; + } + if (maddr == MADDRUNK) { + printf("isic: config error: no shared memory specified for Teles S0/16!\n"); + return 1; + } + if (iosize) *iosize = 8; /* i/o ports */ + if (msize) *msize = 0x1000; /* shared memory size */ + + /* one io and one memory mapping */ + if (maps == NULL) { + *num_mappings = 2; + return 0; + } + *num_mappings = 0; + maps[0].t = iot; + maps[0].offset = 0; + maps[0].size = 8; + if (bus_space_map(maps[0].t, iobase, + maps[0].size, 0, &maps[0].h)) { + return 1; + } + (*num_mappings)++; + maps[1].t = memt; + maps[1].offset = 0; + maps[1].size = 0x1000; + if (bus_space_map(maps[1].t, maddr, + maps[1].size, 0, &maps[1].h)) { + return 1; + } + (*num_mappings)++; + break; + + case FLAG_TELES_S0_163: + if (iobase == IOBASEUNK) { + printf("isic: config error: no i/o address specified for Teles S0/16!\n"); + return 1; + } + if (iosize) *iosize = 8; /* only some i/o ports shown */ + if (msize) *msize = 0; /* no shared memory */ + + /* Four io mappings: config, isac, 2 * hscx */ + if (maps == NULL) { + *num_mappings = 4; + return 0; + } + *num_mappings = 0; + maps[0].t = iot; + maps[0].offset = 0; + maps[0].size = 8; + if (bus_space_map(maps[0].t, iobase, + maps[0].size, 0, &maps[0].h)) { + return 1; + } + (*num_mappings)++; + maps[1].t = iot; + maps[1].offset = 0; + maps[1].size = 0x40; /* XXX - ??? */ + if ((iobase - 0xd80 + 0x980) < 0 || (iobase - 0xd80 + 0x980) > 0x0ffff) + return 1; + if (bus_space_map(maps[1].t, iobase - 0xd80 + 0x980, + maps[1].size, 0, &maps[1].h)) { + return 1; + } + (*num_mappings)++; + maps[2].t = iot; + maps[2].offset = 0; + maps[2].size = 0x40; /* XXX - ??? */ + if ((iobase - 0xd80 + 0x180) < 0 || (iobase - 0xd80 + 0x180) > 0x0ffff) + return 1; + if (bus_space_map(maps[2].t, iobase - 0xd80 + 0x180, + maps[2].size, 0, &maps[2].h)) { + return 1; + } + (*num_mappings)++; + maps[3].t = iot; + maps[3].offset = 0; + maps[3].size = 0x40; /* XXX - ??? */ + if ((iobase - 0xd80 + 0x580) < 0 || (iobase - 0xd80 + 0x580) > 0x0ffff) + return 1; + if (bus_space_map(maps[3].t, iobase - 0xd80 + 0x580, + maps[3].size, 0, &maps[3].h)) { + return 1; + } + (*num_mappings)++; + break; + + case FLAG_AVM_A1: + if (iobase == IOBASEUNK) { + printf("isic: config error: no i/o address specified for AVM A1/Fritz! card!\n"); + return 1; + } + if (iosize) *iosize = 8; /* only some i/o ports shown */ + if (msize) *msize = 0; /* no shared memory */ + + /* Seven io mappings: config, isac, 2 * hscx, + isac-fifo, 2 * hscx-fifo */ + if (maps == NULL) { + *num_mappings = 7; + return 0; + } + *num_mappings = 0; + maps[0].t = iot; /* config */ + maps[0].offset = 0; + maps[0].size = 8; + if ((iobase + 0x1800) < 0 || (iobase + 0x1800) > 0x0ffff) + return 1; + if (bus_space_map(maps[0].t, iobase + 0x1800, maps[0].size, 0, &maps[0].h)) + return 1; + (*num_mappings)++; + maps[1].t = iot; /* isac */ + maps[1].offset = 0; + maps[1].size = 0x80; /* XXX - ??? */ + if ((iobase + 0x1400 - 0x20) < 0 || (iobase + 0x1400 - 0x20) > 0x0ffff) + return 1; + if (bus_space_map(maps[1].t, iobase + 0x1400 - 0x20, maps[1].size, 0, &maps[1].h)) + return 1; + (*num_mappings)++; + maps[2].t = iot; /* hscx 0 */ + maps[2].offset = 0; + maps[2].size = 0x40; /* XXX - ??? */ + if ((iobase + 0x400 - 0x20) < 0 || (iobase + 0x400 - 0x20) > 0x0ffff) + return 1; + if (bus_space_map(maps[2].t, iobase + 0x400 - 0x20, maps[2].size, 0, &maps[2].h)) + return 1; + (*num_mappings)++; + maps[3].t = iot; /* hscx 1 */ + maps[3].offset = 0; + maps[3].size = 0x40; /* XXX - ??? */ + if ((iobase + 0xc00 - 0x20) < 0 || (iobase + 0xc00 - 0x20) > 0x0ffff) + return 1; + if (bus_space_map(maps[3].t, iobase + 0xc00 - 0x20, maps[3].size, 0, &maps[3].h)) + return 1; + (*num_mappings)++; + maps[4].t = iot; /* isac-fifo */ + maps[4].offset = 0; + maps[4].size = 1; + if ((iobase + 0x1400 - 0x20 -0x3e0) < 0 || (iobase + 0x1400 - 0x20 -0x3e0) > 0x0ffff) + return 1; + if (bus_space_map(maps[4].t, iobase + 0x1400 - 0x20 -0x3e0, maps[4].size, 0, &maps[4].h)) + return 1; + (*num_mappings)++; + maps[5].t = iot; /* hscx 0 fifo */ + maps[5].offset = 0; + maps[5].size = 1; + if ((iobase + 0x400 - 0x20 -0x3e0) < 0 || (iobase + 0x400 - 0x20 -0x3e0) > 0x0ffff) + return 1; + if (bus_space_map(maps[5].t, iobase + 0x400 - 0x20 -0x3e0, maps[5].size, 0, &maps[5].h)) + return 1; + (*num_mappings)++; + maps[6].t = iot; /* hscx 1 fifo */ + maps[6].offset = 0; + maps[6].size = 1; + if ((iobase + 0xc00 - 0x20 -0x3e0) < 0 || (iobase + 0xc00 - 0x20 -0x3e0) > 0x0ffff) + return 1; + if (bus_space_map(maps[6].t, iobase + 0xc00 - 0x20 -0x3e0, maps[6].size, 0, &maps[6].h)) + return 1; + (*num_mappings)++; + break; + + case FLAG_USR_ISDN_TA_INT: + if (iobase == IOBASEUNK) { + printf("isic: config error: no I/O base specified for USR Sportster TA intern!\n"); + return 1; + } + if (iosize) *iosize = 8; /* scattered ports, only some shown */ + if (msize) *msize = 0; /* no shared memory */ + + /* 49 io mappings: 1 config and 48x8 registers */ + if (maps == NULL) { + *num_mappings = 49; + return 0; + } + *num_mappings = 0; + { + int i, num; + bus_size_t base; + + /* config at offset 0x8000 */ + base = iobase + 0x8000; + maps[0].size = 1; + maps[0].t = iot; + maps[0].offset = 0; + if (base < 0 || base > 0x0ffff) + return 1; + if (bus_space_map(iot, base, 1, 0, &maps[0].h)) { + return 1; + } + *num_mappings = num = 1; + + /* HSCX A at offset 0 */ + base = iobase; + for (i = 0; i < 16; i++) { + maps[num].size = 8; + maps[num].offset = 0; + maps[num].t = iot; + if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff) + return 1; + if (bus_space_map(iot, base+i*1024, 8, 0, &maps[num].h)) { + return 1; + } + *num_mappings = ++num; + } + /* HSCX B at offset 0x4000 */ + base = iobase + 0x4000; + for (i = 0; i < 16; i++) { + maps[num].size = 8; + maps[num].offset = 0; + maps[num].t = iot; + if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff) + return 1; + if (bus_space_map(iot, base+i*1024, 8, 0, &maps[num].h)) { + return 1; + } + *num_mappings = ++num; + } + /* ISAC at offset 0xc000 */ + base = iobase + 0xc000; + for (i = 0; i < 16; i++) { + maps[num].size = 8; + maps[num].offset = 0; + maps[num].t = iot; + if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff) + return 1; + if (bus_space_map(iot, base+i*1024, 8, 0, &maps[num].h)) { + return 1; + } + *num_mappings = ++num; + } + } + break; + + case FLAG_ITK_IX1: + if (iobase == IOBASEUNK) { + printf("isic: config error: no I/O base specified for ITK ix1 micro!\n"); + return 1; + } + if (iosize) *iosize = 4; + if (msize) *msize = 0; + if (maps == NULL) { + *num_mappings = 1; + return 0; + } + *num_mappings = 0; + maps[0].size = 4; + maps[0].t = iot; + maps[0].offset = 0; + if (bus_space_map(iot, iobase, 4, 0, &maps[0].h)) { + return 1; + } + *num_mappings = 1; + break; + + default: + printf("isic: config error: flags do not specify any known card!\n"); + return 1; + break; + } + + return 0; +} + +static void +args_unmap(num_mappings, maps) + int *num_mappings; + struct isic_io_map *maps; +{ + int i, n; + for (i = 0, n = *num_mappings; i < n; i++) + if (maps[i].size) + bus_space_unmap(maps[i].t, maps[i].h, maps[i].size); + *num_mappings = 0; +} diff --git a/sys/dev/isa/isadaic.c b/sys/dev/isa/isadaic.c new file mode 100644 index 00000000000..86b79ab2d89 --- /dev/null +++ b/sys/dev/isa/isadaic.c @@ -0,0 +1,146 @@ +/*- + * Copyright (c) 1997, 2001 Martin Husemann <martin@duskware.de> + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/device.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/bus.h> + +#include <sys/socket.h> +#include <net/if.h> +#include <dev/isa/isavar.h> +#include <netisdn/i4b_ioctl.h> +#include <netisdn/i4b_l3l4.h> +#include <dev/ic/daicvar.h> + +/* driver state */ +struct isa_daic_softc { + struct daic sc_daic; /* MI driver state */ + void *sc_ih; /* interrupt handler */ +}; + +/* local functions */ +#ifdef __BROKEN_INDIRECT_CONFIG +static int isa_daic_probe __P((struct device *, void *, void *)); +#else +static int isa_daic_probe __P((struct device *, struct cfdata *, void *)); +#endif +static void isa_daic_attach __P((struct device *, struct device *, void *)); +static int isa_daic_intr __P((void *)); + +struct cfattach isa_daic_ca = { + sizeof(struct isa_daic_softc), isa_daic_probe, isa_daic_attach +}; + +static int +#ifdef __BROKEN_INDIRECT_CONFIG +isa_daic_probe(parent, match, aux) +#else +isa_daic_probe(parent, cf, aux) +#endif + struct device *parent; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *cf; +#endif + void *aux; +{ + struct isa_attach_args *ia = aux; + bus_space_tag_t memt = ia->ia_memt; + bus_space_handle_t memh; + int card; + + /* We need some controller memory to comunicate! */ + if (ia->ia_maddr == MADDRUNK || ia->ia_msize == -1) + goto bad; + + /* Map card RAM. */ + ia->ia_msize = DAIC_ISA_MEMSIZE; + ia->ia_iosize = 0; + if (bus_space_map(memt, ia->ia_maddr, ia->ia_msize, + 0, &memh)) + goto bad; + + /* MI check for card at this location */ + card = daic_probe(memt, memh); + if (card < 0) + goto bad; + if (card == DAIC_TYPE_QUAD) + ia->ia_msize = DAIC_ISA_QUADSIZE; + + bus_space_unmap(memt, memh, DAIC_ISA_MEMSIZE); + return 1; + +bad: + /* unmap card RAM */ + bus_space_unmap(memt, memh, DAIC_ISA_MEMSIZE); + return 0; +} + +static void +isa_daic_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct isa_daic_softc *sc = (void *)self; + struct isa_attach_args *ia = aux; + bus_space_tag_t memt = ia->ia_memt; + bus_space_handle_t memh; + + /* Map card RAM. */ + if (bus_space_map(memt, ia->ia_maddr, ia->ia_msize, + 0, &memh)) + return; + + sc->sc_daic.sc_iot = memt; + sc->sc_daic.sc_ioh = memh; + + /* MI initialization of card */ + daic_attach(self, &sc->sc_daic); + + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, isa_daic_intr, sc); +} + +/* + * Controller interrupt. + */ +static int +isa_daic_intr(arg) + void *arg; +{ + struct isa_daic_softc *sc = arg; + return daic_intr(&sc->sc_daic); +} diff --git a/sys/dev/isapnp/i4b_ctx_s0P.c b/sys/dev/isapnp/i4b_ctx_s0P.c new file mode 100644 index 00000000000..710541b9a67 --- /dev/null +++ b/sys/dev/isapnp/i4b_ctx_s0P.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 1997, 1999 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. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for Creatix PnP cards + * ============================================================ + * + * $Id: i4b_ctx_s0P.c,v 1.1.1.1 2001/01/05 12:50:18 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:38:29 2001] + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicpnp.h" +#if ISICPNP_CRTX_S0_P + +#include <sys/param.h> + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif + +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <netisdn/i4b_global.h> + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +#ifndef __FreeBSD__ +static u_int8_t ctxs0P_read_reg __P((struct l1_softc *sc, int what, bus_size_t offs)); +static void ctxs0P_write_reg __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void ctxs0P_read_fifo __P((struct l1_softc *sc, int what, void *buf, size_t size)); +static void ctxs0P_write_fifo __P((struct l1_softc *sc, int what, const void *data, size_t size)); +void isic_attach_Cs0P(struct l1_softc *sc); +#endif + +#ifdef __FreeBSD__ +#include <i386/isa/pnp.h> +extern void isicintr ( int unit ); +#endif + +/*---------------------------------------------------------------------------* + * Creatix ISDN-S0 P&P ISAC get fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +ctxs0P_read_fifo(void *buf, const void *base, size_t len) +{ + insb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +ctxs0P_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_read_multi_1(t, h, o + 0x3e, buf, size); +} + +#endif + +/*---------------------------------------------------------------------------* + * Creatix ISDN-S0 P&P ISAC put fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +ctxs0P_write_fifo(void *base, const void *buf, size_t len) +{ + outsb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +ctxs0P_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_multi_1(t, h, o + 0x3e, (u_int8_t*)buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * Creatix ISDN-S0 P&P ISAC put register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +ctxs0P_write_reg(u_char *base, u_int offset, u_int v) +{ + outb((int)base + offset, (u_char)v); +} + +#else + +static void +ctxs0P_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_1(t, h, o + offs, data); +} +#endif + +/*---------------------------------------------------------------------------* + * Creatix ISDN-S0 P&P ISAC get register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +ctxs0P_read_reg(u_char *base, u_int offset) +{ + return (inb((int)base + offset)); +} + +#else + +static u_int8_t +ctxs0P_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + return bus_space_read_1(t, h, o + offs); +} + +#endif + +#ifdef __FreeBSD__ + +/*---------------------------------------------------------------------------* + * isic_probe_Cs0P - probe for Creatix ISDN-S0 P&P and compatibles + *---------------------------------------------------------------------------*/ +int +isic_probe_Cs0P(struct isa_device *dev, unsigned int iobase2) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Creatix ISDN-S0 P&P!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq) - 1) + { + case 3: + case 5: + case 7: + case 10: + case 11: + case 12: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Creatix ISDN-S0 P&P!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Creatix ISDN-S0 P&P!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + dev->id_msize = 0; + + if(iobase2 == 0) + { + printf("isic%d: Error, iobase2 is 0 for Creatix ISDN-S0 P&P!\n", + dev->id_unit); + return(0); + } + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0x120: + case 0x180: +/*XXX*/ break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for Creatix ISDN-S0 P&P!\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = ctxs0P_read_reg; + sc->writereg = ctxs0P_write_reg; + + sc->readfifo = ctxs0P_read_fifo; + sc->writefifo = ctxs0P_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_CS0P; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t) dev->id_iobase - 0x20; + HSCX_A_BASE = (caddr_t) iobase2 - 0x20; + HSCX_B_BASE = (caddr_t) iobase2; + + /* + * Read HSCX A/B VSTR. Expected value for the Creatix PnP card is + * 0x05 ( = version 2.1 ) in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for Creatix PnP\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +/*---------------------------------------------------------------------------* + * isic_attach_s0163P - attach Creatix ISDN-S0 P&P + *---------------------------------------------------------------------------*/ +int +isic_attach_Cs0P(struct isa_device *dev, unsigned int iobase2) +{ + outb((dev->id_iobase) + 0x1c, 0); + DELAY(SEC_DELAY / 10); + outb((dev->id_iobase) + 0x1c, 1); + DELAY(SEC_DELAY / 10); + return(1); +} + +#else /* !__FreeBSD__ */ + +void +isic_attach_Cs0P(struct l1_softc *sc) +{ + /* init card */ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, 0x1c, 0); + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, 0x1c, 1); + DELAY(SEC_DELAY / 10); + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = ctxs0P_read_reg; + sc->writereg = ctxs0P_write_reg; + + sc->readfifo = ctxs0P_read_fifo; + sc->writefifo = ctxs0P_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_CS0P; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; +} +#endif + +#endif /* ISICPNP_CRTX_S0_P */ + diff --git a/sys/dev/isapnp/i4b_drn_ngo.c b/sys/dev/isapnp/i4b_drn_ngo.c new file mode 100644 index 00000000000..3d89dbf72eb --- /dev/null +++ b/sys/dev/isapnp/i4b_drn_ngo.c @@ -0,0 +1,534 @@ +/* + * Copyright (c) 1997, 1999 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. + * + *--------------------------------------------------------------------------- + * + * i4b_drn_ngo.c - Dr. Neuhaus Niccy GO@ and SAGEM Cybermod + * -------------------------------------------------------- + * + * $Id: i4b_drn_ngo.c,v 1.1.1.1 2001/01/05 12:50:18 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:38:29 2001] + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicpnp.h" +#ifdef ISICPNP_DRN_NGO + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <netisdn/i4b_global.h> + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +/*---------------------------------------------------------------------------* + * Niccy GO@ definitions + * + * the card uses 2 i/o addressranges each using 2 bytes + * + * addressrange 0: + * offset 0 - ISAC dataregister + * offset 1 - HSCX dataregister + * addressrange 1: + * offset 0 - ISAC addressregister + * offset 1 - HSCX addressregister + * + * to access an ISAC/HSCX register, you have to write the register + * number into the ISAC or HSCX addressregister and then read/write + * data for the ISAC/HSCX register into/from the corresponding + * dataregister. + * + * Thanks to Klaus Muehle of Dr. Neuhaus Telekommunikation for giving + * out this information! + * + *---------------------------------------------------------------------------*/ +#define NICCY_PORT_MIN 0x200 +#define NICCY_PORT_MAX 0x3e0 + +#define HSCX_ABIT 0x1000 /* flag, HSCX A is meant */ +#define HSCX_BBIT 0x2000 /* flag, HSCX B is meant */ + +#define HSCX_BOFF 0x40 + +#define ADDR_OFF 2 /* address register range offset XXX */ + +#define ISAC_DATA 0 +#define HSCX_DATA 1 + +#define ISAC_ADDR 0 +#define HSCX_ADDR 1 + +#ifdef __FreeBSD__ + +#if 0 +#define HSCXADEBUG +#define HSCXBDEBUG +#define ISACDEBUG +#else +#undef HSCXADEBUG +#undef HSCXBDEBUG +#undef ISACDEBUG +#endif + +/*---------------------------------------------------------------------------* + * Dr. Neuhaus Niccy GO@ read fifo routine + *---------------------------------------------------------------------------*/ +static void +drnngo_read_fifo(void *buf, const void *base, size_t len) +{ + register int offset; + register u_int data; + + int x = SPLI4B(); + + if((u_int)base & HSCX_ABIT) + { + (u_int)base &= ~HSCX_ABIT; + (u_int)data = ((u_int)base + HSCX_DATA); + (u_int)base += (ADDR_OFF + HSCX_ADDR); + offset = 0; +#ifdef HSCXADEBUG +printf("GO/A/frd: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + else if((u_int)base & HSCX_BBIT) + { + (u_int)base &= ~HSCX_BBIT; + (u_int)data = ((u_int)base + HSCX_DATA); + (u_int)base += (ADDR_OFF + HSCX_ADDR); + offset = HSCX_BOFF; +#ifdef HSCXBDEBUG +printf("GO/B/frd: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + else + { + (u_int)data = ((u_int)base + ISAC_DATA); + (u_int)base += (ADDR_OFF + ISAC_ADDR); + offset = 0; +#ifdef ISACDEBUG +printf("GO/I/frd: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + + for(;len > 0; len--, offset++) + { + outb((int)base, (u_char)offset); + *((u_char *)buf + offset) = inb((int)data); + } + + splx(x); +} + +/*---------------------------------------------------------------------------* + * Dr. Neuhaus Niccy GO@ write fifo routine + *---------------------------------------------------------------------------*/ +static void +drnngo_write_fifo(void *base, const void *buf, size_t len) +{ + register int offset; + register u_int data; + + int x = SPLI4B(); + + if((u_int)base & HSCX_ABIT) + { + (u_int)base &= ~HSCX_ABIT; + (u_int)data = ((u_int)base + HSCX_DATA); + (u_int)base += (ADDR_OFF + HSCX_ADDR); + offset = 0; +#ifdef HSCXADEBUG +printf("GO/A/fwr: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + else if((u_int)base & HSCX_BBIT) + { + (u_int)base &= ~HSCX_BBIT; + (u_int)data = ((u_int)base + HSCX_DATA); + (u_int)base += (ADDR_OFF + HSCX_ADDR); + offset = HSCX_BOFF; +#ifdef HSCXBDEBUG +printf("GO/B/fwr: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + else + { + (u_int)data = ((u_int)base + ISAC_DATA); + (u_int)base += (ADDR_OFF + ISAC_ADDR); + offset = 0; +#ifdef ISACDEBUG +printf("GO/I/fwr: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + + for(;len > 0; len--, offset++) + { + outb((int)base, (u_char)offset); + outb((int)data, *((u_char *)buf + offset)); + } + + splx(x); +} + +/*---------------------------------------------------------------------------* + * Dr. Neuhaus Niccy GO@ write register routine + *---------------------------------------------------------------------------*/ +static void +drnngo_write_reg(u_char *base, u_int offset, u_int v) +{ + int x = SPLI4B(); + if((u_int)base & HSCX_ABIT) + { + (u_int)base &= ~HSCX_ABIT; + outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)offset); + outb((int)base + HSCX_DATA, (u_char)v); +#ifdef HSCXADEBUG +printf("GO/A/rwr: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA, + (u_char)offset, (u_char)v); +#endif + } + else if((u_int)base & HSCX_BBIT) + { + (u_int)base &= ~HSCX_BBIT; + outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)(offset + HSCX_BOFF)); + outb((int)base + HSCX_DATA, (u_char)v); +#ifdef HSCXBDEBUG +printf("GO/B/rwr: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA, + (u_char)(offset + HSCX_BOFF), (u_char)v); +#endif + } + else + { + outb((int)base + ADDR_OFF + ISAC_ADDR, (u_char)offset); + outb((int)base + ISAC_DATA, (u_char)v); +#ifdef ISACDEBUG +printf("GO/I/rwr: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + ISAC_ADDR, (int)base + ISAC_DATA, + (u_char)offset, (u_char)v); +#endif + } + splx(x); +} + +/*---------------------------------------------------------------------------* + * Dr. Neuhaus Niccy GO@ read register routine + *---------------------------------------------------------------------------*/ +static u_char +drnngo_read_reg(u_char *base, u_int offset) +{ + u_char val; + int x = SPLI4B(); + + if((u_int)base & HSCX_ABIT) + { + (u_int)base &= ~HSCX_ABIT; + outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)offset); + val = inb((int)base + HSCX_DATA); +#ifdef HSCXADEBUG +printf("GO/A/rrd: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA, + (u_char)offset, (u_char)val); +#endif + } + else if((u_int)base & HSCX_BBIT) + { + (u_int)base &= ~HSCX_BBIT; + outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)(offset + HSCX_BOFF)); + val = inb((int)base + HSCX_DATA); +#ifdef HSCXBDEBUG +printf("GO/B/rrd: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA, + (u_char)(offset + HSCX_BOFF), (u_char)val); +#endif + } + else + { + outb((int)base + ADDR_OFF + ISAC_ADDR, (u_char)offset); + val = inb((int)base + ISAC_DATA); +#ifdef ISACDEBUG +printf("GO/I/rrd: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + ISAC_ADDR, (int)base + ISAC_DATA, + (u_char)offset, (u_char)val); +#endif + } + splx(x); + return(val); +} + +/*---------------------------------------------------------------------------* + * isic_probe_drnngo - probe for Dr. Neuhaus Niccy GO@ + *---------------------------------------------------------------------------*/ +int +isic_probe_drnngo(struct isa_device *dev, unsigned int iobase2) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq)-1) + { + case 3: + case 4: + case 5: + case 9: + case 10: + case 11: + case 12: + case 15: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + dev->id_msize = 0; + + /* check if we got an iobase */ + + if(dev->id_iobase < NICCY_PORT_MIN || dev->id_iobase > NICCY_PORT_MAX) + { + printf("isic%d: Error, invalid iobase 0x%x specified for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit, dev->id_iobase); + return(0); + } + sc->sc_port = dev->id_iobase; + + if(iobase2 == 0) + { + printf("isic%d: Error, iobase2 is 0 for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit); + return(0); + } + + if(iobase2 < NICCY_PORT_MIN || iobase2 > NICCY_PORT_MAX) + { + printf("isic%d: Error, invalid port1 0x%x specified for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit, iobase2); + return(0); + } + +/*XXX*/ if((dev->id_iobase + 2) != iobase2) + { + printf("isic%d: Error, port1 must be (port0+2) for Dr.Neuhaus Niccy GO@!\n", + dev->id_unit); + return(0); + } + + /* setup ISAC access routines */ + + sc->clearirq = NULL; + sc->readreg = drnngo_read_reg; + sc->writereg = drnngo_write_reg; + + sc->readfifo = drnngo_read_fifo; + sc->writefifo = drnngo_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_DRNNGO; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t)dev->id_iobase; + HSCX_A_BASE = (caddr_t)(((u_int)dev->id_iobase) | HSCX_ABIT); + HSCX_B_BASE = (caddr_t)(((u_int)dev->id_iobase) | HSCX_BBIT); + + /* + * Read HSCX A/B VSTR. Expected value for Dr. Neuhaus Niccy GO@ based + * boards is 0x05 in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for Dr. Neuhaus Niccy GO@\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +/*---------------------------------------------------------------------------* + * isic_attach_drnngo - attach Dr. Neuhaus Niccy GO@ + *---------------------------------------------------------------------------*/ +int +isic_attach_drnngo(struct isa_device *dev, unsigned int iobase2) +{ + return (1); +} + +#else + +static u_int8_t drnngo_read_reg __P((struct l1_softc *sc, int what, bus_size_t offs)); +static void drnngo_write_reg __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void drnngo_read_fifo __P((struct l1_softc *sc, int what, void *buf, size_t size)); +static void drnngo_write_fifo __P((struct l1_softc *sc, int what, const void *data, size_t size)); +void isic_attach_drnngo __P((struct l1_softc *sc)); + +/* + * Mapping from "what" parameter to offsets into the io map + */ +static struct { + bus_size_t oa, /* address register offset */ + od, /* data register offset */ + or; /* additional chip register offset */ +} offset[] = +{ + { ISAC_ADDR, ISAC_DATA, 0 }, /* ISAC access */ + { HSCX_ADDR, HSCX_DATA, 0 }, /* HSCX A access */ + { HSCX_ADDR, HSCX_DATA, HSCX_BOFF } /* HSCX B access */ +}; + +static void +drnngo_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h; + bus_space_write_1(t, ha, offset[what].oa, offset[what].or); + bus_space_read_multi_1(t, hd, offset[what].od, buf, size); +} + +static void +drnngo_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h; + bus_space_write_1(t, ha, offset[what].oa, offset[what].or); + bus_space_write_multi_1(t, hd, offset[what].od, (u_int8_t*)buf, size); +} + +static void +drnngo_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h; + bus_space_write_1(t, ha, offset[what].oa, offs+offset[what].or); + bus_space_write_1(t, hd, offset[what].od, data); +} + +static u_int8_t +drnngo_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h; + bus_space_write_1(t, ha, offset[what].oa, offs+offset[what].or); + return bus_space_read_1(t, hd, offset[what].od); +} + +void +isic_attach_drnngo(struct l1_softc *sc) +{ + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = drnngo_read_reg; + sc->writereg = drnngo_write_reg; + + sc->readfifo = drnngo_read_fifo; + sc->writefifo = drnngo_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_DRNNGO; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; +} + +#endif + +#endif /* ISICPNP_DRN_NGO */ diff --git a/sys/dev/isapnp/i4b_dynalink.c b/sys/dev/isapnp/i4b_dynalink.c new file mode 100644 index 00000000000..65bc1006828 --- /dev/null +++ b/sys/dev/isapnp/i4b_dynalink.c @@ -0,0 +1,570 @@ +/* + * Copyright (c) 1998 Martijn Plak. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * isdn4bsd layer1 driver for Dynalink IS64PH isdn TA + * ================================================== + * + * $Id: i4b_dynalink.c,v 1.1.1.1 2001/01/05 12:50:17 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:38:29 2001] + * + * written by Martijn Plak (martijn@be3.com) + * + * -mp 11 jun 1998 first try, code borrowed from Creatix driver + * -mp 18 jun 1998 cleaned up code + * -hm FreeBSD PnP + * -mp 17 dec 1998 made it compile again + * + *---------------------------------------------------------------------------*/ + +/* NOTES: + + This driver was written for the Dynalink IS64PH ISDN TA, based on two + Siemens chips (HSCX 21525 and ISAC 2186). It is sold in the Netherlands. + + model numbers found on (my) card: + IS64PH, TAS100H-N, P/N:89590555, TA200S100045521 + + chips: + Siemens PSB 21525N, HSCX TE V2.1 + Siemens PSB 2186N, ISAC-S TE V1.1 + 95MS14, PNP + + plug-and-play info: + device id "ASU1688" + vendor id 0x88167506 + serial 0x00000044 + i/o port 4 byte alignment, 4 bytes requested, + 10 bit i/o decoding, 0x100-0x3f8 (?) + irq 3,4,5,9,10,11,12,15, high true, edge sensitive + + At the moment I'm writing this Dynalink is replacing this card with + one based on a single Siemens chip (IPAC). It will apparently be sold + under the same model name. + + This driver might also work for Asuscom cards. +*/ + +#include "opt_isicpnp.h" +#ifdef ISICPNP_DYNALINK + +/* HEADERS +*/ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#if __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#include <i386/isa/pnp.h> +#elif defined(__bsdi__) +#include <i386/isa/pnp.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#if defined(__FreeBSD__) || defined(__bsdi__) +static void dynalink_read_fifo(void *buf, const void *base, size_t len); +static void dynalink_write_fifo(void *base, const void *buf, size_t len); +static void dynalink_write_reg(u_char *base, u_int offset, u_int v); +static u_char dynalink_read_reg(u_char *base, u_int offset); +#endif + +#ifdef __FreeBSD__ +extern struct isa_driver isicdriver; +#endif +#ifdef __bsdi__ +extern struct cfdriver isiccd; +#endif + +#if !defined(__FreeBSD__) && !defined(__bsdi__) +static void dynalink_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size); +static void dynalink_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size); +static void dynalink_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data); +static u_int8_t dynalink_read_reg(struct l1_softc *sc, int what, bus_size_t offs); +void isic_attach_Dyn(struct l1_softc *sc); +#endif + +/* io address mapping */ +#define ISAC 0 +#define HSCX 1 +#define ADDR 2 + +/* ADDR bits */ +#define ADDRMASK 0x7F +#define RESET 0x80 + +/* HSCX register offsets */ +#define HSCXA 0x00 +#define HSCXB 0x40 + +#if defined(__FreeBSD__) || defined(__bsdi__) +/* base address juggling */ +#define HSCXB_HACK 0x400 +#define IOBASE(addr) (((int)addr)&0x3FC) +#define IOADDR(addr) (((int)addr)&0x3FF) +#define IS_HSCXB_HACK(addr) ((((int)addr)&HSCXB_HACK)?HSCXB:HSCXA) +#endif + +#ifdef __FreeBSD__ +/* ISIC probe and attach +*/ + +int +isic_probe_Dyn(struct isa_device *dev, unsigned int iobase2) +{ + + struct l1_softc *sc = &l1_sc[dev->id_unit]; + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Dynalink IS64PH.\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq) - 1) + { + case 3: + case 4: + case 5: + case 9: + case 10: + case 11: + case 12: + case 15: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Dynalink IS64PH.\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Dynalink IS64PH.\n", + dev->id_unit, (u_long)dev->id_maddr); + return (0); + } + dev->id_msize = 0; + + /* check if we got an iobase */ + if ( (dev->id_iobase < 0x100) || + (dev->id_iobase > 0x3f8) || + (dev->id_iobase & 3) ) + { + printf("isic%d: Error, invalid iobase 0x%x specified for Dynalink!\n", dev->id_unit, dev->id_iobase); + return(0); + } + sc->sc_port = dev->id_iobase; + + /* setup access routines */ + sc->clearirq = NULL; + sc->readreg = dynalink_read_reg; + sc->writereg = dynalink_write_reg; + sc->readfifo = dynalink_read_fifo; + sc->writefifo = dynalink_write_fifo; + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_DYNALINK; + + /* setup IOM bus type */ + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + ISAC_BASE = (caddr_t) sc->sc_port; + HSCX_A_BASE = (caddr_t) sc->sc_port + 1; + HSCX_B_BASE = (caddr_t) sc->sc_port + 1 + HSCXB_HACK; + + /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1). */ + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for Dynalink\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +int +isic_attach_Dyn(struct isa_device *dev, unsigned int iobase2) +{ + outb((dev->id_iobase)+ADDR, RESET); + DELAY(SEC_DELAY / 10); + outb((dev->id_iobase)+ADDR, 0); + DELAY(SEC_DELAY / 10); + return(1); +} + +#elif defined(__bsdi__) + +/* ISIC probe and attach +*/ + +static int +set_softc(struct l1_softc *sc, struct isa_attach_args *ia, int unit) +{ + if (unit >= NISIC) + return 0; + sc->sc_unit = unit; + switch(ffs(ia->ia_irq) - 1) + { + case 3: + case 4: + case 5: + case 9: + case 10: + case 11: + case 12: + case 15: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Dynalink IS64PH.\n", + unit, ffs(ia->ia_irq)-1); + return(0); + break; + } + sc->sc_irq = ia->ia_irq; + + /* check if memory addr specified */ + + if(ia->ia_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Dynalink IS64PH.\n", + unit, (u_long)ia->ia_maddr); + return (0); + } + + /* check if we got an iobase */ + if ( (ia->ia_iobase < 0x100) || + (ia->ia_iobase > 0x3f8) || + (ia->ia_iobase & 3) ) + { + printf("isic%d: Error, invalid iobase 0x%x specified for Dynalink!\n", unit, ia->ia_iobase); + return(0); + } + sc->sc_port = ia->ia_iobase; + + /* setup access routines */ + sc->clearirq = NULL; + sc->readreg = dynalink_read_reg; + sc->writereg = dynalink_write_reg; + sc->readfifo = dynalink_read_fifo; + sc->writefifo = dynalink_write_fifo; + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_DYNALINK; + + /* setup IOM bus type */ + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + ISAC_BASE = (caddr_t) sc->sc_port; + HSCX_A_BASE = (caddr_t) sc->sc_port + 1; + HSCX_B_BASE = (caddr_t) sc->sc_port + 1 + HSCXB_HACK; + return 1; +} + +int +isapnp_match_dynalink(struct device *parent, struct cfdata *cf, + struct isa_attach_args *ia) +{ + struct l1_softc dummysc, *sc = &dummysc; + pnp_resource_t res; + char *ids[] = {"ASU1688", NULL}; + bzero(&res, sizeof res); + res.res_irq[0].irq_level = ia->ia_irq; + res.res_port[0].prt_base = ia->ia_iobase; + res.res_port[0].prt_length = 4; + + if (!pnp_assigndev(ids, isiccd.cd_name, &res)) + return (0); + + ia->ia_irq = res.res_irq[0].irq_level; + ia->ia_iobase = res.res_port[0].prt_base; + ia->ia_iosize = res.res_port[0].prt_length; + + if (set_softc(sc, ia, cf->cf_unit) == 0) + return 0; + + /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1). */ + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for Dynalink\n", + cf->cf_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + cf->cf_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + cf->cf_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + cf->cf_flags = FLAG_DYNALINK; + return (1); +} + +int +isic_attach_Dyn(struct device *parent, struct device *self, + struct isa_attach_args *ia) +{ + struct l1_softc *sc = (struct l1_softc *)self; + int unit = sc->sc_dev.dv_unit; + + /* Commit the probed attachment values */ + if (set_softc(sc, ia, unit) == 0) + panic("isic_attach_Dyn: set_softc"); + + outb((ia->ia_iobase)+ADDR, RESET); + DELAY(SEC_DELAY / 10); + outb((ia->ia_iobase)+ADDR, 0); + DELAY(SEC_DELAY / 10); + return(1); +} + +#else + +void isic_attach_Dyn(struct l1_softc *sc) +{ + /* setup access routines */ + sc->clearirq = NULL; + sc->readreg = dynalink_read_reg; + sc->writereg = dynalink_write_reg; + sc->readfifo = dynalink_read_fifo; + sc->writefifo = dynalink_write_fifo; + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_DYNALINK; + + /* setup IOM bus type */ + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1). */ + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("%s: HSCX VSTR test failed for Dynalink PnP\n", + sc->sc_dev.dv_xname); + printf("%s: HSC0: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(0, H_VSTR)); + printf("%s: HSC1: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(1, H_VSTR)); + return; + } + + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR, RESET); + DELAY(SEC_DELAY / 10); + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR, 0); + DELAY(SEC_DELAY / 10); +} + +#endif + +/* LOW-LEVEL DEVICE ACCESS + + NOTE: The isdn4bsd code expects the two HSCX channels at different + base addresses. I'm faking this, and remap them to the same address + in the low-level routines. Search for HSCXB_HACK and IS_HSCXB_HACK. + + REM: this is only true for the FreeBSD version of I4B! +*/ + +#if defined(__FreeBSD__) || defined(__bsdi__) +static void +dynalink_read_fifo(void *buf, const void *base, size_t len) +{ + outb(IOBASE(base)+ADDR, 0+IS_HSCXB_HACK(base)); + insb(IOADDR(base), (u_char *)buf, (u_int)len); +} +#else +static void +dynalink_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR, 0); + bus_space_read_multi_1(t, h, ISAC, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR, HSCXA); + bus_space_read_multi_1(t, h, HSCX, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR, HSCXB); + bus_space_read_multi_1(t, h, HSCX, buf, size); + break; + } +} +#endif + +#if defined(__FreeBSD__) || defined(__bsdi__) +static void +dynalink_write_fifo(void *base, const void *buf, size_t len) +{ + outb(IOBASE(base)+ADDR, 0+IS_HSCXB_HACK(base)); + outsb(IOADDR(base), (u_char *)buf, (u_int)len); +} +#else +static void dynalink_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR, 0); + bus_space_write_multi_1(t, h, ISAC, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR, HSCXA); + bus_space_write_multi_1(t, h, HSCX, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR, HSCXB); + bus_space_write_multi_1(t, h, HSCX, (u_int8_t*)buf, size); + break; + } +} +#endif + +#if defined(__FreeBSD__) || defined(__bsdi__) +static void +dynalink_write_reg(u_char *base, u_int offset, u_int v) +{ + outb(IOBASE(base)+ADDR, (offset+IS_HSCXB_HACK(base))&ADDRMASK); + outb(IOADDR(base), (u_char)v); +} +#else +static void dynalink_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR, offs); + bus_space_write_1(t, h, ISAC, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR, HSCXA+offs); + bus_space_write_1(t, h, HSCX, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR, HSCXB+offs); + bus_space_write_1(t, h, HSCX, data); + break; + } +} +#endif + +#if defined(__FreeBSD__) || defined(__bsdi__) +static u_char +dynalink_read_reg(u_char *base, u_int offset) +{ + outb(IOBASE(base)+ADDR, (offset+IS_HSCXB_HACK(base))&ADDRMASK); + return (inb(IOADDR(base))); +} +#else +static u_int8_t dynalink_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR, offs); + return bus_space_read_1(t, h, ISAC); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR, HSCXA+offs); + return bus_space_read_1(t, h, HSCX); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR, HSCXB+offs); + return bus_space_read_1(t, h, HSCX); + } + return 0; +} +#endif + +#endif /* ISICPNP_DYNALINK */ diff --git a/sys/dev/isapnp/i4b_elsa_qs1i.c b/sys/dev/isapnp/i4b_elsa_qs1i.c new file mode 100644 index 00000000000..d7d388c52cd --- /dev/null +++ b/sys/dev/isapnp/i4b_elsa_qs1i.c @@ -0,0 +1,501 @@ +/* + * Copyright (c) 1997, 1999 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. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for ELSA Quickstep 1000pro ISA + * ===================================================================== + * + * $Id: i4b_elsa_qs1i.c,v 1.1.1.1 2001/01/05 12:50:17 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:38:29 2001] + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicpnp.h" +#if defined(ISICPNP_ELSA_QS1ISA) || defined(ISICPNP_ELSA_PCC16) + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#if __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#include <i386/isa/pnp.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#ifdef __FreeBSD__ +static void i4b_eq1i_clrirq(void* base); +#else +static void i4b_eq1i_clrirq(struct l1_softc *sc); +void isic_attach_Eqs1pi __P((struct l1_softc *sc)); +#endif + +/* masks for register encoded in base addr */ + +#define ELSA_BASE_MASK 0x0ffff +#define ELSA_OFF_MASK 0xf0000 + +/* register id's to be encoded in base addr */ + +#define ELSA_IDISAC 0x00000 +#define ELSA_IDHSCXA 0x10000 +#define ELSA_IDHSCXB 0x20000 + +/* offsets from base address */ + +#define ELSA_OFF_ISAC 0x00 +#define ELSA_OFF_HSCX 0x02 +#define ELSA_OFF_OFF 0x03 +#define ELSA_OFF_CTRL 0x04 +#define ELSA_OFF_CFG 0x05 +#define ELSA_OFF_TIMR 0x06 +#define ELSA_OFF_IRQ 0x07 + +/* control register (write access) */ + +#define ELSA_CTRL_LED_YELLOW 0x02 +#define ELSA_CTRL_LED_GREEN 0x08 +#define ELSA_CTRL_RESET 0x20 +#define ELSA_CTRL_TIMEREN 0x80 +#define ELSA_CTRL_SECRET 0x50 + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/ISA clear IRQ routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +i4b_eq1i_clrirq(void* base) +{ + outb((u_int)base + ELSA_OFF_IRQ, 0); +} + +#else +static void +i4b_eq1i_clrirq(struct l1_softc *sc) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, ELSA_OFF_IRQ, 0); +} +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/ISA ISAC get fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pi_read_fifo(void *buf, const void *base, size_t len) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0x40); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX), (u_char *)buf, (u_int)len); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX), (u_char *)buf, (u_int)len); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ISAC), (u_char *)buf, (u_int)len); + } +} + +#else + +static void +eqs1pi_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0); + bus_space_read_multi_1(t, h, ELSA_OFF_ISAC, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0); + bus_space_read_multi_1(t, h, ELSA_OFF_HSCX, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40); + bus_space_read_multi_1(t, h, ELSA_OFF_HSCX, buf, size); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/ISA ISAC put fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pi_write_fifo(void *base, const void *buf, size_t len) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0x40); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX), (u_char *)buf, (u_int)len); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX), (u_char *)buf, (u_int)len); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ISAC), (u_char *)buf, (u_int)len); + } +} + +#else + +static void +eqs1pi_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0); + bus_space_write_multi_1(t, h, ELSA_OFF_ISAC, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0); + bus_space_write_multi_1(t, h, ELSA_OFF_HSCX, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40); + bus_space_write_multi_1(t, h, ELSA_OFF_HSCX, (u_int8_t*)buf, size); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/ISA ISAC put register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pi_write_reg(u_char *base, u_int offset, u_int v) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)(offset+0x40)); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX, (u_char)v); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)offset); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX, (u_char)v); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)offset); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ISAC, (u_char)v); + } +} + +#else + +static void +eqs1pi_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_OFF, offs); + bus_space_write_1(t, h, ELSA_OFF_ISAC, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_OFF, offs); + bus_space_write_1(t, h, ELSA_OFF_HSCX, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40+offs); + bus_space_write_1(t, h, ELSA_OFF_HSCX, data); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/ISA ISAC get register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +eqs1pi_read_reg(u_char *base, u_int offset) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)(offset+0x40)); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX)); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)offset); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX)); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)offset); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ISAC)); + } +} + +#else + +static u_int8_t +eqs1pi_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_OFF, offs); + return bus_space_read_1(t, h, ELSA_OFF_ISAC); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_OFF, offs); + return bus_space_read_1(t, h, ELSA_OFF_HSCX); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40+offs); + return bus_space_read_1(t, h, ELSA_OFF_HSCX); + } + return 0; +} + +#endif + +#ifdef __FreeBSD__ + +/*---------------------------------------------------------------------------* + * isic_probe_Eqs1pi - probe for ELSA QuickStep 1000pro/ISA and compatibles + *---------------------------------------------------------------------------*/ +int +isic_probe_Eqs1pi(struct isa_device *dev, unsigned int iobase2) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for ELSA QuickStep 1000pro/ISA!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq) - 1) + { + case 3: + case 4: + case 5: + case 7: + case 10: + case 11: + case 12: + case 15: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for ELSA QuickStep 1000pro/ISA!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for ELSA QuickStep 1000pro/ISA!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + dev->id_msize = 0; + + /* check if we got an iobase */ + + if(!((dev->id_iobase >= 0x160) && (dev->id_iobase <= 0x360))) + { + printf("isic%d: Error, invalid iobase 0x%x specified for ELSA QuickStep 1000pro/ISA!\n", + dev->id_unit, dev->id_iobase); + return(0); + } + sc->sc_port = dev->id_iobase; + + /* setup access routines */ + + sc->clearirq = i4b_eq1i_clrirq; + sc->readreg = eqs1pi_read_reg; + sc->writereg = eqs1pi_write_reg; + + sc->readfifo = eqs1pi_read_fifo; + sc->writefifo = eqs1pi_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_ELSAQS1ISA; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t) ((u_int)dev->id_iobase | ELSA_IDISAC); + HSCX_A_BASE = (caddr_t) ((u_int)dev->id_iobase | ELSA_IDHSCXA); + HSCX_B_BASE = (caddr_t) ((u_int)dev->id_iobase | ELSA_IDHSCXB); + + /* + * Read HSCX A/B VSTR. Expected value for the ELSA QuickStep 1000pro + * ISA card is 0x05 ( = version 2.1 ) in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for ELSA QuickStep 1000pro/ISA\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +/*---------------------------------------------------------------------------* + * isic_attach_s0163P - attach ELSA QuickStep 1000pro/ISA + *---------------------------------------------------------------------------*/ +int +isic_attach_Eqs1pi(struct isa_device *dev, unsigned int iobase2) +{ + u_char byte = ELSA_CTRL_SECRET; + + byte &= ~ELSA_CTRL_RESET; + outb(dev->id_iobase + ELSA_OFF_CTRL, byte); + DELAY(20); + byte |= ELSA_CTRL_RESET; + outb(dev->id_iobase + ELSA_OFF_CTRL, byte); + + DELAY(20); + outb(dev->id_iobase + ELSA_OFF_IRQ, 0xff); + + return(1); +} + +#else /* !__FreeBSD__ */ + +void +isic_attach_Eqs1pi(struct l1_softc *sc) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + u_char byte = ELSA_CTRL_SECRET; + + byte &= ~ELSA_CTRL_RESET; + bus_space_write_1(t, h, ELSA_OFF_CTRL, byte); + DELAY(20); + byte |= ELSA_CTRL_RESET; + bus_space_write_1(t, h, ELSA_OFF_CTRL, byte); + + DELAY(20); + bus_space_write_1(t, h, ELSA_OFF_IRQ, 0xff); + + /* setup access routines */ + + sc->clearirq = i4b_eq1i_clrirq; + sc->readreg = eqs1pi_read_reg; + sc->writereg = eqs1pi_write_reg; + + sc->readfifo = eqs1pi_read_fifo; + sc->writefifo = eqs1pi_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_ELSAQS1ISA; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; +} + +#endif + +#endif /* ISICPNP_ELSA_QS1ISA or ISICPNP_ELSA_PCC16 */ diff --git a/sys/dev/isapnp/i4b_siemens_isurf.c b/sys/dev/isapnp/i4b_siemens_isurf.c new file mode 100644 index 00000000000..0b4c4c1e7e5 --- /dev/null +++ b/sys/dev/isapnp/i4b_siemens_isurf.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 1999 Udo Schweigert. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * Based on ELSA Quickstep 1000pro PCI driver (i4b_elsa_qs1p.c) + *--------------------------------------------------------------------------- + * In case of trouble please contact Udo Schweigert <ust@cert.siemens.de> + *--------------------------------------------------------------------------- + * + * Siemens I-Surf 2.0 PnP specific routines for isic driver + * -------------------------------------------------------- + * + * $Id: i4b_siemens_isurf.c,v 1.1.1.1 2001/01/05 12:50:18 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:38:29 2001] + * + *---------------------------------------------------------------------------*/ + + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#if defined(__FreeBSD__) +#if __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif + +#include <machine/clock.h> +#include <i386/isa/isa_device.h> + +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__FreeBSD__) +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_ipac.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#if !defined(__FreeBSD__) +void isic_attach_siemens_isurf __P((struct l1_softc *sc)); +#endif + +/* masks for register encoded in base addr */ + +#define SIE_ISURF_BASE_MASK 0x0ffff +#define SIE_ISURF_OFF_MASK 0xf0000 + +/* register id's to be encoded in base addr */ + +#define SIE_ISURF_IDISAC 0x00000 +#define SIE_ISURF_IDHSCXA 0x10000 +#define SIE_ISURF_IDHSCXB 0x20000 +#define SIE_ISURF_IDIPAC 0x40000 + +/* offsets from base address */ + +#define SIE_ISURF_OFF_ALE 0x00 +#define SIE_ISURF_OFF_RW 0x01 + +/*---------------------------------------------------------------------------* + * Siemens I-Surf 2.0 PnP ISAC get fifo routine + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD__) + +static void +siemens_isurf_read_fifo(void *buf, const void *base, size_t len) +{ + if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB) + { + outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF); + insb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (u_char *)buf, (u_int)len); + } + else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA) + { + outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF); + insb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (u_char *)buf, (u_int)len); + } + else /* if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC) */ + { + outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF); + insb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (u_char *)buf, (u_int)len); + } +} + +#else + +static void +siemens_isurf_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF); + bus_space_read_multi_1(t, h, SIE_ISURF_OFF_RW, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF); + bus_space_read_multi_1(t, h, SIE_ISURF_OFF_RW, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF); + bus_space_read_multi_1(t, h, SIE_ISURF_OFF_RW, buf, size); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * Siemens I-Surf 2.0 PnP ISAC put fifo routine + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD__) + +static void +siemens_isurf_write_fifo(void *base, const void *buf, size_t len) +{ + if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB) + { + outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF); + outsb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (const u_char *)buf, (u_int)len); + } + else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA) + { + outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF); + outsb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (const u_char *)buf, (u_int)len); + } + else /* if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC) */ + { + outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF); + outsb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (const u_char *)buf, (u_int)len); + } +} + +#else + +static void +siemens_isurf_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF); + bus_space_write_multi_1(t, h, SIE_ISURF_OFF_RW, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF); + bus_space_write_multi_1(t, h, SIE_ISURF_OFF_RW, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF); + bus_space_write_multi_1(t, h, SIE_ISURF_OFF_RW, (u_int8_t*)buf, size); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * Siemens I-Surf 2.0 PnP ISAC put register routine + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD__) + +static void +siemens_isurf_write_reg(u_char *base, u_int offset, u_int v) +{ + if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB) + { + outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF)); + outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v); + } + else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA) + { + outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF)); + outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v); + } + else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC) + { + outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF)); + outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v); + } + else /* IPAC */ + { + outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF)); + outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v); + } +} + +#else + +static void +siemens_isurf_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF+offs); + bus_space_write_1(t, h, SIE_ISURF_OFF_RW, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF+offs); + bus_space_write_1(t, h, SIE_ISURF_OFF_RW, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF+offs); + bus_space_write_1(t, h, SIE_ISURF_OFF_RW, data); + break; + case ISIC_WHAT_IPAC: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_IPAC_OFF+offs); + bus_space_write_1(t, h, SIE_ISURF_OFF_RW, data); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * Siemens I-Surf 2.0 PnP ISAC get register routine + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD__) + +static u_char +siemens_isurf_read_reg(u_char *base, u_int offset) +{ + if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB) + { + outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF)); + return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW)); + } + else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA) + { + outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF)); + return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW)); + } + else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC) + { + outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF)); + return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW)); + } + else /* IPAC */ + { + outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF)); + return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW)); + } +} + +#else + +static u_int8_t +siemens_isurf_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF+offs); + return bus_space_read_1(t, h, SIE_ISURF_OFF_RW); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF+offs); + return bus_space_read_1(t, h, SIE_ISURF_OFF_RW); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF+offs); + return bus_space_read_1(t, h, SIE_ISURF_OFF_RW); + case ISIC_WHAT_IPAC: + bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_IPAC_OFF+offs); + return bus_space_read_1(t, h, SIE_ISURF_OFF_RW); + } + return 0; +} + +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_siemens_isurf - probe for Siemens I-Surf 2.0 PnP + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD__) + +int +isic_probe_siemens_isurf(struct isa_device *dev, unsigned int iobase2) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Siemens I-Surf 2.0 PnP\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq) - 1) + { + case 3: + case 4: + case 5: + case 7: + case 10: + case 11: + case 12: + case 15: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Siemens I-Surf 2.0 PnP!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Siemens I-Surf 2.0 PnP!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + dev->id_msize = 0; + + /* check if we got an iobase */ + + if(!((dev->id_iobase >= 0x100) && (dev->id_iobase <= 0xfffc))) + { + printf("isic%d: Error, invalid iobase 0x%x specified for Siemens I-Surf 2.0 PnP!\n", + dev->id_unit, dev->id_iobase); + return(0); + } + sc->sc_port = dev->id_iobase; + + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = siemens_isurf_read_reg; + sc->writereg = siemens_isurf_write_reg; + + sc->readfifo = siemens_isurf_read_fifo; + sc->writefifo = siemens_isurf_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_SIE_ISURF2; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + /* setup chip type = IPAC ! */ + + sc->sc_ipac = 1; + sc->sc_bfifolen = IPAC_BFIFO_LEN; + + + return (1); +} + +/*---------------------------------------------------------------------------* + * isic_attach_siemens_isurf - attach for Siemens I-Surf 2.0 PnP + *---------------------------------------------------------------------------*/ +int +isic_attach_siemens_isurf(struct isa_device *dev, unsigned int iobase2) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t) ((u_int)sc->sc_port | SIE_ISURF_IDISAC); + HSCX_A_BASE = (caddr_t) ((u_int)sc->sc_port | SIE_ISURF_IDHSCXA); + HSCX_B_BASE = (caddr_t) ((u_int)sc->sc_port | SIE_ISURF_IDHSCXB); + IPAC_BASE = (caddr_t) ((u_int)sc->sc_port | SIE_ISURF_IDIPAC); + + /* enable hscx/isac irq's */ + IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0)); + + IPAC_WRITE(IPAC_ACFG, 0); /* outputs are open drain */ + IPAC_WRITE(IPAC_AOE, /* aux 5..2 are inputs, 7, 6 outputs */ + (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2)); + IPAC_WRITE(IPAC_ATX, 0xff); /* set all output lines high */ + + return(1); +} + +#else + +void +isic_attach_siemens_isurf(struct l1_softc *sc) +{ + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = siemens_isurf_read_reg; + sc->writereg = siemens_isurf_write_reg; + + sc->readfifo = siemens_isurf_read_fifo; + sc->writefifo = siemens_isurf_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_SIE_ISURF2; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + /* setup chip type = IPAC ! */ + + sc->sc_ipac = 1; + sc->sc_bfifolen = IPAC_BFIFO_LEN; + + /* enable hscx/isac irq's */ + + IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0)); + + IPAC_WRITE(IPAC_ACFG, 0); /* outputs are open drain */ + IPAC_WRITE(IPAC_AOE, /* aux 5..2 are inputs, 7, 6 outputs */ + (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2)); + IPAC_WRITE(IPAC_ATX, 0xff); /* set all output lines high */ +} + +#endif diff --git a/sys/dev/isapnp/i4b_sws.c b/sys/dev/isapnp/i4b_sws.c new file mode 100644 index 00000000000..7b17aa5d385 --- /dev/null +++ b/sys/dev/isapnp/i4b_sws.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 1998 German Tischler. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * Card format: + * + * iobase + 0 : reset on (0x03) + * iobase + 1 : reset off (0x0) + * iobase + 2 : isac read/write + * iobase + 3 : hscx read/write ( offset 0-0x3f hscx0 , + * offset 0x40-0x7f hscx1 ) + * iobase + 4 : offset for indirect adressing + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for SWS cards + * ==================================================== + * + * EXPERIMENTAL !!!! + * ================= + * + * $Id: i4b_sws.c,v 1.1.1.1 2001/01/05 12:50:17 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:38:29 2001] + * + * -hm adding driver to i4b + * -hm adjustments for FreeBSD < 2.2.6, no PnP support yet + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicpnp.h" +#ifdef ISICPNP_SEDLBAUER + +#define SWS_RESON 0 /* reset on */ +#define SWS_RESOFF 1 /* reset off */ +#define SWS_ISAC 2 /* ISAC */ +#define SWS_HSCX0 3 /* HSCX0 */ +#define SWS_RW 4 /* indirect access register */ +#define SWS_HSCX1 5 /* this is for fakeing that we mean hscx1, though */ + /* access is done through hscx0 */ + +#define SWS_REGS 8 /* we use an area of 8 bytes for io */ + +#define SWS_BASE(X) ((unsigned int)X&~(SWS_REGS-1)) +#define SWS_PART(X) ((unsigned int)X& (SWS_REGS-1)) +#define SWS_ADDR(X) ((SWS_PART(X) == SWS_ISAC) ? (SWS_BASE(X)+SWS_ISAC) : (SWS_BASE(X)+SWS_HSCX0) ) +#define SWS_REG(X,Y) ((SWS_PART(X) != SWS_HSCX1) ? Y : (Y+0x40) ) +#define SWS_IDO(X) (SWS_BASE(X)+SWS_RW) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +#ifndef __FreeBSD__ +static u_int8_t sws_read_reg __P((struct l1_softc *sc, int what, bus_size_t offs)); +static void sws_write_reg __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void sws_read_fifo __P((struct l1_softc *sc, int what, void *buf, size_t size)); +static void sws_write_fifo __P((struct l1_softc *sc, int what, const void *data, size_t size)); +void isic_attach_sws __P((struct l1_softc *sc)); +#endif + +/*---------------------------------------------------------------------------* + * SWS P&P ISAC get fifo routine + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ + +static void +sws_read_fifo(void *buf, const void *base, size_t len) +{ + outb(SWS_IDO(base),SWS_REG(base,0)); + insb(SWS_ADDR(base),buf,len); +} + +#else + +static void +sws_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SWS_RW, 0); + bus_space_read_multi_1(t, h, SWS_ISAC, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SWS_RW, 0); + bus_space_read_multi_1(t, h, SWS_HSCX0, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SWS_RW, 0x40); + bus_space_read_multi_1(t, h, SWS_HSCX0, buf, size); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * SWS P&P ISAC put fifo routine + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ + +static void +sws_write_fifo(void *base, const void *buf, size_t len) +{ + outb (SWS_IDO(base),SWS_REG(base,0)); + outsb(SWS_ADDR(base),buf,len); +} + +#else + +static void +sws_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SWS_RW, 0); + bus_space_write_multi_1(t, h, SWS_ISAC, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SWS_RW, 0); + bus_space_write_multi_1(t, h, SWS_HSCX0, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SWS_RW, 0x40); + bus_space_write_multi_1(t, h, SWS_HSCX0, (u_int8_t*)buf, size); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * SWS P&P ISAC put register routine + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ + +static void +sws_write_reg(u_char *base, u_int offset, u_int v) +{ + outb(SWS_IDO(base),SWS_REG(base,offset)); + outb(SWS_ADDR(base),v); +} + +#else + +static void +sws_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SWS_RW, offs); + bus_space_write_1(t, h, SWS_ISAC, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SWS_RW, offs); + bus_space_write_1(t, h, SWS_HSCX0, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SWS_RW, 0x40+offs); + bus_space_write_1(t, h, SWS_HSCX0, data); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * SWS P&P ISAC get register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +sws_read_reg(u_char *base, u_int offset) +{ + outb(SWS_IDO(base),SWS_REG(base,offset)); + return inb(SWS_ADDR(base)); +} + +#else + +static u_int8_t +sws_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SWS_RW, offs); + return bus_space_read_1(t, h, SWS_ISAC); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SWS_RW, offs); + return bus_space_read_1(t, h, SWS_HSCX0); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SWS_RW, 0x40+offs); + return bus_space_read_1(t, h, SWS_HSCX0); + } + return 0; +} + +#endif + +#ifdef __FreeBSD__ + +/* attach callback routine */ + +int +isic_attach_sws(struct isa_device *dev) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + + /* fill in l1_softc structure */ + + sc->readreg = sws_read_reg; + sc->writereg = sws_write_reg; + sc->readfifo = sws_read_fifo; + sc->writefifo = sws_write_fifo; + sc->clearirq = NULL; + sc->sc_unit = dev->id_unit; + sc->sc_irq = dev->id_irq; + sc->sc_port = dev->id_iobase; + sc->sc_cardtyp = CARD_TYPEP_SWS; + sc->sc_bustyp = BUS_TYPE_IOM2; + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + dev->id_msize = 0; + + ISAC_BASE = (caddr_t) (((u_int) sc->sc_port) + SWS_ISAC); + HSCX_A_BASE = (caddr_t) (((u_int) sc->sc_port) + SWS_HSCX0); + HSCX_B_BASE = (caddr_t) (((u_int) sc->sc_port) + SWS_HSCX1); + + /* + * Read HSCX A/B VSTR. Expected value for the SWS PnP card is + * 0x05 ( = version 2.1 ) in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for SWS PnP\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + /* reset card */ + + outb( ((u_int) sc->sc_port) + SWS_RESON , 0x3); + DELAY(SEC_DELAY / 5); + outb( ((u_int) sc->sc_port) + SWS_RESOFF, 0); + DELAY(SEC_DELAY / 5); + + return(1); +} + +#else /* !__FreeBSD__ */ + +void +isic_attach_sws(struct l1_softc *sc) +{ + /* setup access routines */ + + sc->readreg = sws_read_reg; + sc->writereg = sws_write_reg; + + sc->readfifo = sws_read_fifo; + sc->writefifo = sws_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_SWS; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* + * Read HSCX A/B VSTR. Expected value for the SWS PnP card is + * 0x05 ( = version 2.1 ) in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("%s: HSCX VSTR test failed for SWS PnP\n", + sc->sc_dev.dv_xname); + printf("%s: HSC0: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(0, H_VSTR)); + printf("%s: HSC1: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(1, H_VSTR)); + return; + } + + /* reset card */ + { + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, SWS_RESON, 0x3); + DELAY(SEC_DELAY / 5); + bus_space_write_1(t, h, SWS_RESOFF, 0); + DELAY(SEC_DELAY / 5); + } +} + +#endif /* !__FreeBSD__ */ + +#endif /* ISICPNP_SEDLBAUER */ diff --git a/sys/dev/isapnp/i4b_tel_s0P.c b/sys/dev/isapnp/i4b_tel_s0P.c new file mode 100644 index 00000000000..fc979ee2ccf --- /dev/null +++ b/sys/dev/isapnp/i4b_tel_s0P.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 1997 Andrew Gordon. All rights reserved. + * + * Copyright (c) 1997, 1999 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for Teles S0 PnP + * ======================================================= + * + * EXPERIMENTAL !!! + * ================ + * + * $Id: i4b_tel_s0P.c,v 1.1.1.1 2001/01/05 12:50:18 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:38:29 2001] + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicpnp.h" +#ifdef ISICPNP_TEL_S0_16_3_P + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +#ifndef __FreeBSD__ +static u_int8_t tels0163P_read_reg __P((struct l1_softc *sc, int what, bus_size_t offs)); +static void tels0163P_write_reg __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void tels0163P_read_fifo __P((struct l1_softc *sc, int what, void *buf, size_t size)); +static void tels0163P_write_fifo __P((struct l1_softc *sc, int what, const void *data, size_t size)); +void isic_attach_s0163P __P((struct l1_softc *sc)); +#endif + + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 PnP read fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels0163P_read_fifo(void *buf, const void *base, size_t len) +{ + insb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +tels0163P_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_read_multi_1(t, h, o + 0x3e, buf, size); +} + +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 PnP write fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels0163P_write_fifo(void *base, const void *buf, size_t len) +{ + outsb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +tels0163P_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_multi_1(t, h, o + 0x3e, (u_int8_t*)buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 PnP write register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels0163P_write_reg(u_char *base, u_int offset, u_int v) +{ + outb((int)base + offset, (u_char)v); +} + +#else + +static void +tels0163P_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_1(t, h, o + offs, data); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 PnP read register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +tels0163P_read_reg(u_char *base, u_int offset) +{ + return (inb((int)base + offset)); +} + +#else + +static u_int8_t +tels0163P_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + return bus_space_read_1(t, h, o + offs); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_s0163P - probe for Teles S0/16.3 PnP and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_probe_s0163P(struct isa_device *dev, unsigned int iobase2) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles S0/16.3 PnP!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq) - 1) + { + case 3: + case 5: + case 7: + case 10: + case 11: + case 12: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/16.3 PnP!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Teles S0/16.3 PnP!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + dev->id_msize = 0; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0x580: + case 0x500: + case 0x680: + break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for Teles S0/16.3 PnP!\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels0163P_read_reg; + sc->writereg = tels0163P_write_reg; + + sc->readfifo = tels0163P_read_fifo; + sc->writefifo = tels0163P_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_163P; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + switch(dev->id_iobase) + { + case 0x580: + ISAC_BASE = (caddr_t) 0x580 - 0x20; + HSCX_A_BASE = (caddr_t) 0x180 - 0x20; + HSCX_B_BASE = (caddr_t) 0x180; + break; + + case 0x500: + ISAC_BASE = (caddr_t) 0x500 - 0x20; + HSCX_A_BASE = (caddr_t) 0x100 - 0x20; + HSCX_B_BASE = (caddr_t) 0x100; + break; + + case 0x680: + ISAC_BASE = (caddr_t) 0x680 - 0x20; + HSCX_A_BASE = (caddr_t) 0x280 - 0x20; + HSCX_B_BASE = (caddr_t) 0x280; + break; + } + + /* + * Read HSCX A/B VSTR. Expected value for the S0/16.3 PnP card is + * 0x05 in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for Teles S0/16.3 PnP\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_s0163P - attach Teles S0/16.3 PnP and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_attach_s0163P(struct isa_device *dev, unsigned int iobase2) +{ + outb((dev->id_iobase) + 0x1c, 0); + DELAY(SEC_DELAY / 10); + outb((dev->id_iobase) + 0x1c, 1); + DELAY(SEC_DELAY / 10); + return(1); +} + +#else + +void +isic_attach_s0163P(struct l1_softc *sc) +{ + /* init card */ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, 0x1c, 0); + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, 0x1c, 1); + DELAY(SEC_DELAY / 10); + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels0163P_read_reg; + sc->writereg = tels0163P_write_reg; + + sc->readfifo = tels0163P_read_fifo; + sc->writefifo = tels0163P_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_163P; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; +} +#endif + +#endif /* ISICPNP_TEL_S0_16_3_P */ + diff --git a/sys/dev/isapnp/isapnp_isic.c b/sys/dev/isapnp/isapnp_isic.c new file mode 100644 index 00000000000..44069c46a86 --- /dev/null +++ b/sys/dev/isapnp/isapnp_isic.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 1997, 1998 Martin Husemann. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * isapnp_isic.c - ISA-P&P bus frontend for i4b_isic driver + * -------------------------------------------------------- + * + * $Id: isapnp_isic.c,v 1.1.1.1 2001/01/05 12:50:16 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:38:29 2001] + * + * -mh original implementation + * -hm NetBSD patches from Martin + * + *---------------------------------------------------------------------------*/ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/systm.h> +#include <sys/malloc.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/isa/isavar.h> +#include <dev/isapnp/isapnpreg.h> +#include <dev/isapnp/isapnpvar.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <netisdn/i4b_ioctl.h> +#include <netisdn/i4b_trace.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_ipac.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_global.h> + +#include "opt_isicpnp.h" + +#ifdef __BROKEN_INDIRECT_CONFIG +static int isapnp_isic_probe __P((struct device *, void *, void *)); +#else +static int isapnp_isic_probe __P((struct device *, struct cfdata *, void *)); +#endif +static void isapnp_isic_attach __P((struct device *, struct device *, void *)); + +struct cfattach isapnp_isic_ca = { + sizeof(struct l1_softc), isapnp_isic_probe, isapnp_isic_attach +}; + +typedef void (*allocmaps_func)(struct isapnp_attach_args *ipa, struct l1_softc *sc); +typedef void (*attach_func)(struct l1_softc *sc); + +/* map allocators */ +static void generic_pnp_mapalloc(struct isapnp_attach_args *ipa, struct l1_softc *sc); +#ifdef ISICPNP_DRN_NGO +static void ngo_pnp_mapalloc(struct isapnp_attach_args *ipa, struct l1_softc *sc); +#endif +#if defined(ISICPNP_CRTX_S0_P) || defined(ISICPNP_TEL_S0_16_3_P) +static void tls_pnp_mapalloc(struct isapnp_attach_args *ipa, struct l1_softc *sc); +#endif + +/* card attach functions */ +extern void isic_attach_Cs0P __P((struct l1_softc *sc)); +extern void isic_attach_Dyn __P((struct l1_softc *sc)); +extern void isic_attach_s0163P __P((struct l1_softc *sc)); +extern void isic_attach_drnngo __P((struct l1_softc *sc)); +extern void isic_attach_sws __P((struct l1_softc *sc)); +extern void isic_attach_Eqs1pi __P((struct l1_softc *sc)); +extern void isic_attach_siemens_isurf __P((struct l1_softc *sc)); + +struct isapnp_isic_card_desc { + char *devlogic; /* ISAPNP logical device ID */ + char *name; /* Name of the card */ + int card_type; /* isic card type identifier */ + allocmaps_func allocmaps; /* map allocator function */ + attach_func attach; /* card attach and init function */ +}; +static const struct isapnp_isic_card_desc +isapnp_isic_descriptions[] = +{ +#ifdef ISICPNP_CRTX_S0_P + { "CTX0000", "Creatix ISDN S0-16 P&P", CARD_TYPEP_CS0P, + tls_pnp_mapalloc, isic_attach_Cs0P }, +#endif +#ifdef ISICPNP_TEL_S0_16_3_P + { "TAG2110", "Teles S0/PnP", CARD_TYPEP_163P, + tls_pnp_mapalloc, isic_attach_s0163P }, +#endif +#ifdef ISICPNP_DRN_NGO + { "SDA0150", "Dr. Neuhaus NICCY GO@", CARD_TYPEP_DRNNGO, + ngo_pnp_mapalloc, isic_attach_drnngo }, +#endif +#ifdef ISICPNP_ELSA_QS1ISA + { "ELS0133", "Elsa QuickStep 1000 (ISA)", CARD_TYPEP_ELSAQS1ISA, + generic_pnp_mapalloc, isic_attach_Eqs1pi }, +#endif +#ifdef ISICPNP_SEDLBAUER + { "SAG0001", "Sedlbauer WinSpeed", CARD_TYPEP_SWS, + generic_pnp_mapalloc, isic_attach_sws }, +#endif +#ifdef ISICPNP_DYNALINK + { "ASU1688", "Dynalink IS64PH", CARD_TYPEP_DYNALINK, + generic_pnp_mapalloc, isic_attach_Dyn }, +#endif +#ifdef ISICPNP_SIEMENS_ISURF2 + { "SIE0020", "Siemens I-Surf 2.0 PnP", CARD_TYPEP_SIE_ISURF2, + generic_pnp_mapalloc, isic_attach_siemens_isurf }, +#endif +}; +#define NUM_DESCRIPTIONS (sizeof(isapnp_isic_descriptions)/sizeof(isapnp_isic_descriptions[0])) + +/* + * Probe card + */ +static int +#ifdef __BROKEN_INDIRECT_CONFIG +isapnp_isic_probe(parent, match, aux) +#else +isapnp_isic_probe(parent, cf, aux) +#endif + struct device *parent; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *cf; +#endif + void *aux; +{ + struct isapnp_attach_args *ipa = aux; + const struct isapnp_isic_card_desc *desc = isapnp_isic_descriptions; + int i; + + for (i = 0; i < NUM_DESCRIPTIONS; i++, desc++) + if (strcmp(ipa->ipa_devlogic, desc->devlogic) == 0) + return 1; + + return 0; +} + + +/*---------------------------------------------------------------------------* + * card independend attach for ISA P&P cards + *---------------------------------------------------------------------------*/ + +/* parameter and format for message producing e.g. "isic0: " */ + +#ifdef __FreeBSD__ +#define ISIC_FMT "isic%d: " +#define ISIC_PARM dev->id_unit +#define TERMFMT " " +#else +#define ISIC_FMT "%s: " +#define ISIC_PARM sc->sc_dev.dv_xname +#define TERMFMT "\n" +#endif + +static void +isapnp_isic_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + static char *ISACversion[] = { + "2085 Version A1/A2 or 2086/2186 Version 1.1", + "2085 Version B1", + "2085 Version B2", + "2085 Version V2.3 (B3)", + "Unknown Version" + }; + + static char *HSCXversion[] = { + "82525 Version A1", + "Unknown (0x01)", + "82525 Version A2", + "Unknown (0x03)", + "82525 Version A3", + "82525 or 21525 Version 2.1", + "Unknown Version" + }; + + struct l1_softc *sc = (void *)self; + struct isapnp_attach_args *ipa = aux; + const struct isapnp_isic_card_desc *desc = isapnp_isic_descriptions; + int i; + + for (i = 0; i < NUM_DESCRIPTIONS; i++, desc++) + if (strcmp(ipa->ipa_devlogic, desc->devlogic) == 0) + break; + if (i >= NUM_DESCRIPTIONS) + panic("could not identify isic PnP device"); + + /* setup parameters */ + sc->sc_cardtyp = desc->card_type; + sc->sc_unit = sc->sc_dev.dv_unit; + sc->sc_irq = ipa->ipa_irq[0].num; + desc->allocmaps(ipa, sc); + + /* announce card name */ + printf(": %s\n", desc->name); + + /* establish interrupt handler */ + if (isa_intr_establish(ipa->ipa_ic, ipa->ipa_irq[0].num, IST_EDGE, + IPL_NET, isicintr, sc) == NULL) + printf("%s: couldn't establish interrupt handler\n", + sc->sc_dev.dv_xname); + + /* init card */ + l1_sc[sc->sc_unit] = sc; + desc->attach(sc); + + /* announce chip versions */ + sc->sc_isac_version = 0; + sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; + + switch(sc->sc_isac_version) + { + case ISAC_VA: + case ISAC_VB1: + case ISAC_VB2: + case ISAC_VB3: + break; + + default: + printf(ISIC_FMT "Error, ISAC version %d unknown!\n", + ISIC_PARM, sc->sc_isac_version); + return; + break; + } + + sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; + + switch(sc->sc_hscx_version) + { + case HSCX_VA1: + case HSCX_VA2: + case HSCX_VA3: + case HSCX_V21: + break; + + default: + printf(ISIC_FMT "Error, HSCX version %d unknown!\n", + ISIC_PARM, sc->sc_hscx_version); + return; + break; + }; + + /* ISAC setup */ + + isic_isac_init(sc); + + /* HSCX setup */ + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* setup linktab */ + + isic_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 + callout_init(&sc->sc_T3_callout); + callout_init(&sc->sc_T4_callout); +#endif + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + /* announce chip versions */ + + if(sc->sc_isac_version >= ISAC_UNKN) + { + printf(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_isac_version); + sc->sc_isac_version = ISAC_UNKN; + } + else + { + printf(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT, + ISIC_PARM, + ISACversion[sc->sc_isac_version], + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + } + + if(sc->sc_hscx_version >= HSCX_UNKN) + { + printf(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_hscx_version); + sc->sc_hscx_version = HSCX_UNKN; + } + else + { + printf(ISIC_FMT "HSCX %s" TERMFMT, + ISIC_PARM, + HSCXversion[sc->sc_hscx_version]); + } +} + +static void +generic_pnp_mapalloc(struct isapnp_attach_args *ipa, struct l1_softc *sc) +{ + sc->sc_num_mappings = 1; /* most cards have just one mapping */ + MALLOC_MAPS(sc); /* malloc the maps */ + sc->sc_maps[0].t = ipa->ipa_iot; /* copy the access handles */ + sc->sc_maps[0].h = ipa->ipa_io[0].h; + sc->sc_maps[0].size = 0; /* foreign mapping, leave it alone */ +} + +#ifdef ISICPNP_DRN_NGO +static void +ngo_pnp_mapalloc(struct isapnp_attach_args *ipa, struct l1_softc *sc) +{ + sc->sc_num_mappings = 2; /* one data, one address mapping */ + MALLOC_MAPS(sc); /* malloc the maps */ + sc->sc_maps[0].t = ipa->ipa_iot; /* copy the access handles */ + sc->sc_maps[0].h = ipa->ipa_io[0].h; + sc->sc_maps[0].size = 0; /* foreign mapping, leave it alone */ + sc->sc_maps[1].t = ipa->ipa_iot; + sc->sc_maps[1].h = ipa->ipa_io[1].h; + sc->sc_maps[1].size = 0; +} +#endif + +#if defined(ISICPNP_CRTX_S0_P) || defined(ISICPNP_TEL_S0_16_3_P) +static void +tls_pnp_mapalloc(struct isapnp_attach_args *ipa, struct l1_softc *sc) +{ + sc->sc_num_mappings = 4; /* config, isac, 2 * hscx */ + MALLOC_MAPS(sc); /* malloc the maps */ + sc->sc_maps[0].t = ipa->ipa_iot; /* copy the access handles */ + sc->sc_maps[0].h = ipa->ipa_io[0].h; + sc->sc_maps[0].size = 0; /* foreign mapping, leave it alone */ + sc->sc_maps[1].t = ipa->ipa_iot; + sc->sc_maps[1].h = ipa->ipa_io[0].h; + sc->sc_maps[1].size = 0; + sc->sc_maps[1].offset = - 0x20; + sc->sc_maps[2].t = ipa->ipa_iot; + sc->sc_maps[2].offset = - 0x20; + sc->sc_maps[2].h = ipa->ipa_io[1].h; + sc->sc_maps[2].size = 0; + sc->sc_maps[3].t = ipa->ipa_iot; + sc->sc_maps[3].offset = 0; + sc->sc_maps[3].h = ipa->ipa_io[1].h; + sc->sc_maps[3].size = 0; +} +#endif diff --git a/sys/dev/microcode/daic/Makefile b/sys/dev/microcode/daic/Makefile new file mode 100644 index 00000000000..ef250072b5b --- /dev/null +++ b/sys/dev/microcode/daic/Makefile @@ -0,0 +1,31 @@ +# The Microcode for the Eicon.Diehl active ISDN cards comes in two parts. +# A tiny bootstrap loader delivered by Diehl as "dnload.bin" and a +# D-channel protocol specific file, e.g. "te_etsi.sx" for the SX card +# running E-DSS1. +# We can not deliver either of these files. The user is assumed to use +# the ones distributed with his card or download the newest version from +# http://www.diehl.de. +# The bootstrap loader is compiled into the kernel, as it is needed to +# identify the card. The protocol specific part is later downloaded by +# the ISDN management daemon. + +.NOPATH: dnload.bin +.if exists(dnload.bin) +# Real part - the bootstrap image is available. We convert it into a +# static byte array via the "gendnloadh" shell script. +dnload.h: dnload.bin + @rm -f dnload.h + @sh ./gendnloadh +.else +# Fake part - user did not copy the necessary file here. Compilation will +# fail with an error explaining his fault. +dnload.h: dnload.h-dist + cp dnload.h-dist dnload.h +.endif + +clean: + rm -f dnload.h + +cleandir: clean + +includes: dnload.h diff --git a/sys/dev/microcode/daic/dnload.h-dist b/sys/dev/microcode/daic/dnload.h-dist new file mode 100644 index 00000000000..11f3fbf6217 --- /dev/null +++ b/sys/dev/microcode/daic/dnload.h-dist @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1997,2001 Martin Husemann <martin@duskware.de> + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + */ +/* + * File: dnload.h + * This file is usualy generated from the binary bootstrap image + * delivered with the ISDN controller. Just copy the file "dnload.bin" + * to this directory, run "make" here and the kernel will compile fine. + * If you don't have this software, download the newest version of + * the DOS driver software for your card from http://www.diehl.de, + * extract the archive and copy "dnload.bin" here. + */ + +#error "You did not copy 'dnload.bin' to sys/dev/microcode/daic and ran 'make' there" + +/* ------------------------------------------------------------------------- */ +static u_int8_t dnload[] = { + 0 +}; + +/* ------------------------------------------------------------------------- */ diff --git a/sys/dev/microcode/daic/gendnloadh b/sys/dev/microcode/daic/gendnloadh new file mode 100644 index 00000000000..29e8b1b8d00 --- /dev/null +++ b/sys/dev/microcode/daic/gendnloadh @@ -0,0 +1,47 @@ +#!/bin/sh + +# Copyright (c) 1997,2001 Martin Husemann <martin@duskware.de> +# 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. The name of the author may not be used to endorse or promote products +# derived from this software withough specific prior written permission +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + +echo "Generating dnload.h from dnload.bin" + +cat << EOF > dnload.h +/* + * File: dnload.h + * Generated from: `ls -lT dnload.bin | awk '{print $10, $6, $7, $8, $9}'` + * By: `id -un`@`hostname`, `date` + * + * DO NOT EDIT THIS FILE! + */ + +/* ------------------------------------------------------------------------- */ +static u_int8_t dnload[] = { +EOF + +hexdump -v -e '" /* %04.4_ax */\t" 8/1 "0x%02x, " "\n"' -s 0x200 dnload.bin >> dnload.h + +cat << EOF >> dnload.h + 0 +}; + +/* ------------------------------------------------------------------------- */ +EOF diff --git a/sys/dev/pci/i4b_avm_fritz_pci.c b/sys/dev/pci/i4b_avm_fritz_pci.c new file mode 100644 index 00000000000..b2ba7368801 --- /dev/null +++ b/sys/dev/pci/i4b_avm_fritz_pci.c @@ -0,0 +1,1756 @@ +/* + * Copyright (c) 1999 Gary Jennejohn. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * a lot of code was borrowed from i4b_bchan.c and i4b_hscx.c + *--------------------------------------------------------------------------- + * + * Fritz!Card PCI specific routines for isic driver + * ------------------------------------------------ + * + * $Id: i4b_avm_fritz_pci.c,v 1.1.1.1 2001/01/05 12:50:20 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:38:58 2001] + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicpci.h" +#ifdef ISICPCI_AVM_A1 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#include <pci/pcivar.h> /* for pcici_t */ +#if __FreeBSD__ < 3 +#include <pci/pcireg.h> +#include <pci/pcibus.h> +#endif /* __FreeBSD__ < 3 */ +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#ifndef __FreeBSD__ + +#include <dev/pci/pci_isic.h> + +/* PCI config map to use (only one in this driver) */ +#define FRITZPCI_PORT0_MAPOFF PCI_MAPREG_START+4 + +#endif + +/* prototypes */ +static void avma1pp_disable(struct l1_softc *); +static int isic_hscx_fifo(l1_bchan_state_t *chan, struct l1_softc *sc); + +#ifdef __FreeBSD__ + +static void avma1pp_intr(struct l1_softc *); +static void avma1pp_disable(struct l1_softc *); +void avma1pp_map_int(pcici_t , void *, unsigned *); +static void hscx_write_reg(int, u_int, u_int, struct l1_softc *); +static u_char hscx_read_reg(int, u_int, struct l1_softc *); +static u_int hscx_read_reg_int(int, u_int, struct l1_softc *); +static void hscx_read_fifo(int, void *, size_t, struct l1_softc *); +static void hscx_write_fifo(int, const void *, size_t, struct l1_softc *); +static void avma1pp_hscx_int_handler(struct l1_softc *); +static void avma1pp_hscx_intr(int, u_int, struct l1_softc *); +static void avma1pp_init_linktab(struct l1_softc *); +static void avma1pp_bchannel_setup(int, int, int, int); +static void avma1pp_bchannel_start(int, int); +static void avma1pp_hscx_init(struct l1_softc *, int, int); +static void avma1pp_bchannel_stat(int, int, bchan_statistics_t *); +static void avma1pp_set_linktab(int, int, drvr_link_t *); +static isdn_link_t * avma1pp_ret_linktab(int, int); +int isic_attach_avma1pp(int, u_int, u_int); +extern void isicintr_sc(struct l1_softc *); + +#else + +static int avma1pp_intr(void*); +static void avma1pp_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size); +static void avma1pp_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size); +static void avma1pp_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data); +static u_int8_t avma1pp_read_reg(struct l1_softc *sc, int what, bus_size_t offs); +static void hscx_write_fifo(int chan, const void *buf, size_t len, struct l1_softc *sc); +static void hscx_read_fifo(int chan, void *buf, size_t len, struct l1_softc *sc); +static void hscx_write_reg(int chan, u_int off, u_int val, struct l1_softc *sc); +static u_char hscx_read_reg(int chan, u_int off, struct l1_softc *sc); +static u_int hscx_read_reg_int(int chan, u_int off, struct l1_softc *sc); +static void avma1pp_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp); +static void avma1pp_map_int(struct pci_l1_softc *sc, struct pci_attach_args *pa); +static void avma1pp_bchannel_setup(int unit, int h_chan, int bprot, int activate); +static void avma1pp_init_linktab(struct l1_softc *); +#endif + +/*---------------------------------------------------------------------------* + * AVM PCI Fritz!Card special registers + *---------------------------------------------------------------------------*/ + +/* + * register offsets from i/o base + */ +#define STAT0_OFFSET 0x02 +#define STAT1_OFFSET 0x03 +#define ADDR_REG_OFFSET 0x04 +/*#define MODREG_OFFSET 0x06 +#define VERREG_OFFSET 0x07*/ + +/* these 2 are used to select an ISAC register set */ +#define ISAC_LO_REG_OFFSET 0x04 +#define ISAC_HI_REG_OFFSET 0x06 + +/* offset higher than this goes to the HI register set */ +#define MAX_LO_REG_OFFSET 0x2f + +/* mask for the offset */ +#define ISAC_REGSET_MASK 0x0f + +/* the offset from the base to the ISAC registers */ +#define ISAC_REG_OFFSET 0x10 + +/* the offset from the base to the ISAC FIFO */ +#define ISAC_FIFO 0x02 + +/* not really the HSCX, but sort of */ +#define HSCX_FIFO 0x00 +#define HSCX_STAT 0x04 + +/* + * AVM PCI Status Latch 0 read only bits + */ +#define ASL_IRQ_ISAC 0x01 /* ISAC interrupt, active low */ +#define ASL_IRQ_HSCX 0x02 /* HSX interrupt, active low */ +#define ASL_IRQ_TIMER 0x04 /* Timer interrupt, active low */ +#define ASL_IRQ_BCHAN ASL_IRQ_HSCX +/* actually active LOW */ +#define ASL_IRQ_Pending (ASL_IRQ_ISAC | ASL_IRQ_HSCX | ASL_IRQ_TIMER) + +/* + * AVM Status Latch 0 write only bits + */ +#define ASL_RESET_ALL 0x01 /* reset siemens IC's, active 1 */ +#define ASL_TIMERDISABLE 0x02 /* active high */ +#define ASL_TIMERRESET 0x04 /* active high */ +#define ASL_ENABLE_INT 0x08 /* active high */ +#define ASL_TESTBIT 0x10 /* active high */ + +/* + * AVM Status Latch 1 write only bits + */ +#define ASL1_INTSEL 0x0f /* active high */ +#define ASL1_ENABLE_IOM 0x80 /* active high */ + +/* + * "HSCX" mode bits + */ +#define HSCX_MODE_ITF_FLG 0x01 +#define HSCX_MODE_TRANS 0x02 +#define HSCX_MODE_CCR_7 0x04 +#define HSCX_MODE_CCR_16 0x08 +#define HSCX_MODE_TESTLOOP 0x80 + +/* + * "HSCX" status bits + */ +#define HSCX_STAT_RME 0x01 +#define HSCX_STAT_RDO 0x10 +#define HSCX_STAT_CRCVFRRAB 0x0E +#define HSCX_STAT_CRCVFR 0x06 +#define HSCX_STAT_RML_MASK 0x3f00 + +/* + * "HSCX" interrupt bits + */ +#define HSCX_INT_XPR 0x80 +#define HSCX_INT_XDU 0x40 +#define HSCX_INT_RPR 0x20 +#define HSCX_INT_MASK 0xE0 + +/* + * "HSCX" command bits + */ +#define HSCX_CMD_XRS 0x80 +#define HSCX_CMD_XME 0x01 +#define HSCX_CMD_RRS 0x20 +#define HSCX_CMD_XML_MASK 0x3f00 + +/* + * Commands and parameters are sent to the "HSCX" as a long, but the + * fields are handled as bytes. + * + * The long contains: + * (prot << 16)|(txl << 8)|cmd + * + * where: + * prot = protocol to use + * txl = transmit length + * cmd = the command to be executed + * + * The fields are defined as u_char in struct l1_softc. + * + * Macro to coalesce the byte fields into a u_int + */ +#define AVMA1PPSETCMDLONG(f) (f) = ((sc->avma1pp_cmd) | (sc->avma1pp_txl << 8) \ + | (sc->avma1pp_prot << 16)) + +#ifdef __FreeBSD__ + +/* "fake" addresses for the non-existent HSCX */ +/* note: the unit number is in the lower byte for both the ISAC and "HSCX" */ +#define HSCX0FAKE 0xfa000 /* read: fake0 */ +#define HSCX1FAKE 0xfa100 /* read: fake1 */ +#define IS_HSCX_MASK 0xfff00 + +#endif /* __FreeBSD__ */ + +/* + * to prevent deactivating the "HSCX" when both channels are active we + * define an HSCX_ACTIVE flag which is or'd into the channel's state + * flag in avma1pp_bchannel_setup upon active and cleared upon deactivation. + * It is set high to allow room for new flags. + */ +#define HSCX_AVMA1PP_ACTIVE 0x1000 + +/*---------------------------------------------------------------------------* + * AVM read fifo routines + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +static void +avma1pp_read_fifo(void *buf, const void *base, size_t len) +{ + int unit; + struct l1_softc *sc; + + unit = (int)base & 0xff; + sc = &l1_sc[unit]; + + /* check whether the target is an HSCX */ + if (((int)base & IS_HSCX_MASK) == HSCX0FAKE) + { + hscx_read_fifo(0, buf, len, sc); + return; + } + if (((int)base & IS_HSCX_MASK) == HSCX1FAKE) + { + hscx_read_fifo(1, buf, len, sc); + return; + } + /* tell the board to access the ISAC fifo */ + outb(sc->sc_port + ADDR_REG_OFFSET, ISAC_FIFO); + insb(sc->sc_port + ISAC_REG_OFFSET, (u_char *)buf, len); +} + +static void +hscx_read_fifo(int chan, void *buf, size_t len, struct l1_softc *sc) +{ + u_int *ip; + size_t cnt; + + outl(sc->sc_port + ADDR_REG_OFFSET, chan); + ip = (u_int *)buf; + cnt = 0; + /* what if len isn't a multiple of sizeof(int) and buf is */ + /* too small ???? */ + while (cnt < len) + { + *ip++ = inl(sc->sc_port + ISAC_REG_OFFSET); + cnt += 4; + } +} + +#else + +static void +avma1pp_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, ISAC_FIFO); + bus_space_read_multi_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET, buf, size); + break; + case ISIC_WHAT_HSCXA: + hscx_read_fifo(0, buf, size, sc); + break; + case ISIC_WHAT_HSCXB: + hscx_read_fifo(1, buf, size, sc); + break; + } +} + +static void +hscx_read_fifo(int chan, void *buf, size_t len, struct l1_softc *sc) +{ + u_int32_t *ip; + size_t cnt; + + bus_space_write_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, chan); + ip = (u_int32_t *)buf; + cnt = 0; + /* what if len isn't a multiple of sizeof(int) and buf is */ + /* too small ???? */ + while (cnt < len) + { + *ip++ = bus_space_read_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET); + cnt += 4; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * AVM write fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1pp_write_fifo(void *base, const void *buf, size_t len) +{ + int unit; + struct l1_softc *sc; + + unit = (int)base & 0xff; + sc = &l1_sc[unit]; + + /* check whether the target is an HSCX */ + if (((int)base & IS_HSCX_MASK) == HSCX0FAKE) + { + hscx_write_fifo(0, buf, len, sc); + return; + } + if (((int)base & IS_HSCX_MASK) == HSCX1FAKE) + { + hscx_write_fifo(1, buf, len, sc); + return; + } + /* tell the board to use the ISAC fifo */ + outb(sc->sc_port + ADDR_REG_OFFSET, ISAC_FIFO); + outsb(sc->sc_port + ISAC_REG_OFFSET, (const u_char *)buf, len); +} + +static void +hscx_write_fifo(int chan, const void *buf, size_t len, struct l1_softc *sc) +{ + register const u_int *ip; + register size_t cnt; + l1_bchan_state_t *Bchan = &sc->sc_chan[chan]; + + sc->avma1pp_cmd &= ~HSCX_CMD_XME; + sc->avma1pp_txl = 0; + if (Bchan->out_mbuf_cur == NULL) + { + if (Bchan->bprot != BPROT_NONE) + sc->avma1pp_cmd |= HSCX_CMD_XME; + } + if (len != sc->sc_bfifolen) + sc->avma1pp_txl = len; + + cnt = 0; /* borrow cnt */ + AVMA1PPSETCMDLONG(cnt); + hscx_write_reg(chan, HSCX_STAT, cnt, sc); + + ip = (const u_int *)buf; + cnt = 0; + while (cnt < len) + { + outl(sc->sc_port + ISAC_REG_OFFSET, *ip++); + cnt += 4; + } +} + +#else + +static void +avma1pp_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, ISAC_FIFO); + bus_space_write_multi_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + hscx_write_fifo(0, buf, size, sc); + break; + case ISIC_WHAT_HSCXB: + hscx_write_fifo(1, buf, size, sc); + break; + } +} + +static void +hscx_write_fifo(int chan, const void *buf, size_t len, struct l1_softc *sc) +{ + u_int32_t *ip; + size_t cnt; + l1_bchan_state_t *Bchan = &sc->sc_chan[chan]; + + sc->avma1pp_cmd &= ~HSCX_CMD_XME; + sc->avma1pp_txl = 0; + if (Bchan->out_mbuf_cur == NULL) + { + if (Bchan->bprot != BPROT_NONE) + sc->avma1pp_cmd |= HSCX_CMD_XME; + } + if (len != sc->sc_bfifolen) + sc->avma1pp_txl = len; + + cnt = 0; /* borrow cnt */ + AVMA1PPSETCMDLONG(cnt); + hscx_write_reg(chan, HSCX_STAT, cnt, sc); + + ip = (u_int32_t *)buf; + cnt = 0; + while (cnt < len) + { + bus_space_write_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET, *ip); + ip++; + cnt += 4; + } +} +#endif + +/*---------------------------------------------------------------------------* + * AVM write register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1pp_write_reg(u_char *base, u_int offset, u_int v) +{ + int unit; + struct l1_softc *sc; + u_char reg_bank; + + unit = (int)base & 0xff; + sc = &l1_sc[unit]; + + /* check whether the target is an HSCX */ + if (((int)base & IS_HSCX_MASK) == HSCX0FAKE) + { + hscx_write_reg(0, offset, v, sc); + return; + } + if (((int)base & IS_HSCX_MASK) == HSCX1FAKE) + { + hscx_write_reg(1, offset, v, sc); + return; + } + /* must be the ISAC */ + reg_bank = (offset > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET; +#ifdef AVMA1PCI_DEBUG + printf("write_reg bank %d off %d.. ", reg_bank, offset); +#endif + /* set the register bank */ + outb(sc->sc_port + ADDR_REG_OFFSET, reg_bank); + outb(sc->sc_port + ISAC_REG_OFFSET + (offset & ISAC_REGSET_MASK), v); +} + +static void +hscx_write_reg(int chan, u_int off, u_int val, struct l1_softc *sc) +{ + /* HACK */ + if (off == H_MASK) + return; + /* point at the correct channel */ + outl(sc->sc_port + ADDR_REG_OFFSET, chan); + outl(sc->sc_port + ISAC_REG_OFFSET + off, val); +} + +#else + +static void +avma1pp_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + u_char reg_bank; + switch (what) { + case ISIC_WHAT_ISAC: + reg_bank = (offs > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET; +#ifdef AVMA1PCI_DEBUG + printf("write_reg bank %d off %ld.. ", (int)reg_bank, (long)offs); +#endif + /* set the register bank */ + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, reg_bank); + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET + (offs & ISAC_REGSET_MASK), data); + break; + case ISIC_WHAT_HSCXA: + hscx_write_reg(0, offs, data, sc); + break; + case ISIC_WHAT_HSCXB: + hscx_write_reg(1, offs, data, sc); + break; + } +} + +static void +hscx_write_reg(int chan, u_int off, u_int val, struct l1_softc *sc) +{ + /* HACK */ + if (off == H_MASK) + return; + /* point at the correct channel */ + bus_space_write_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, chan); + bus_space_write_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET + off, val); +} + +#endif + +/*---------------------------------------------------------------------------* + * AVM read register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +avma1pp_read_reg(u_char *base, u_int offset) +{ + int unit; + struct l1_softc *sc; + u_char reg_bank; + + unit = (int)base & 0xff; + sc = &l1_sc[unit]; + + /* check whether the target is an HSCX */ + if (((int)base & IS_HSCX_MASK) == HSCX0FAKE) + return(hscx_read_reg(0, offset, sc)); + if (((int)base & IS_HSCX_MASK) == HSCX1FAKE) + return(hscx_read_reg(1, offset, sc)); + /* must be the ISAC */ + reg_bank = (offset > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET; +#ifdef AVMA1PCI_DEBUG + printf("read_reg bank %d off %d.. ", reg_bank, offset); +#endif + /* set the register bank */ + outb(sc->sc_port + ADDR_REG_OFFSET, reg_bank); + return(inb(sc->sc_port + ISAC_REG_OFFSET + + (offset & ISAC_REGSET_MASK))); +} +#else +static u_int8_t +avma1pp_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + u_char reg_bank; + switch (what) { + case ISIC_WHAT_ISAC: + reg_bank = (offs > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET; +#ifdef AVMA1PCI_DEBUG + printf("read_reg bank %d off %ld.. ", (int)reg_bank, (long)offs); +#endif + /* set the register bank */ + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, reg_bank); + return(bus_space_read_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET + + (offs & ISAC_REGSET_MASK))); + case ISIC_WHAT_HSCXA: + return hscx_read_reg(0, offs, sc); + case ISIC_WHAT_HSCXB: + return hscx_read_reg(1, offs, sc); + } + return 0; +} +#endif + +static u_char +hscx_read_reg(int chan, u_int off, struct l1_softc *sc) +{ + return(hscx_read_reg_int(chan, off, sc) & 0xff); +} + +/* + * need to be able to return an int because the RBCH is in the 2nd + * byte. + */ +static u_int +hscx_read_reg_int(int chan, u_int off, struct l1_softc *sc) +{ + /* HACK */ + if (off == H_ISTA) + return(0); + /* point at the correct channel */ +#ifdef __FreeBSD__ + outl(sc->sc_port + ADDR_REG_OFFSET, chan); + return(inl(sc->sc_port + ISAC_REG_OFFSET + off)); +#else + bus_space_write_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR_REG_OFFSET, chan); + return(bus_space_read_4(sc->sc_maps[0].t, sc->sc_maps[0].h, ISAC_REG_OFFSET + off)); +#endif +} + +/*---------------------------------------------------------------------------* + * isic_attach_avma1pp - attach Fritz!Card PCI + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_attach_avma1pp(int unit, u_int iobase1, u_int iobase2) +{ + struct l1_softc *sc = &l1_sc[unit]; + u_int v; + + /* check max unit range */ + + if(unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for AVM FRITZ/PCI!\n", + unit, unit); + return(0); + } + sc->sc_unit = unit; + + /* setup iobase */ + + if((iobase1 <= 0) || (iobase1 > 0xffff)) + { + printf("isic%d: Error, invalid iobase 0x%x specified for AVM FRITZ/PCI!\n", + unit, iobase1); + return(0); + } + sc->sc_port = iobase1; + + /* the ISAC lives at offset 0x10, but we can't use that. */ + /* instead, put the unit number into the lower byte - HACK */ + sc->sc_isac = (caddr_t)((int)(iobase1 & ~0xff) + unit); + + /* this thing doesn't have an HSCX, so fake the base addresses */ + /* put the unit number into the lower byte - HACK */ + HSCX_A_BASE = (caddr_t)(HSCX0FAKE + unit); + HSCX_B_BASE = (caddr_t)(HSCX1FAKE + unit); + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = avma1pp_read_reg; + sc->writereg = avma1pp_write_reg; + + sc->readfifo = avma1pp_read_fifo; + sc->writefifo = avma1pp_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_AVMA1PCI; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + /* set up some other miscellaneous things */ + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* reset the card */ + /* the Linux driver does this to clear any pending ISAC interrupts */ + v = 0; + v = ISAC_READ(I_STAR); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_STAR %x...", v); +#endif + v = ISAC_READ(I_MODE); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_MODE %x...", v); +#endif + v = ISAC_READ(I_ADF2); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_ADF2 %x...", v); +#endif + v = ISAC_READ(I_ISTA); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_ISTA %x...", v); +#endif + if (v & ISAC_ISTA_EXI) + { + v = ISAC_READ(I_EXIR); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_EXIR %x...", v); +#endif + } + v = ISAC_READ(I_CIRR); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_CIRR %x...", v); +#endif + ISAC_WRITE(I_MASK, 0xff); + /* the Linux driver does this to clear any pending HSCX interrupts */ + v = hscx_read_reg_int(0, HSCX_STAT, sc); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: 0 HSCX_STAT %x...", v); +#endif + v = hscx_read_reg_int(1, HSCX_STAT, sc); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: 1 HSCX_STAT %x\n", v); +#endif + + outb(sc->sc_port + STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE); + DELAY(SEC_DELAY/100); /* 10 ms */ + outb(sc->sc_port + STAT0_OFFSET, ASL_TIMERRESET|ASL_ENABLE_INT|ASL_TIMERDISABLE); + DELAY(SEC_DELAY/100); /* 10 ms */ +#ifdef AVMA1PCI_DEBUG + outb(sc->sc_port + STAT1_OFFSET, ASL1_ENABLE_IOM|sc->sc_irq); + DELAY(SEC_DELAY/100); /* 10 ms */ + printf("after reset: S1 %#x\n", inb(sc->sc_port + STAT1_OFFSET)); + + v = inl(sc->sc_port); + printf("isic_attach_avma1pp: v %#x\n", v); +#endif + + /* from here to the end would normally be done in isic_pciattach */ + + printf("isic%d: ISAC %s (IOM-%c)\n", unit, + "2085 Version A1/A2 or 2086/2186 Version 1.1", + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + + /* init the ISAC */ + isic_isac_init(sc); + + /* init the "HSCX" */ + avma1pp_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + avma1pp_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* can't use the normal B-Channel stuff */ + avma1pp_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + +#if defined(__FreeBSD__) && __FreeBSD__ >=3 + callout_handle_init(&sc->sc_T3_callout); + callout_handle_init(&sc->sc_T4_callout); +#endif + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + return(1); +} + +#else + +void +isic_attach_fritzPci(struct pci_l1_softc *psc, struct pci_attach_args *pa) +{ + struct l1_softc *sc = &psc->sc_isic; + u_int v; + + l1_sc[sc->sc_unit] = sc; /* XXX - hack! */ + + /* setup io mappings */ + sc->sc_num_mappings = 1; + MALLOC_MAPS(sc); + sc->sc_maps[0].size = 0; + if (pci_mapreg_map(pa, FRITZPCI_PORT0_MAPOFF, PCI_MAPREG_TYPE_IO, 0, + &sc->sc_maps[0].t, &sc->sc_maps[0].h, NULL, NULL)) { + printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname); + return; + } + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = avma1pp_read_reg; + sc->writereg = avma1pp_write_reg; + + sc->readfifo = avma1pp_read_fifo; + sc->writefifo = avma1pp_write_fifo; + + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_AVMA1PCI; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + /* this is no IPAC based card */ + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* init the card */ + /* the Linux driver does this to clear any pending ISAC interrupts */ + /* see if it helps any - XXXX */ + v = 0; + v = ISAC_READ(I_STAR); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_STAR %x...", v); +#endif + v = ISAC_READ(I_MODE); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_MODE %x...", v); +#endif + v = ISAC_READ(I_ADF2); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_ADF2 %x...", v); +#endif + v = ISAC_READ(I_ISTA); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_ISTA %x...", v); +#endif + if (v & ISAC_ISTA_EXI) + { + v = ISAC_READ(I_EXIR); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_EXIR %x...", v); +#endif + } + v = ISAC_READ(I_CIRR); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: I_CIRR %x...", v); +#endif + ISAC_WRITE(I_MASK, 0xff); + /* the Linux driver does this to clear any pending HSCX interrupts */ + v = hscx_read_reg_int(0, HSCX_STAT, sc); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: 0 HSCX_STAT %x...", v); +#endif + v = hscx_read_reg_int(1, HSCX_STAT, sc); +#ifdef AVMA1PCI_DEBUG + printf("avma1pp_attach: 1 HSCX_STAT %x\n", v); +#endif + + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE); + DELAY(SEC_DELAY/100); /* 10 ms */ + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT0_OFFSET, ASL_TIMERRESET|ASL_ENABLE_INT|ASL_TIMERDISABLE); + DELAY(SEC_DELAY/100); /* 10 ms */ +#ifdef AVMA1PCI_DEBUG + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT1_OFFSET, ASL1_ENABLE_IOM|sc->sc_irq); + DELAY(SEC_DELAY/100); /* 10 ms */ + v = bus_space_read_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT1_OFFSET); + printf("after reset: S1 %#x\n", v); + + v = bus_space_read_4(sc->sc_maps[0].t, sc->sc_maps[0].h, 0); + printf("isic_attach_avma1pp: v %#x\n", v); +#endif + + /* setup i4b infrastructure (have to roll our own here) */ + + /* sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; */ + printf("%s: ISAC %s (IOM-%c)\n", sc->sc_dev.dv_xname, + "2085 Version A1/A2 or 2086/2186 Version 1.1", + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + + /* init the ISAC */ + isic_isac_init(sc); + + /* init the "HSCX" */ + avma1pp_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + avma1pp_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* can't use the normal B-Channel stuff */ + avma1pp_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + /* setup interrupt mapping */ + avma1pp_map_int(psc, pa); +} + +#endif + +/* + * this is the real interrupt routine + */ +static void +avma1pp_hscx_intr(int h_chan, u_int stat, struct l1_softc *sc) +{ + register l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + int activity = -1; + u_int param = 0; + + NDBGL1(L1_H_IRQ, "%#x", stat); + + if((stat & HSCX_INT_XDU) && (chan->bprot != BPROT_NONE))/* xmit data underrun */ + { + chan->stat_XDU++; + NDBGL1(L1_H_XFRERR, "xmit data underrun"); + /* abort the transmission */ + sc->avma1pp_txl = 0; + sc->avma1pp_cmd |= HSCX_CMD_XRS; + AVMA1PPSETCMDLONG(param); + hscx_write_reg(h_chan, HSCX_STAT, param, sc); + sc->avma1pp_cmd &= ~HSCX_CMD_XRS; + AVMA1PPSETCMDLONG(param); + hscx_write_reg(h_chan, HSCX_STAT, param, sc); + + if (chan->out_mbuf_head != NULL) /* don't continue to transmit this buffer */ + { + i4b_Bfreembuf(chan->out_mbuf_head); + chan->out_mbuf_cur = chan->out_mbuf_head = NULL; + } + } + + /* + * The following is based on examination of the Linux driver. + * + * The logic here is different than with a "real" HSCX; all kinds + * of information (interrupt/status bits) are in stat. + * HSCX_INT_RPR indicates a receive interrupt + * HSCX_STAT_RDO indicates an overrun condition, abort - + * otherwise read the bytes ((stat & HSCX_STZT_RML_MASK) >> 8) + * HSCX_STAT_RME indicates end-of-frame and apparently any + * CRC/framing errors are only reported in this state. + * if ((stat & HSCX_STAT_CRCVFRRAB) != HSCX_STAT_CRCVFR) + * CRC/framing error + */ + + if(stat & HSCX_INT_RPR) + { + register int fifo_data_len; + int error = 0; + /* always have to read the FIFO, so use a scratch buffer */ + u_char scrbuf[HSCX_FIFO_LEN]; + + if(stat & HSCX_STAT_RDO) + { + chan->stat_RDO++; + NDBGL1(L1_H_XFRERR, "receive data overflow"); + error++; + } + + /* + * check whether we're receiving data for an inactive B-channel + * and discard it. This appears to happen for telephony when + * both B-channels are active and one is deactivated. Since + * it is not really possible to deactivate the channel in that + * case (the ASIC seems to deactivate _both_ channels), the + * "deactivated" channel keeps receiving data which can lead + * to exhaustion of mbufs and a kernel panic. + * + * This is a hack, but it's the only solution I can think of + * without having the documentation for the ASIC. + * GJ - 28 Nov 1999 + */ + if (chan->state == HSCX_IDLE) + { + NDBGL1(L1_H_XFRERR, "toss data from %d", h_chan); + error++; + } + + fifo_data_len = ((stat & HSCX_STAT_RML_MASK) >> 8); + + if(fifo_data_len == 0) + fifo_data_len = sc->sc_bfifolen; + + /* ALWAYS read data from HSCX fifo */ + + HSCX_RDFIFO(h_chan, scrbuf, fifo_data_len); + chan->rxcount += fifo_data_len; + + /* all error conditions checked, now decide and take action */ + + if(error == 0) + { + if(chan->in_mbuf == NULL) + { + if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL) + panic("L1 avma1pp_hscx_intr: RME, cannot allocate mbuf!\n"); + chan->in_cbptr = chan->in_mbuf->m_data; + chan->in_len = 0; + } + + if((chan->in_len + fifo_data_len) <= BCH_MAX_DATALEN) + { + /* OK to copy the data */ + bcopy(scrbuf, chan->in_cbptr, fifo_data_len); + chan->in_cbptr += fifo_data_len; + chan->in_len += fifo_data_len; + + /* setup mbuf data length */ + + chan->in_mbuf->m_len = chan->in_len; + chan->in_mbuf->m_pkthdr.len = chan->in_len; + + if(sc->sc_trace & TRACE_B_RX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); + } + + if (stat & HSCX_STAT_RME) + { + if((stat & HSCX_STAT_CRCVFRRAB) == HSCX_STAT_CRCVFR) + { + (*chan->drvr_linktab->bch_rx_data_ready)(chan->drvr_linktab->unit); + activity = ACT_RX; + + /* mark buffer ptr as unused */ + + chan->in_mbuf = NULL; + chan->in_cbptr = NULL; + chan->in_len = 0; + } + else + { + chan->stat_CRC++; + NDBGL1(L1_H_XFRERR, "CRC/RAB"); + if (chan->in_mbuf != NULL) + { + i4b_Bfreembuf(chan->in_mbuf); + chan->in_mbuf = NULL; + chan->in_cbptr = NULL; + chan->in_len = 0; + } + } + } + } /* END enough space in mbuf */ + else + { + if(chan->bprot == BPROT_NONE) + { + /* setup mbuf data length */ + + chan->in_mbuf->m_len = chan->in_len; + chan->in_mbuf->m_pkthdr.len = chan->in_len; + + if(sc->sc_trace & TRACE_B_RX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); + } + + if(!(isic_hscx_silence(chan->in_mbuf->m_data, chan->in_mbuf->m_len))) + activity = ACT_RX; + + /* move rx'd data to rx queue */ + + if (!(IF_QFULL(&chan->rx_queue))) + { + IF_ENQUEUE(&chan->rx_queue, chan->in_mbuf); + } + else + { + i4b_Bfreembuf(chan->in_mbuf); + } + + /* signal upper layer that data are available */ + (*chan->drvr_linktab->bch_rx_data_ready)(chan->drvr_linktab->unit); + + /* alloc new buffer */ + + if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL) + panic("L1 avma1pp_hscx_intr: RPF, cannot allocate new mbuf!\n"); + + /* setup new data ptr */ + + chan->in_cbptr = chan->in_mbuf->m_data; + + /* OK to copy the data */ + bcopy(scrbuf, chan->in_cbptr, fifo_data_len); + + chan->in_cbptr += fifo_data_len; + chan->in_len = fifo_data_len; + + chan->rxcount += fifo_data_len; + } + else + { + NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RPF, in_len=%d", chan->in_len); + chan->in_cbptr = chan->in_mbuf->m_data; + chan->in_len = 0; + } + } + } /* if(error == 0) */ + else + { + /* land here for RDO */ + if (chan->in_mbuf != NULL) + { + i4b_Bfreembuf(chan->in_mbuf); + chan->in_mbuf = NULL; + chan->in_cbptr = NULL; + chan->in_len = 0; + } + sc->avma1pp_txl = 0; + sc->avma1pp_cmd |= HSCX_CMD_RRS; + AVMA1PPSETCMDLONG(param); + hscx_write_reg(h_chan, HSCX_STAT, param, sc); + sc->avma1pp_cmd &= ~HSCX_CMD_RRS; + AVMA1PPSETCMDLONG(param); + hscx_write_reg(h_chan, HSCX_STAT, param, sc); + } + } + + + /* transmit fifo empty, new data can be written to fifo */ + + if(stat & HSCX_INT_XPR) + { + /* + * for a description what is going on here, please have + * a look at isic_bchannel_start() in i4b_bchan.c ! + */ + + NDBGL1(L1_H_IRQ, "unit %d, chan %d - XPR, Tx Fifo Empty!", sc->sc_unit, h_chan); + + if(chan->out_mbuf_cur == NULL) /* last frame is transmitted */ + { + IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head); + + if(chan->out_mbuf_head == NULL) + { + chan->state &= ~HSCX_TX_ACTIVE; + (*chan->drvr_linktab->bch_tx_queue_empty)(chan->drvr_linktab->unit); + } + else + { + chan->state |= HSCX_TX_ACTIVE; + chan->out_mbuf_cur = chan->out_mbuf_head; + chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; + chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; + + if(sc->sc_trace & TRACE_B_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); + } + + if(chan->bprot == BPROT_NONE) + { + if(!(isic_hscx_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len))) + activity = ACT_TX; + } + else + { + activity = ACT_TX; + } + } + } + + isic_hscx_fifo(chan, sc); + } + + /* call timeout handling routine */ + + if(activity == ACT_RX || activity == ACT_TX) + (*chan->drvr_linktab->bch_activity)(chan->drvr_linktab->unit, activity); +} + +/* + * this is the main routine which checks each channel and then calls + * the real interrupt routine as appropriate + */ +static void +avma1pp_hscx_int_handler(struct l1_softc *sc) +{ + u_int stat; + + /* has to be a u_int because the byte count is in the 2nd byte */ + stat = hscx_read_reg_int(0, HSCX_STAT, sc); + if (stat & HSCX_INT_MASK) + avma1pp_hscx_intr(0, stat, sc); + stat = hscx_read_reg_int(1, HSCX_STAT, sc); + if (stat & HSCX_INT_MASK) + avma1pp_hscx_intr(1, stat, sc); +} + +static void +avma1pp_disable(struct l1_softc *sc) +{ +#ifdef __FreeBSD__ + outb(sc->sc_port + STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE); +#else + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE); +#endif +} + +#ifdef __FreeBSD__ +static void +avma1pp_intr(struct l1_softc *sc) +{ +#define OURS /* no return value accumulated */ +#define ISICINTR(sc) isicintr_sc(sc) +#else +static int +avma1pp_intr(void * parm) +{ + struct l1_softc *sc = parm; + int ret = 0; +#define OURS ret = 1 +#define ISICINTR(sc) isicintr(sc) +#endif + u_char stat; + +#ifdef __FreeBSD__ + stat = inb(sc->sc_port + STAT0_OFFSET); +#else + stat = bus_space_read_1(sc->sc_maps[0].t, sc->sc_maps[0].h, STAT0_OFFSET); +#endif + NDBGL1(L1_H_IRQ, "stat %x", stat); + /* was there an interrupt from this card ? */ + if ((stat & ASL_IRQ_Pending) == ASL_IRQ_Pending) +#ifdef __FreeBSD__ + return; /* no */ +#else + return 0; /* no */ +#endif + /* interrupts are low active */ + if (!(stat & ASL_IRQ_TIMER)) + NDBGL1(L1_H_IRQ, "timer interrupt ???"); + if (!(stat & ASL_IRQ_HSCX)) + { + NDBGL1(L1_H_IRQ, "HSCX"); + avma1pp_hscx_int_handler(sc); + OURS; + } + if (!(stat & ASL_IRQ_ISAC)) + { + NDBGL1(L1_H_IRQ, "ISAC"); + ISICINTR(sc); + OURS; + } +#ifndef __FreeBSD__ + return ret; +#endif +} + +#ifdef __FreeBSD__ +void +avma1pp_map_int(pcici_t config_id, void *pisc, unsigned *net_imask) +{ + struct l1_softc *sc = (struct l1_softc *)pisc; + +#ifdef AVMA1PCI_DEBUG + /* may need the irq later */ +#if __FreeBSD__ < 3 + /* I'd like to call getirq here, but it is static */ + sc->sc_irq = PCI_INTERRUPT_LINE_EXTRACT( + pci_conf_read (config_id, PCI_INTERRUPT_REG)); + + if (sc->sc_irq == 0 || sc->sc_irq == 0xff) + printf ("avma1pp_map_int:int line register not set by bios\n"); + + if (sc->sc_irq >= PCI_MAX_IRQ) + printf ("avma1pp_map_int:irq %d out of bounds (must be < %d)\n", + sc->sc_irq, PCI_MAX_IRQ); +#else + sc->sc_irq = config_id->intline; +#endif +#endif /* AVMA1PCI_DEBUG */ + + if(!(pci_map_int(config_id, (void *)avma1pp_intr, sc, net_imask))) + { + printf("Failed to map interrupt for AVM Fritz!Card PCI\n"); + /* disable the card */ + avma1pp_disable(sc); + } +} +#else +static void +avma1pp_map_int(struct pci_l1_softc *psc, struct pci_attach_args *pa) +{ + struct l1_softc *sc = &psc->sc_isic; + pci_chipset_tag_t pc = pa->pa_pc; + pci_intr_handle_t ih; + const char *intrstr; + + /* Map and establish the interrupt. */ + if (pci_intr_map(pa, &ih)) { + printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); + avma1pp_disable(sc); + return; + } + intrstr = pci_intr_string(pc, ih); + psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, avma1pp_intr, sc); + if (psc->sc_ih == NULL) { + printf("%s: couldn't establish interrupt", + sc->sc_dev.dv_xname); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + avma1pp_disable(sc); + return; + } + printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); +} +#endif + +static void +avma1pp_hscx_init(struct l1_softc *sc, int h_chan, int activate) +{ + l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + u_int param = 0; + + NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s", + sc->sc_unit, h_chan, activate ? "activate" : "deactivate"); + + if (activate == 0) + { + /* only deactivate if both channels are idle */ + if (sc->sc_chan[HSCX_CH_A].state != HSCX_IDLE || + sc->sc_chan[HSCX_CH_B].state != HSCX_IDLE) + { + return; + } + sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS; + sc->avma1pp_prot = HSCX_MODE_TRANS; + AVMA1PPSETCMDLONG(param); + hscx_write_reg(h_chan, HSCX_STAT, param, sc); + return; + } + if(chan->bprot == BPROT_RHDLC) + { + NDBGL1(L1_BCHAN, "BPROT_RHDLC"); + + /* HDLC Frames, transparent mode 0 */ + sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS; + sc->avma1pp_prot = HSCX_MODE_ITF_FLG; + AVMA1PPSETCMDLONG(param); + hscx_write_reg(h_chan, HSCX_STAT, param, sc); + sc->avma1pp_cmd = HSCX_CMD_XRS; + AVMA1PPSETCMDLONG(param); + hscx_write_reg(h_chan, HSCX_STAT, param, sc); + sc->avma1pp_cmd = 0; + } + else + { + NDBGL1(L1_BCHAN, "BPROT_NONE??"); + + /* Raw Telephony, extended transparent mode 1 */ + sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS; + sc->avma1pp_prot = HSCX_MODE_TRANS; + AVMA1PPSETCMDLONG(param); + hscx_write_reg(h_chan, HSCX_STAT, param, sc); + sc->avma1pp_cmd = HSCX_CMD_XRS; + AVMA1PPSETCMDLONG(param); + hscx_write_reg(h_chan, HSCX_STAT, param, sc); + sc->avma1pp_cmd = 0; + } +} + +static void +avma1pp_bchannel_setup(int unit, int h_chan, int bprot, int activate) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + + int s = SPLI4B(); + + if(activate == 0) + { + /* deactivation */ + chan->state = HSCX_IDLE; + avma1pp_hscx_init(sc, h_chan, activate); + } + + NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s", + sc->sc_unit, h_chan, activate ? "activate" : "deactivate"); + + /* general part */ + + chan->unit = sc->sc_unit; /* unit number */ + chan->channel = h_chan; /* B channel */ + chan->bprot = bprot; /* B channel protocol */ + chan->state = HSCX_IDLE; /* B channel state */ + + /* receiver part */ + + i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */ + + chan->rx_queue.ifq_maxlen = IFQ_MAXLEN; + + chan->rxcount = 0; /* reset rx counter */ + + i4b_Bfreembuf(chan->in_mbuf); /* clean rx mbuf */ + + chan->in_mbuf = NULL; /* reset mbuf ptr */ + chan->in_cbptr = NULL; /* reset mbuf curr ptr */ + chan->in_len = 0; /* reset mbuf data len */ + + /* transmitter part */ + + i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */ + + chan->tx_queue.ifq_maxlen = IFQ_MAXLEN; + + chan->txcount = 0; /* reset tx counter */ + + i4b_Bfreembuf(chan->out_mbuf_head); /* clean tx mbuf */ + + chan->out_mbuf_head = NULL; /* reset head mbuf ptr */ + chan->out_mbuf_cur = NULL; /* reset current mbuf ptr */ + chan->out_mbuf_cur_ptr = NULL; /* reset current mbuf data ptr */ + chan->out_mbuf_cur_len = 0; /* reset current mbuf data cnt */ + + if(activate != 0) + { + /* activation */ + avma1pp_hscx_init(sc, h_chan, activate); + chan->state |= HSCX_AVMA1PP_ACTIVE; + } + + splx(s); +} + +static void +avma1pp_bchannel_start(int unit, int h_chan) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + register l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + int s; + int activity = -1; + + s = SPLI4B(); /* enter critical section */ + if(chan->state & HSCX_TX_ACTIVE) /* already running ? */ + { + splx(s); + return; /* yes, leave */ + } + + /* get next mbuf from queue */ + + IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head); + + if(chan->out_mbuf_head == NULL) /* queue empty ? */ + { + splx(s); /* leave critical section */ + return; /* yes, exit */ + } + + /* init current mbuf values */ + + chan->out_mbuf_cur = chan->out_mbuf_head; + chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; + chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; + + /* activity indicator for timeout handling */ + + if(chan->bprot == BPROT_NONE) + { + if(!(isic_hscx_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len))) + activity = ACT_TX; + } + else + { + activity = ACT_TX; + } + + chan->state |= HSCX_TX_ACTIVE; /* we start transmitting */ + + if(sc->sc_trace & TRACE_B_TX) /* if trace, send mbuf to trace dev */ + { + i4b_trace_hdr_t hdr; + hdr.unit = unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); + } + + isic_hscx_fifo(chan, sc); + + /* call timeout handling routine */ + + if(activity == ACT_RX || activity == ACT_TX) + (*chan->drvr_linktab->bch_activity)(chan->drvr_linktab->unit, activity); + + splx(s); +} + +/*---------------------------------------------------------------------------* + * return the address of isic drivers linktab + *---------------------------------------------------------------------------*/ +static isdn_link_t * +avma1pp_ret_linktab(int unit, int channel) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[channel]; + + return(&chan->isdn_linktab); +} + +/*---------------------------------------------------------------------------* + * set the driver linktab in the b channel softc + *---------------------------------------------------------------------------*/ +static void +avma1pp_set_linktab(int unit, int channel, drvr_link_t *dlt) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[channel]; + + chan->drvr_linktab = dlt; +} + + +/*---------------------------------------------------------------------------* + * initialize our local linktab + *---------------------------------------------------------------------------*/ +static void +avma1pp_init_linktab(struct l1_softc *sc) +{ + l1_bchan_state_t *chan = &sc->sc_chan[HSCX_CH_A]; + isdn_link_t *lt = &chan->isdn_linktab; + + /* make sure the hardware driver is known to layer 4 */ + /* avoid overwriting if already set */ + if (ctrl_types[CTRL_PASSIVE].set_linktab == NULL) + { + ctrl_types[CTRL_PASSIVE].set_linktab = avma1pp_set_linktab; + ctrl_types[CTRL_PASSIVE].get_linktab = avma1pp_ret_linktab; + } + + /* local setup */ + lt->unit = sc->sc_unit; + lt->channel = HSCX_CH_A; + lt->bch_config = avma1pp_bchannel_setup; + lt->bch_tx_start = avma1pp_bchannel_start; + lt->bch_stat = avma1pp_bchannel_stat; + lt->tx_queue = &chan->tx_queue; + + /* used by non-HDLC data transfers, i.e. telephony drivers */ + lt->rx_queue = &chan->rx_queue; + + /* used by HDLC data transfers, i.e. ipr and isp drivers */ + lt->rx_mbuf = &chan->in_mbuf; + + chan = &sc->sc_chan[HSCX_CH_B]; + lt = &chan->isdn_linktab; + + lt->unit = sc->sc_unit; + lt->channel = HSCX_CH_B; + lt->bch_config = avma1pp_bchannel_setup; + lt->bch_tx_start = avma1pp_bchannel_start; + lt->bch_stat = avma1pp_bchannel_stat; + lt->tx_queue = &chan->tx_queue; + + /* used by non-HDLC data transfers, i.e. telephony drivers */ + lt->rx_queue = &chan->rx_queue; + + /* used by HDLC data transfers, i.e. ipr and isp drivers */ + lt->rx_mbuf = &chan->in_mbuf; +} + +/* + * use this instead of isic_bchannel_stat in i4b_bchan.c because it's static + */ +static void +avma1pp_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = &l1_sc[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + int s; + + s = SPLI4B(); + + bsp->outbytes = chan->txcount; + bsp->inbytes = chan->rxcount; + + chan->txcount = 0; + chan->rxcount = 0; + + splx(s); +} + +/*---------------------------------------------------------------------------* + * fill HSCX fifo with data from the current mbuf + * Put this here until it can go into i4b_hscx.c + *---------------------------------------------------------------------------*/ +static int +isic_hscx_fifo(l1_bchan_state_t *chan, struct l1_softc *sc) +{ + int len; + int nextlen; + int i; + int cmd; + /* using a scratch buffer simplifies writing to the FIFO */ + u_char scrbuf[HSCX_FIFO_LEN]; + + len = 0; + + /* + * fill the HSCX tx fifo with data from the current mbuf. if + * current mbuf holds less data than HSCX fifo length, try to + * get the next mbuf from (a possible) mbuf chain. if there is + * not enough data in a single mbuf or in a chain, then this + * is the last mbuf and we tell the HSCX that it has to send + * CRC and closing flag + */ + + while(chan->out_mbuf_cur && len != sc->sc_bfifolen) + { + nextlen = min(chan->out_mbuf_cur_len, sc->sc_bfifolen - len); + +#ifdef NOTDEF + printf("i:mh=%p, mc=%p, mcp=%p, mcl=%d l=%d nl=%d # ", + chan->out_mbuf_head, + chan->out_mbuf_cur, + chan->out_mbuf_cur_ptr, + chan->out_mbuf_cur_len, + len, + nextlen); +#endif + + cmd |= HSCX_CMDR_XTF; + /* collect the data in the scratch buffer */ + for (i = 0; i < nextlen; i++) + scrbuf[i + len] = chan->out_mbuf_cur_ptr[i]; + + len += nextlen; + chan->txcount += nextlen; + + chan->out_mbuf_cur_ptr += nextlen; + chan->out_mbuf_cur_len -= nextlen; + + if(chan->out_mbuf_cur_len == 0) + { + if((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL) + { + chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; + chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; + + if(sc->sc_trace & TRACE_B_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (chan->channel == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); + } + } + else + { + if (chan->bprot != BPROT_NONE) + cmd |= HSCX_CMDR_XME; + i4b_Bfreembuf(chan->out_mbuf_head); + chan->out_mbuf_head = NULL; + } + } + } + /* write what we have from the scratch buf to the HSCX fifo */ + if (len != 0) + HSCX_WRFIFO(chan->channel, scrbuf, len); + return(cmd); +} + +#endif /* ISICPCI_AVM_A1 */ diff --git a/sys/dev/pci/i4b_elsa_qs1p.c b/sys/dev/pci/i4b_elsa_qs1p.c new file mode 100644 index 00000000000..67a33fae7d7 --- /dev/null +++ b/sys/dev/pci/i4b_elsa_qs1p.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 1997, 1999 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. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for ELSA Quickstep 1000pro PCI + * ===================================================================== + * + * $Id: i4b_elsa_qs1p.c,v 1.1.1.1 2001/01/05 12:50:18 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:38:58 2001] + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicpci.h" +#ifdef ISICPCI_ELSA_QS1PCI + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#if __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#endif + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_mbuf.h> + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> +#include <dev/ic/i4b_ipac.h> + +#ifndef __FreeBSD__ +#include <dev/pci/pci_isic.h> +#endif + +/* masks for register encoded in base addr */ + +#define ELSA_BASE_MASK 0x0ffff +#define ELSA_OFF_MASK 0xf0000 + +/* register id's to be encoded in base addr */ + +#define ELSA_IDISAC 0x00000 +#define ELSA_IDHSCXA 0x10000 +#define ELSA_IDHSCXB 0x20000 +#define ELSA_IDIPAC 0x40000 + +/* offsets from base address */ + +#define ELSA_OFF_ALE 0x00 +#define ELSA_OFF_RW 0x01 + +#define ELSA_PORT0_MAPOFF PCI_MAPREG_START+4 +#define ELSA_PORT1_MAPOFF PCI_MAPREG_START+12 + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/PCI ISAC get fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pp_read_fifo(void *buf, const void *base, size_t len) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_HSCXB_OFF); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_HSCXA_OFF); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_ISAC_OFF); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } +} + +#else + +static void +eqs1pp_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF); + bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF); + bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF); + bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/PCI ISAC put fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pp_write_fifo(void *base, const void *buf, size_t len) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_HSCXB_OFF); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_HSCXA_OFF); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_ISAC_OFF); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } +} + +#else + +static void +eqs1pp_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF); + bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF); + bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF); + bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/PCI ISAC put register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pp_write_reg(u_char *base, u_int offset, u_int v) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF)); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW, (u_char)v); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF)); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW, (u_char)v); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF)); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW, (u_char)v); + } + else /* IPAC */ + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF)); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW, (u_char)v); + } +} + +#else + +static void +eqs1pp_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF+offs); + bus_space_write_1(t, h, ELSA_OFF_RW, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF+offs); + bus_space_write_1(t, h, ELSA_OFF_RW, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF+offs); + bus_space_write_1(t, h, ELSA_OFF_RW, data); + break; + case ISIC_WHAT_IPAC: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_IPAC_OFF+offs); + bus_space_write_1(t, h, ELSA_OFF_RW, data); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/PCI ISAC get register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +eqs1pp_read_reg(u_char *base, u_int offset) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF)); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW)); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF)); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW)); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF)); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW)); + } + else /* IPAC */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF)); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW)); + } +} + +#else + +static u_int8_t +eqs1pp_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF+offs); + return bus_space_read_1(t, h, ELSA_OFF_RW); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF+offs); + return bus_space_read_1(t, h, ELSA_OFF_RW); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF+offs); + return bus_space_read_1(t, h, ELSA_OFF_RW); + case ISIC_WHAT_IPAC: + { + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_IPAC_OFF+offs); + return bus_space_read_1(t, h, ELSA_OFF_RW); + } + } + + return 0; +} + +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_Eqs1pp - attach for ELSA QuickStep 1000pro/PCI + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_attach_Eqs1pp(int unit, unsigned int iobase1, unsigned int iobase2) +{ + struct l1_softc *sc = &l1_sc[unit]; + + /* check max unit range */ + + if(unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for ELSA QuickStep 1000pro/PCI!\n", + unit, unit); + return(0); + } + sc->sc_unit = unit; + + /* setup iobase */ + + if((iobase2 <= 0) || (iobase2 > 0xffff)) + { + printf("isic%d: Error, invalid iobase 0x%x specified for ELSA QuickStep 1000pro/PCI!\n", + unit, iobase2); + return(0); + } + sc->sc_port = iobase2; + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = eqs1pp_read_reg; + sc->writereg = eqs1pp_write_reg; + + sc->readfifo = eqs1pp_read_fifo; + sc->writefifo = eqs1pp_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_ELSAQS1PCI; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + /* setup chip type = IPAC ! */ + + sc->sc_ipac = 1; + sc->sc_bfifolen = IPAC_BFIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t) ((u_int)iobase2 | ELSA_IDISAC); + HSCX_A_BASE = (caddr_t) ((u_int)iobase2 | ELSA_IDHSCXA); + HSCX_B_BASE = (caddr_t) ((u_int)iobase2 | ELSA_IDHSCXB); + IPAC_BASE = (caddr_t) ((u_int)iobase2 | ELSA_IDIPAC); + + /* enable hscx/isac irq's */ + IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0)); + + IPAC_WRITE(IPAC_ACFG, 0); /* outputs are open drain */ + IPAC_WRITE(IPAC_AOE, /* aux 5..2 are inputs, 7, 6 outputs */ + (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2)); + IPAC_WRITE(IPAC_ATX, 0xff); /* set all output lines high */ + + outb(iobase1 + 0x4c, 0x41); /* enable card interrupt */ + + return (1); +} + +#else /* !FreeBSD */ + +void +isic_attach_Eqs1pp(psc, pa) + struct pci_l1_softc *psc; + struct pci_attach_args *pa; +{ + struct l1_softc *sc = &psc->sc_isic; + + /* setup io mappings */ + sc->sc_num_mappings = 2; + MALLOC_MAPS(sc); + sc->sc_maps[0].size = 0; + if (pci_mapreg_map(pa, ELSA_PORT0_MAPOFF, PCI_MAPREG_TYPE_IO, 0, + &sc->sc_maps[0].t, &sc->sc_maps[0].h, NULL, NULL)) { + printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname); + return; + } + sc->sc_maps[1].size = 0; + if (pci_mapreg_map(pa, ELSA_PORT1_MAPOFF, PCI_MAPREG_TYPE_IO, 0, + &sc->sc_maps[1].t, &sc->sc_maps[1].h, NULL, NULL)) { + printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname); + return; + } + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = eqs1pp_read_reg; + sc->writereg = eqs1pp_write_reg; + + sc->readfifo = eqs1pp_read_fifo; + sc->writefifo = eqs1pp_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_ELSAQS1PCI; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + /* setup chip type = IPAC ! */ + + sc->sc_ipac = 1; + sc->sc_bfifolen = IPAC_BFIFO_LEN; + + /* enable hscx/isac irq's */ + IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0)); + + IPAC_WRITE(IPAC_ACFG, 0); /* outputs are open drain */ + IPAC_WRITE(IPAC_AOE, /* aux 5..2 are inputs, 7, 6 outputs */ + (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2)); + IPAC_WRITE(IPAC_ATX, 0xff); /* set all output lines high */ + + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, 0x4c, 0x41); /* enable card interrupt */ +} + +#endif + +#endif /* ISICPCI_ELSA_QS1PCI */ diff --git a/sys/dev/pci/pci_isic.c b/sys/dev/pci/pci_isic.c new file mode 100644 index 00000000000..64c12a69168 --- /dev/null +++ b/sys/dev/pci/pci_isic.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 1998,1999 Martin Husemann. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * pci_isic.c - pcmcia bus frontend for i4b_isic driver + * ------------------------------------------------------- + * + * $Id: pci_isic.c,v 1.1.1.1 2001/01/05 12:50:20 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:38:58 2001] + * + * -mh original implementation + * -mh added support for Fritz! PCI card + * + *---------------------------------------------------------------------------*/ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/systm.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/bus.h> + + +#include <machine/bus.h> +#include <machine/intr.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_ioctl.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_ipac.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_global.h> +#include <netisdn/i4b_l1l2.h> +#include <dev/pci/pci_isic.h> + +#include "opt_isicpci.h" + +static int pci_isic_match __P((struct device *, struct cfdata *, void *)); +static void pci_isic_attach __P((struct device *, struct device *, void *)); +static const struct isic_pci_product * find_matching_card __P((struct pci_attach_args *pa)); + +static void isic_pciattach __P((struct pci_l1_softc *psc, struct pci_attach_args *pa)); + +struct cfattach pci_isic_ca = { + sizeof(struct pci_l1_softc), pci_isic_match, pci_isic_attach +}; + + +static const struct isic_pci_product { + pci_vendor_id_t npp_vendor; + pci_product_id_t npp_product; + int cardtype; + const char * name; + void (*attach)(struct pci_l1_softc *psc, struct pci_attach_args *pa); + void (*pciattach)(struct pci_l1_softc *psc, struct pci_attach_args *pa); +} isic_pci_products[] = { + +#ifdef ISICPCI_ELSA_QS1PCI +#ifndef PCI_PRODUCT_ELSA_QS1PCI +#define PCI_PRODUCT_ELSA_QS1PCI 0x1000 /* added to pcidevs in 1.3K, earlier versions missing it */ +#endif + { PCI_VENDOR_ELSA, PCI_PRODUCT_ELSA_QS1PCI, + CARD_TYPEP_ELSAQS1PCI, + "ELSA QuickStep 1000pro/PCI", + isic_attach_Eqs1pp, /* card specific initialization */ + isic_pciattach /* generic setup for ISAC/HSCX or IPAC boards */ + }, +#endif + +#ifdef ISICPCI_AVM_A1 +#ifndef PCI_VENDOR_AVM +#define PCI_VENDOR_AVM 0x1244 /* earlier versions missing this */ +#define PCI_PRODUCT_AVM_FRITZ_CARD 0x0a00 +#endif + { PCI_VENDOR_AVM, PCI_PRODUCT_AVM_FRITZ_CARD, + CARD_TYPEP_AVMA1PCI, + "Fritz!Card", + isic_attach_fritzPci, + NULL /* card rolls its own setup */ + }, +#endif + + { 0, 0, 0, NULL, NULL }, +}; + +static const struct isic_pci_product * find_matching_card(pa) + struct pci_attach_args *pa; +{ + const struct isic_pci_product * pp = NULL; + + for (pp = isic_pci_products; pp->npp_vendor; pp++) + if (PCI_VENDOR(pa->pa_id) == pp->npp_vendor && + PCI_PRODUCT(pa->pa_id) == pp->npp_product) + return pp; + + return NULL; +} + +/* + * Match card + */ +static int +pci_isic_match(parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; +{ + struct pci_attach_args *pa = aux; + + if (!find_matching_card(pa)) + return 0; + + return 1; +} + +/* + * Attach the card + */ +static void +pci_isic_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct pci_l1_softc *psc = (void*) self; + struct l1_softc *sc = &psc->sc_isic; + struct pci_attach_args *pa = aux; + const struct isic_pci_product * prod; + + /* Redo probe */ + prod = find_matching_card(pa); + if (prod == NULL) return; /* oops - not found?!? */ + + sc->sc_unit = sc->sc_dev.dv_unit; + printf(": %s\n", prod->name); + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 + callout_init(&sc->sc_T3_callout); + callout_init(&sc->sc_T4_callout); +#endif + + /* card initilization and sc setup */ + prod->attach(psc, pa); + + /* generic setup, if needed for this card */ + if (prod->pciattach) prod->pciattach(psc, pa); +} + +/*---------------------------------------------------------------------------* + * isic - pci device driver attach routine + *---------------------------------------------------------------------------*/ +static void +isic_pciattach(psc, pa) + struct pci_l1_softc *psc; + struct pci_attach_args *pa; +{ + struct l1_softc *sc = &psc->sc_isic; + pci_chipset_tag_t pc = pa->pa_pc; + pci_intr_handle_t ih; + const char *intrstr; + + static char *ISACversion[] = { + "2085 Version A1/A2 or 2086/2186 Version 1.1", + "2085 Version B1", + "2085 Version B2", + "2085 Version V2.3 (B3)", + "Unknown Version" + }; + + static char *HSCXversion[] = { + "82525 Version A1", + "Unknown (0x01)", + "82525 Version A2", + "Unknown (0x03)", + "82525 Version A3", + "82525 or 21525 Version 2.1", + "Unknown Version" + }; + + l1_sc[sc->sc_unit] = sc; /* XXX - hack! */ + + sc->sc_isac_version = 0; + sc->sc_hscx_version = 0; + + if(sc->sc_ipac) + { + u_int ret = IPAC_READ(IPAC_ID); + + switch(ret) + { + case 0x01: + printf("%s: IPAC PSB2115 Version 1.1\n", sc->sc_dev.dv_xname); + break; + + case 0x02: + printf("%s: IPAC PSB2115 Version 2\n", sc->sc_dev.dv_xname); + break; + + default: + printf("%s: Error, IPAC version %d unknown!\n", + sc->sc_dev.dv_xname, ret); + return; + } + } + else + { + sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; + + switch(sc->sc_isac_version) + { + case ISAC_VA: + case ISAC_VB1: + case ISAC_VB2: + case ISAC_VB3: + printf("%s: ISAC %s (IOM-%c)\n", + sc->sc_dev.dv_xname, + ISACversion[sc->sc_isac_version], + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + break; + + default: + printf("%s: Error, ISAC version %d unknown!\n", + sc->sc_dev.dv_xname, sc->sc_isac_version); + return; + } + + sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; + + switch(sc->sc_hscx_version) + { + case HSCX_VA1: + case HSCX_VA2: + case HSCX_VA3: + case HSCX_V21: + printf("%s: HSCX %s\n", + sc->sc_dev.dv_xname, + HSCXversion[sc->sc_hscx_version]); + break; + + default: + printf("%s: Error, HSCX version %d unknown!\n", + sc->sc_dev.dv_xname, sc->sc_hscx_version); + return; + } + } + + /* ISAC setup */ + + isic_isac_init(sc); + + /* HSCX setup */ + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* setup linktab */ + + isic_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + +#if defined(__FreeBSD__) && __FreeBSD__ >=3 + callout_handle_init(&sc->sc_T3_callout); + callout_handle_init(&sc->sc_T4_callout); +#endif + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + + /* Map and establish the interrupt. */ + if (pci_intr_map(pa, &ih)) { + printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); + return; + } + intrstr = pci_intr_string(pc, ih); + psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, isicintr, sc); + if (psc->sc_ih == NULL) { + printf("%s: couldn't establish interrupt", + sc->sc_dev.dv_xname); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + return; + } + printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); +} + diff --git a/sys/dev/pci/pci_isic.h b/sys/dev/pci/pci_isic.h new file mode 100644 index 00000000000..560f25515da --- /dev/null +++ b/sys/dev/pci/pci_isic.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1999 Martin Husemann. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * pci_isic.h - pci bus frontend for i4b_isic driver + * ------------------------------------------------- + * + * $Id: pci_isic.h,v 1.1.1.1 2001/01/05 12:50:20 martin Exp $ + * + * last edit-date: [Wed Mar 10 07:22:08 1999] + * + * -mh original implementation + * + *---------------------------------------------------------------------------*/ + +struct pci_l1_softc { + struct l1_softc sc_isic; /* parent class */ + + /* PCI-specific goo */ + void *sc_ih; /* interrupt handler */ +}; + +extern void isic_attach_Eqs1pp __P((struct pci_l1_softc *psc, struct pci_attach_args *pa)); +extern void isic_attach_fritzPci __P((struct pci_l1_softc *psc, struct pci_attach_args *pa)); + diff --git a/sys/dev/pcmcia/i4b_avm_fritz_pcmcia.c b/sys/dev/pcmcia/i4b_avm_fritz_pcmcia.c new file mode 100644 index 00000000000..73f1473f65b --- /dev/null +++ b/sys/dev/pcmcia/i4b_avm_fritz_pcmcia.c @@ -0,0 +1,499 @@ +/* + * Copyright (c) 1998 Matthias Apitz. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * Fritz!Card pcmcia specific routines for isic driver + * --------------------------------------------------- + * + * $Id: i4b_avm_fritz_pcmcia.c,v 1.1.1.1 2001/01/05 12:50:21 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:39:32 2001] + * + * -ap added support for AVM PCMCIA Fritz!Card + * -mh split into separate file + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicpcmcia.h" +#ifdef ISICPCMCIA_AVM_A1 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#ifndef __FreeBSD__ +#include <dev/pcmcia/pcmcia_isic.h> + +/* PCMCIA support routines */ +static u_int8_t avma1_pcmcia_read_reg __P((struct l1_softc *sc, int what, bus_size_t offs)); +static void avma1_pcmcia_write_reg __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void avma1_pcmcia_read_fifo __P((struct l1_softc *sc, int what, void *buf, size_t size)); +static void avma1_pcmcia_write_fifo __P((struct l1_softc *sc, int what, const void *data, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * AVM PCMCIA Fritz!Card special registers + *---------------------------------------------------------------------------*/ + +/* + * register offsets from i/o base 0x140 or 0x300 + */ +#define ADDR_REG_OFFSET 0x02 +#define DATA_REG_OFFSET 0x03 +#define STAT0_OFFSET 0x04 +#define STAT1_OFFSET 0x05 +#define MODREG_OFFSET 0x06 +#define VERREG_OFFSET 0x07 +/* + * AVM PCMCIA Status Latch 0 read only bits + */ +#define ASL_IRQ_TIMER 0x10 /* Timer interrupt, active low */ +#define ASL_IRQ_ISAC 0x20 /* ISAC interrupt, active low */ +#define ASL_IRQ_HSCX 0x40 /* HSX interrupt, active low */ +#define ASL_IRQ_BCHAN ASL_IRQ_HSCX +#define ASL_IRQ_Pending (ASL_IRQ_ISAC | ASL_IRQ_HSCX | ASL_IRQ_TIMER) +/* + * AVM Status Latch 0 write only bits + */ +#define ASL_RESET_ALL 0x01 /* reset siemens IC's, active 1 */ +#define ASL_TIMERDISABLE 0x02 /* active high */ +#define ASL_TIMERRESET 0x04 /* active high */ +#define ASL_ENABLE_INT 0x08 /* active high */ +/* + * AVM Status Latch 1 write only bits + */ +#define ASL1_LED0 0x10 /* active high */ +#define ASL1_LED1 0x20 /* active high */ + +#define ASL1_ENABLE_S0 0xc0 /* enable active S0 I/F */ + +/*----- EEpromless controller -----*/ +/* + * AVM Status Latch read/write bit + */ + +#define ASL_TESTBIT 0x80 + + +/*---------------------------------------------------------------------------* + * AVM read fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static int PCMCIA_IO_BASE = 0; /* ap: XXX hack */ +static void +avma1_pcmcia_read_fifo(void *buf, const void *base, size_t len) +{ + outb(PCMCIA_IO_BASE + ADDR_REG_OFFSET, (int)base - 0x20); + insb(PCMCIA_IO_BASE + DATA_REG_OFFSET, (u_char *)buf, (u_int)len); +} +#else +/* offsets of the different 'what' arguments */ +static u_int8_t what_map[] = { + 0x20-0x20, /* ISIC_WHAT_ISAC */ + 0xA0-0x20, /* ISIC_WHAT_HSCXA */ + 0xE0-0x20 /* ISIC_WHAT_HSCXB */ +}; +static void +avma1_pcmcia_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, ADDR_REG_OFFSET, what_map[what]); + bus_space_read_multi_1(t, h, DATA_REG_OFFSET, buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM write fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1_pcmcia_write_fifo(void *base, const void *buf, size_t len) +{ + outb(PCMCIA_IO_BASE + ADDR_REG_OFFSET, (int)base - 0x20); + outsb(PCMCIA_IO_BASE + DATA_REG_OFFSET, (u_char *)buf, (u_int)len); +} +#else +static void +avma1_pcmcia_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, ADDR_REG_OFFSET, what_map[what]); + bus_space_write_multi_1(t, h, DATA_REG_OFFSET, (u_int8_t*)buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM write register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1_pcmcia_write_reg(u_char *base, u_int offset, u_int v) +{ + /* offset includes 0x20 FIFO ! */ + outb(PCMCIA_IO_BASE + ADDR_REG_OFFSET, (int)base+offset-0x20); + outb(PCMCIA_IO_BASE + DATA_REG_OFFSET, (u_char)v); +} +#else +static void +avma1_pcmcia_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, ADDR_REG_OFFSET, what_map[what]+offs); + bus_space_write_1(t, h, DATA_REG_OFFSET, data); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM read register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static u_char +avma1_pcmcia_read_reg(u_char *base, u_int offset) +{ + /* offset includes 0x20 FIFO ! */ + outb(PCMCIA_IO_BASE + ADDR_REG_OFFSET, (int)base+offset-0x20); + return (inb(PCMCIA_IO_BASE + DATA_REG_OFFSET)); +} +#else +static u_int8_t +avma1_pcmcia_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, ADDR_REG_OFFSET, what_map[what]+offs); + return bus_space_read_1(t, h, DATA_REG_OFFSET); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_avma1_pcmcia - probe for AVM PCMCIA Fritz!Card + * This is in the bus attachemnt part on NetBSD (pcmcia_isic.c), no + * card specicfic probe is needed on direct config buses like pcmcia. + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_probe_avma1_pcmcia(struct isa_device *dev) +{ + struct l1_softc *sc = &l1_sc[dev->id_unit]; + u_char byte; + int i; + u_int cardinfo; + + /* check max unit range */ + + if(dev->id_unit > 1) + { + printf("isic%d: Error, unit %d > MAXUNIT for AVM PCMCIA Fritz!Card\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* + * we trust the IRQ we got from PCCARD service + */ + sc->sc_irq = dev->id_irq; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0x140: + case 0x300: + break; + default: + printf("isic%d: Error, invalid iobase 0x%x specified for AVM PCMCIA Fritz!Card.\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + /* ResetController */ + + outb(dev->id_iobase + STAT0_OFFSET, 0x00); + DELAY(SEC_DELAY / 20); + outb(dev->id_iobase + STAT0_OFFSET, 0x01); + DELAY(SEC_DELAY / 20); + outb(dev->id_iobase + STAT0_OFFSET, 0x00); + + /* + * CheckController + * The logic to check for the PCMCIA was adapted as + * described by AVM. + */ + + outb(dev->id_iobase + ADDR_REG_OFFSET, 0x21); /* ISAC STAR */ + if ( (byte=inb(dev->id_iobase + DATA_REG_OFFSET) & 0xfd) != 0x48 ) + { + printf("isic%d: Error, ISAC STAR for AVM PCMCIA is 0x%0x (should be 0x48)\n", + dev->id_unit, byte); + return(0); + } + + outb(dev->id_iobase + ADDR_REG_OFFSET, 0xa1); /* HSCX STAR */ + if ( (byte=inb(dev->id_iobase + DATA_REG_OFFSET) & 0xfd) != 0x48 ) + { + printf("isic%d: Error, HSCX STAR for AVM PCMCIA is 0x%0x (should be 0x48)\n", + dev->id_unit, byte); + return(0); + } + + byte = ASL_TESTBIT; + for (i=0; i<256; i++) { + byte = byte ? 0 : ASL_TESTBIT; + outb(dev->id_iobase + STAT0_OFFSET, byte); + if ((inb(dev->id_iobase+STAT0_OFFSET)&ASL_TESTBIT)!=byte) { + printf("isic%d: Error during toggle of AVM PCMCIA Status Latch0\n", + dev->id_unit); + return(0); + } + } + + sc->clearirq = NULL; + sc->readreg = avma1_pcmcia_read_reg; + sc->writereg = avma1_pcmcia_write_reg; + + sc->readfifo = avma1_pcmcia_read_fifo; + sc->writefifo = avma1_pcmcia_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_PCFRITZ; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; /* ap: XXX ??? */ + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + /* + * NOTE: for PCMCIA these are no real addrs; they are + * offsets to be written into the base+ADDR_REG_OFFSET register + * to pick up the values of the bytes fro base+DATA_REG_OFFSET + * + * see also the logic in the avma1_pcmcia_* routines; + * therefore we also must have the base addr in some static + * space or struct; XXX better solution? + */ + + PCMCIA_IO_BASE = dev->id_iobase; + ISAC_BASE = (caddr_t)0x20; + + HSCX_A_BASE = (caddr_t)0xA0; + HSCX_B_BASE = (caddr_t)0xE0; + + /* + * Read HSCX A/B VSTR. + * Expected value for AVM A1 is 0x04 or 0x05 and for the + * AVM Fritz!Card is 0x05 in the least significant bits. + */ + + if( (((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(0, H_VSTR) & 0xf) != 0x4)) || + (((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x4)) ) + { + printf("isic%d: HSCX VSTR test failed for AVM PCMCIA Fritz!Card\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: 0x%0x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: 0x%0x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + /* + * seems we really have an AVM PCMCIA Fritz!Card controller + */ + cardinfo = inb(dev->id_iobase + VERREG_OFFSET)<<8 | inb(dev->id_iobase + MODREG_OFFSET); + printf("isic%d: successfully detect AVM PCMCIA cardinfo = 0x%0x\n", + dev->id_unit, cardinfo); + dev->id_flags = FLAG_AVM_A1_PCMCIA; + return (1); +} +#endif /* __FreeBSD__ */ + + + +/*---------------------------------------------------------------------------* + * isic_attach_fritzpcmcia - attach Fritz!Card + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_attach_fritzpcmcia(struct isa_device *dev) +{ + /* ResetController again just to make sure... */ + + outb(dev->id_iobase + STAT0_OFFSET, 0x00); + DELAY(SEC_DELAY / 10); + outb(dev->id_iobase + STAT0_OFFSET, 0x01); + DELAY(SEC_DELAY / 10); + outb(dev->id_iobase + STAT0_OFFSET, 0x00); + DELAY(SEC_DELAY / 10); + + /* enable IRQ, disable counter IRQ */ + + outb(dev->id_iobase + STAT0_OFFSET, ASL_TIMERDISABLE | + ASL_TIMERRESET | ASL_ENABLE_INT); + /* DELAY(SEC_DELAY / 10); */ + + return(1); +} + +#else + +/* + * XXX - one time only! Some of this has to go into an enable + * function, with apropriate counterpart in disable, so a card + * could be removed an inserted again. But never mind for now, + * this won't work anyway for several reasons (both in NetBSD + * and in I4B). + */ +int +isic_attach_fritzpcmcia(struct pcmcia_l1_softc *psc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa) +{ + struct l1_softc *sc = &psc->sc_isic; + bus_space_tag_t t; + bus_space_handle_t h; + + /* Validate config info */ + if (cfe->num_memspace != 0) + printf(": unexpected number of memory spaces %d should be 0\n", + cfe->num_memspace); + if (cfe->num_iospace != 1) + printf(": unexpected number of memory spaces %d should be 1\n", + cfe->num_iospace); + + /* Allocate pcmcia space - exactly as dictated by the card */ + if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start, cfe->iospace[0].length, + 0, &psc->sc_pcioh)) + printf(": can't allocate i/o space\n"); + + /* map them */ + if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? + PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, + cfe->iospace[0].length, &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return 0; + } + + /* Setup bus space maps */ + sc->sc_num_mappings = 1; + sc->sc_cardtyp = CARD_TYPEP_PCFRITZ; + MALLOC_MAPS(sc); + + /* Copy our handles/tags to the MI maps */ + sc->sc_maps[0].t = psc->sc_pcioh.iot; + sc->sc_maps[0].h = psc->sc_pcioh.ioh; + sc->sc_maps[0].offset = 0; + sc->sc_maps[0].size = 0; /* not our mapping */ + + t = sc->sc_maps[0].t; + h = sc->sc_maps[0].h; + + sc->clearirq = NULL; + sc->readreg = avma1_pcmcia_read_reg; + sc->writereg = avma1_pcmcia_write_reg; + + sc->readfifo = avma1_pcmcia_read_fifo; + sc->writefifo = avma1_pcmcia_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_PCFRITZ; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* Reset controller again just to make sure... */ + + bus_space_write_1(t, h, STAT0_OFFSET, 0x00); + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, STAT0_OFFSET, 0x01); + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, STAT0_OFFSET, 0x00); + DELAY(SEC_DELAY / 10); + + /* enable IRQ, disable counter IRQ */ + + bus_space_write_1(t, h, STAT0_OFFSET, ASL_TIMERDISABLE | + ASL_TIMERRESET | ASL_ENABLE_INT); + + return 1; +} +#endif + +#endif /* ISICPCMCIA_AVM_A1 */ diff --git a/sys/dev/pcmcia/i4b_elsa_isdnmc.c b/sys/dev/pcmcia/i4b_elsa_isdnmc.c new file mode 100644 index 00000000000..b047b09dcc0 --- /dev/null +++ b/sys/dev/pcmcia/i4b_elsa_isdnmc.c @@ -0,0 +1,323 @@ +/* + * Copyright (c) 1998 Martin Husemann. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * ELSA MicroLink ISDN/MC card specific routines + * --------------------------------------------- + * + * $Id: i4b_elsa_isdnmc.c,v 1.1.1.1 2001/01/05 12:50:21 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:39:32 2001] + * + * -mh added support for elsa ISDN/mc + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicpcmcia.h" +#ifdef ISICPCMCIA_ELSA_ISDNMC + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <dev/pcmcia/pcmcia_isic.h> + +#ifndef __FreeBSD__ +/* PCMCIA support routines */ +static u_int8_t elsa_isdnmc_read_reg __P((struct l1_softc *sc, int what, bus_size_t offs)); +static void elsa_isdnmc_write_reg __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void elsa_isdnmc_read_fifo __P((struct l1_softc *sc, int what, void *buf, size_t size)); +static void elsa_isdnmc_write_fifo __P((struct l1_softc *sc, int what, const void *data, size_t size)); +static void elsa_isdnmc_clrirq __P((struct l1_softc *sc)); +#endif + +/* + * The ELSA MicroLink ISDN/MC uses one contigous IO region, + * mapped by the pcmcia code. + * The chip access is via three ports: + */ +#define ISAC_DATA 1 /* ISAC dataport at offset 1 */ +#define HSCX_DATA 2 /* HSCX dataport at offset 2 */ +#define ADDR_LATCH 4 /* address latch at offset 4 */ + +/* This is very similar to the ELSA QuickStep 1000 (ISA) card */ + +#ifdef __FreeBSD__ +static void +elsa_isdnmc_clrirq(void *base) +{ +} +#else +static void +elsa_isdnmc_clrirq(struct l1_softc *sc) +{ + ISAC_WRITE(I_MASK, 0xff); + HSCX_WRITE(0, H_MASK, 0xff); + HSCX_WRITE(1, H_MASK, 0xff); + ISAC_WRITE(I_MASK, ISAC_IMASK); + HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); + HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); +} +#endif + +/*---------------------------------------------------------------------------* + * read fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +elsa_isdnmc_read_fifo(void *buf, const void *base, size_t len) +{ +} +#else +static void +elsa_isdnmc_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR_LATCH, 0); + bus_space_read_multi_1(t, h, ISAC_DATA, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR_LATCH, 0); + bus_space_read_multi_1(t, h, HSCX_DATA, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR_LATCH, 0x40); + bus_space_read_multi_1(t, h, HSCX_DATA, buf, size); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * write fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +elsa_isdnmc_write_fifo(void *base, const void *buf, size_t len) +{ +} +#else +static void +elsa_isdnmc_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR_LATCH, 0); + bus_space_write_multi_1(t, h, ISAC_DATA, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR_LATCH, 0); + bus_space_write_multi_1(t, h, HSCX_DATA, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR_LATCH, 0x40); + bus_space_write_multi_1(t, h, HSCX_DATA, (u_int8_t*)buf, size); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * write register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +elsa_isdnmc_write_reg(u_char *base, u_int offset, u_int v) +{ +} +#else +static void +elsa_isdnmc_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR_LATCH, offs); + bus_space_write_1(t, h, ISAC_DATA, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR_LATCH, offs); + bus_space_write_1(t, h, HSCX_DATA, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR_LATCH, 0x40+offs); + bus_space_write_1(t, h, HSCX_DATA, data); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * read register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static u_char +elsa_isdnmc_read_reg(u_char *base, u_int offset) +{ + return 0; +} +#else +static u_int8_t +elsa_isdnmc_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR_LATCH, offs); + return bus_space_read_1(t, h, ISAC_DATA); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR_LATCH, offs); + return bus_space_read_1(t, h, HSCX_DATA); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR_LATCH, 0x40+offs); + return bus_space_read_1(t, h, HSCX_DATA); + } + return 0; +} +#endif + +#ifdef __FreeBSD__ +#else + +/* + * XXX - one time only! Some of this has to go into an enable + * function, with apropriate counterpart in disable, so a card + * could be removed an inserted again. But never mind for now, + * this won't work anyway for several reasons (both in NetBSD + * and in I4B). + */ +int +isic_attach_elsaisdnmc(struct pcmcia_l1_softc *psc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa) +{ + struct l1_softc *sc = &psc->sc_isic; + bus_space_tag_t t; + bus_space_handle_t h; + + /* Validate config info */ + if (cfe->num_memspace != 0) + printf(": unexpected number of memory spaces %d should be 0\n", + cfe->num_memspace); + if (cfe->num_iospace != 1) + printf(": unexpected number of memory spaces %d should be 1\n", + cfe->num_iospace); + + /* Allocate pcmcia space */ + if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length, + cfe->iospace[0].length, &psc->sc_pcioh)) + printf(": can't allocate i/o space\n"); + + /* map them */ + if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? + PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, + cfe->iospace[0].length, &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return 0; + } + + /* OK, this will work! */ + sc->sc_cardtyp = CARD_TYPEP_ELSAMLIMC; + + /* Setup bus space maps */ + sc->sc_num_mappings = 1; + MALLOC_MAPS(sc); + + /* Copy our handles/tags to the MI maps */ + sc->sc_maps[0].t = psc->sc_pcioh.iot; + sc->sc_maps[0].h = psc->sc_pcioh.ioh; + sc->sc_maps[0].offset = 0; + sc->sc_maps[0].size = 0; /* not our mapping */ + + t = sc->sc_maps[0].t; + h = sc->sc_maps[0].h; + + sc->clearirq = elsa_isdnmc_clrirq; + + sc->readreg = elsa_isdnmc_read_reg; + sc->writereg = elsa_isdnmc_write_reg; + + sc->readfifo = elsa_isdnmc_read_fifo; + sc->writefifo = elsa_isdnmc_write_fifo; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + return 1; +} +#endif + +#endif /* ISICPCMCIA_ELSA_ISDNMC */ diff --git a/sys/dev/pcmcia/i4b_elsa_mcall.c b/sys/dev/pcmcia/i4b_elsa_mcall.c new file mode 100644 index 00000000000..5fadd4a4859 --- /dev/null +++ b/sys/dev/pcmcia/i4b_elsa_mcall.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 1998 Martin Husemann. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * ELSA MicroLink MC/all card specific routines + * -------------------------------------------- + * + * $Id: i4b_elsa_mcall.c,v 1.1.1.1 2001/01/05 12:50:21 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:39:32 2001] + * + * -mh started support for ELSA MC/all + * + *---------------------------------------------------------------------------*/ + +#include "opt_isicpcmcia.h" +#ifdef ISICPCMCIA_ELSA_MCALL + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <netisdn/i4b_debug.h> +#include <netisdn/i4b_ioctl.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> +#include <dev/ic/i4b_ipac.h> + +#include <dev/pcmcia/pcmcia_isic.h> + +#ifndef __FreeBSD__ +/* PCMCIA support routines */ +static u_int8_t elsa_mcall_read_reg __P((struct l1_softc *sc, int what, bus_size_t offs)); +static void elsa_mcall_write_reg __P((struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void elsa_mcall_read_fifo __P((struct l1_softc *sc, int what, void *buf, size_t size)); +static void elsa_mcall_write_fifo __P((struct l1_softc *sc, int what, const void *data, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * read fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static int PCMCIA_IO_BASE = 0; /* ap: XXX hack */ +static void +elsa_mcall_read_fifo(void *buf, const void *base, size_t len) +{ +} +#else +static void +elsa_mcall_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + /* + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + */ +} +#endif + +/*---------------------------------------------------------------------------* + * write fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +elsa_mcall_write_fifo(void *base, const void *buf, size_t len) +{ +} +#else +static void +elsa_mcall_write_fifo(struct l1_softc *sc, int what, const void *buf, size_t size) +{ + /* + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + */ +} +#endif + +/*---------------------------------------------------------------------------* + * write register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +elsa_mcall_write_reg(u_char *base, u_int offset, u_int v) +{ +} +#else +static void +elsa_mcall_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + /* + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + */ +} +#endif + +/*---------------------------------------------------------------------------* + * read register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static u_char +elsa_mcall_read_reg(u_char *base, u_int offset) +{ + return 0; +} +#else +static u_int8_t +elsa_mcall_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + /* + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + */ + return 0; +} +#endif + +#ifdef __FreeBSD__ +#else + +/* + * XXX - one time only! Some of this has to go into an enable + * function, with apropriate counterpart in disable, so a card + * could be removed an inserted again. But never mind for now, + * this won't work anyway for several reasons (both in NetBSD + * and in I4B). + */ +int +isic_attach_elsamcall(struct pcmcia_l1_softc *psc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa) +{ + struct l1_softc *sc = &psc->sc_isic; + bus_space_tag_t t; + bus_space_handle_t h; + + /* Validate config info */ + if (cfe->num_memspace != 0) + printf(": unexpected number of memory spaces %d should be 0\n", + cfe->num_memspace); + if (cfe->num_iospace != 1) + printf(": unexpected number of memory spaces %d should be 1\n", + cfe->num_iospace); + + /* Allocate pcmcia space */ + if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length, + cfe->iospace[0].length, &psc->sc_pcioh)) + printf(": can't allocate i/o space\n"); + + /* map them */ + if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? + PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, + cfe->iospace[0].length, &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return 0; + } + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_ELSAMLMCALL; + + /* Setup bus space maps */ + sc->sc_num_mappings = 1; + MALLOC_MAPS(sc); + + /* Copy our handles/tags to the MI maps */ + sc->sc_maps[0].t = psc->sc_pcioh.iot; + sc->sc_maps[0].h = psc->sc_pcioh.ioh; + sc->sc_maps[0].offset = 0; + sc->sc_maps[0].size = 0; /* not our mapping */ + + t = sc->sc_maps[0].t; + h = sc->sc_maps[0].h; + + sc->clearirq = NULL; + sc->readreg = elsa_mcall_read_reg; + sc->writereg = elsa_mcall_write_reg; + + sc->readfifo = elsa_mcall_read_fifo; + sc->writefifo = elsa_mcall_write_fifo; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 1; + sc->sc_bfifolen = IPAC_BFIFO_LEN; + + return 1; +} +#endif + +#endif /* ISICPCMCIA_ELSA_MCALL */ diff --git a/sys/dev/pcmcia/pcmcia_isic.c b/sys/dev/pcmcia/pcmcia_isic.c new file mode 100644 index 00000000000..f77b26ea534 --- /dev/null +++ b/sys/dev/pcmcia/pcmcia_isic.c @@ -0,0 +1,369 @@ +/* + * Copyright (c) 1998 Martin Husemann. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * pcmcia_isic.c - pcmcia bus frontend for i4b_isic driver + * ------------------------------------------------------- + * + * $Id: pcmcia_isic.c,v 1.1.1.1 2001/01/05 12:50:20 martin Exp $ + * + * last edit-date: [Fri Jan 5 11:39:32 2001] + * + * -mh original implementation + * + *---------------------------------------------------------------------------*/ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/systm.h> +#include <sys/malloc.h> + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 +#include <sys/callout.h> +#endif + +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmciadevs.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <netisdn/i4b_ioctl.h> +#include <netisdn/i4b_trace.h> +#endif + +#include <dev/ic/i4b_isicl1.h> +#include <dev/ic/i4b_ipac.h> +#include <dev/ic/i4b_isac.h> +#include <dev/ic/i4b_hscx.h> + +#include <netisdn/i4b_l1l2.h> +#include <netisdn/i4b_global.h> + +#include <dev/pcmcia/pcmcia_isic.h> + +#include "opt_isicpcmcia.h" + +static int pcmcia_isic_match __P((struct device *, struct cfdata *, void *)); +static void pcmcia_isic_attach __P((struct device *, struct device *, void *)); +static const struct isic_pcmcia_card_entry * find_matching_card __P((struct pcmcia_attach_args *pa)); +static int pcmcia_isicattach __P((struct l1_softc *sc)); + +struct cfattach pcmcia_isic_ca = { + sizeof(struct pcmcia_l1_softc), pcmcia_isic_match, pcmcia_isic_attach +}; + +struct isic_pcmcia_card_entry { + int32_t vendor; /* vendor ID */ + int32_t product; /* product ID */ + char *cis1_info[4]; /* CIS info to match */ + char *name; /* name of controller */ + int function; /* expected PCMCIA function type */ + int card_type; /* card type found */ + isic_pcmcia_attach_func attach; /* card initialization */ +}; + +static const struct isic_pcmcia_card_entry card_list[] = { + +#ifdef ISICPCMCIA_AVM_A1 + { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, + { "AVM", "ISDN A", NULL, NULL }, + "AVM Fritz!Card", PCMCIA_FUNCTION_NETWORK, + CARD_TYPEP_PCFRITZ, isic_attach_fritzpcmcia }, +#endif + +#ifdef ISICPCMCIA_ELSA_ISDNMC + { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, + { "ELSA GmbH, Aachen", "MicroLink ISDN/MC ", NULL, NULL }, + "ELSA MicroLink ISDN/MC", PCMCIA_FUNCTION_NETWORK, + CARD_TYPEP_ELSAMLIMC, isic_attach_elsaisdnmc }, + { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, + { "ELSA AG, Aachen", "MicroLink ISDN/MC ", NULL, NULL }, + "ELSA MicroLink ISDN/MC", PCMCIA_FUNCTION_NETWORK, + CARD_TYPEP_ELSAMLIMC, isic_attach_elsaisdnmc }, +#endif + +#ifdef ISICPCMCIA_ELSA_MCALL + { 0x105, 0x410a, + { "ELSA", "MicroLink MC all", NULL, NULL }, + "ELSA MicroLink MCall", PCMCIA_FUNCTION_NETWORK, + CARD_TYPEP_ELSAMLMCALL, isic_attach_elsamcall }, +#endif + +}; +#define NUM_MATCH_ENTRIES (sizeof(card_list)/sizeof(card_list[0])) + +static const struct isic_pcmcia_card_entry * +find_matching_card(pa) + struct pcmcia_attach_args *pa; +{ + int i, j; + + for (i = 0; i < NUM_MATCH_ENTRIES; i++) { + if (card_list[i].vendor != PCMCIA_VENDOR_INVALID && pa->card->manufacturer != card_list[i].vendor) + continue; + if (card_list[i].product != PCMCIA_PRODUCT_INVALID && pa->card->product != card_list[i].product) + continue; + if (pa->pf->function != card_list[i].function) + continue; + for (j = 0; j < 4; j++) { + if (card_list[i].cis1_info[j] == NULL) + continue; /* wildcard */ + if (pa->card->cis1_info[j] == NULL) + break; /* not available */ + if (strcmp(pa->card->cis1_info[j], card_list[i].cis1_info[j]) != 0) + break; /* mismatch */ + } + if (j >= 4) + break; + } + if (i >= NUM_MATCH_ENTRIES) + return NULL; + + return &card_list[i]; +} + +/* + * Match card + */ +static int +pcmcia_isic_match(parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; +{ + struct pcmcia_attach_args *pa = aux; + + if (!find_matching_card(pa)) + return 0; + + return 1; +} + +/* + * Attach the card + */ +static void +pcmcia_isic_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct pcmcia_l1_softc *psc = (void*) self; + struct l1_softc *sc = &psc->sc_isic; + struct pcmcia_attach_args *pa = aux; + struct pcmcia_config_entry *cfe; + const struct isic_pcmcia_card_entry * cde; + + /* Which card is it? */ + cde = find_matching_card(pa); + if (cde == NULL) return; /* oops - not found?!? */ + + psc->sc_pf = pa->pf; + cfe = pa->pf->cfe_head.sqh_first; + + /* Enable the card */ + pcmcia_function_init(pa->pf, cfe); + pcmcia_function_enable(pa->pf); + + if (!cde->attach(psc, cfe, pa)) + return; /* Ooops ? */ + + sc->sc_unit = sc->sc_dev.dv_unit; + + /* Announce card name */ + printf(": %s\n", cde->name); + + /* MI initilization */ + pcmcia_isicattach(sc); + + /* setup interrupt */ + psc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, isicintr, sc); +} + +/*---------------------------------------------------------------------------* + * card independend attach for pcmicia cards + *---------------------------------------------------------------------------*/ + +/* parameter and format for message producing e.g. "isic0: " */ + +#ifdef __FreeBSD__ +#define ISIC_FMT "isic%d: " +#define ISIC_PARM dev->id_unit +#define TERMFMT " " +#else +#define ISIC_FMT "%s: " +#define ISIC_PARM sc->sc_dev.dv_xname +#define TERMFMT "\n" +#endif + +int +pcmcia_isicattach(struct l1_softc *sc) +{ + static char *ISACversion[] = { + "2085 Version A1/A2 or 2086/2186 Version 1.1", + "2085 Version B1", + "2085 Version B2", + "2085 Version V2.3 (B3)", + "Unknown Version" + }; + + static char *HSCXversion[] = { + "82525 Version A1", + "Unknown (0x01)", + "82525 Version A2", + "Unknown (0x03)", + "82525 Version A3", + "82525 or 21525 Version 2.1", + "Unknown Version" + }; + + l1_sc[sc->sc_unit] = sc; + sc->sc_isac_version = 0; + sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; + + switch(sc->sc_isac_version) + { + case ISAC_VA: + case ISAC_VB1: + case ISAC_VB2: + case ISAC_VB3: + break; + + default: + printf(ISIC_FMT "Error, ISAC version %d unknown!\n", + ISIC_PARM, sc->sc_isac_version); + return(0); + break; + } + + sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; + + switch(sc->sc_hscx_version) + { + case HSCX_VA1: + case HSCX_VA2: + case HSCX_VA3: + case HSCX_V21: + break; + + default: + printf(ISIC_FMT "Error, HSCX version %d unknown!\n", + ISIC_PARM, sc->sc_hscx_version); + return(0); + break; + }; + + /* ISAC setup */ + + isic_isac_init(sc); + + /* HSCX setup */ + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* setup linktab */ + + isic_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 + callout_init(&sc->sc_T3_callout); + callout_init(&sc->sc_T4_callout); +#endif + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + /* announce chip versions */ + + if(sc->sc_isac_version >= ISAC_UNKN) + { + printf(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_isac_version); + sc->sc_isac_version = ISAC_UNKN; + } + else + { + printf(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT, + ISIC_PARM, + ISACversion[sc->sc_isac_version], + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + } + + if(sc->sc_hscx_version >= HSCX_UNKN) + { + printf(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_hscx_version); + sc->sc_hscx_version = HSCX_UNKN; + } + else + { + printf(ISIC_FMT "HSCX %s" TERMFMT, + ISIC_PARM, + HSCXversion[sc->sc_hscx_version]); + } + + return(1); +} + diff --git a/sys/dev/pcmcia/pcmcia_isic.h b/sys/dev/pcmcia/pcmcia_isic.h new file mode 100644 index 00000000000..f98d0611632 --- /dev/null +++ b/sys/dev/pcmcia/pcmcia_isic.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1998 Martin Husemann. 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. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * 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. + * + *--------------------------------------------------------------------------- + * + * pcmcia_isic.h - common definitions for pcmcia isic cards + * -------------------------------------------------------- + * + * $Id: pcmcia_isic.h,v 1.1.1.1 2001/01/05 12:50:21 martin Exp $ + * + * last edit-date: [Sun Feb 14 10:29:33 1999] + * + * -mh original implementation + * + *---------------------------------------------------------------------------*/ + +struct pcmcia_l1_softc { + struct l1_softc sc_isic; /* parent class */ + + /* PCMCIA-specific goo */ + struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ + int sc_io_window; /* our i/o window */ + struct pcmcia_function *sc_pf; /* our PCMCIA function */ + void *sc_ih; /* interrupt handler */ +}; + +typedef int (*isic_pcmcia_attach_func)(struct pcmcia_l1_softc *sc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa); + +extern int isic_attach_fritzpcmcia(struct pcmcia_l1_softc *sc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa); +extern int isic_attach_elsaisdnmc(struct pcmcia_l1_softc *sc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa); +extern int isic_attach_elsamcall(struct pcmcia_l1_softc *sc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa); + + |
