diff options
author | tanimura <tanimura@FreeBSD.org> | 2000-06-11 06:43:16 +0000 |
---|---|---|
committer | tanimura <tanimura@FreeBSD.org> | 2000-06-11 06:43:16 +0000 |
commit | 423e9563878f579d365a6cd05d272784bd92edc4 (patch) | |
tree | e33f7429f0e830f180f941f90eea41572dfd3a4c /sys/dev/rp/rp_isa.c | |
parent | 4fc801a85706650d7922df5965352e4517d542fd (diff) | |
download | FreeBSD-src-423e9563878f579d365a6cd05d272784bd92edc4.zip FreeBSD-src-423e9563878f579d365a6cd05d272784bd92edc4.tar.gz |
1. Update Comtrol RocketPort driver(rp) to version 3.02.
2. Newbusify the driver.
3. Build as a module.
4. Use correct minor numbers when creating device files.
5. Correctly lock control characters.
6. Return ENXIO when device not configured.
Submitted by: Tor Egge <Tor.Egge@fast.no>
7. Fix the baud_table.
Submitted by: Elliot Dierksen <ebd@oau.org>
Note:
- the old driver still lives in src/sys/i386/isa, so that you can
revert to it if something goes wrong.
- The module does not detach very well. Attaching works fine.
Diffstat (limited to 'sys/dev/rp/rp_isa.c')
-rw-r--r-- | sys/dev/rp/rp_isa.c | 506 |
1 files changed, 506 insertions, 0 deletions
diff --git a/sys/dev/rp/rp_isa.c b/sys/dev/rp/rp_isa.c new file mode 100644 index 0000000..fdea4a7 --- /dev/null +++ b/sys/dev/rp/rp_isa.c @@ -0,0 +1,506 @@ +/* + * Copyright (c) Comtrol Corporation <support@comtrol.com> + * All rights reserved. + * + * ISA-specific part separated from: + * sys/i386/isa/rp.c,v 1.33 1999/09/28 11:45:27 phk Exp + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted prodived that the follwoing conditions + * are met. + * 1. Redistributions of source code must retain the above copyright + * notive, this list of conditions and the following disclainer. + * 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 prodided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Comtrol Corporation. + * 4. The name of Comtrol Corporation may not be used to endorse or + * promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``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 COMTROL CORPORATION 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, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/fcntl.h> +#include <sys/malloc.h> +#include <sys/tty.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/kernel.h> +#include <machine/resource.h> +#include <machine/bus.h> +#include <sys/bus.h> +#include <sys/rman.h> + +#define ROCKET_C +#include <dev/rp/rpreg.h> +#include <dev/rp/rpvar.h> + +#include <isa/isavar.h> + +/* ISA-specific part of CONTROLLER_t */ +struct ISACONTROLLER_T { + int MBaseIO; /* rid of the Mudbac controller for this controller */ + int MReg0IO; /* offset0 of the Mudbac controller for this controller */ + int MReg1IO; /* offset1 of the Mudbac controller for this controller */ + int MReg2IO; /* offset2 of the Mudbac controller for this controller */ + int MReg3IO; /* offset3 of the Mudbac controller for this controller */ + Byte_t MReg2; + Byte_t MReg3; +}; +typedef struct ISACONTROLLER_T ISACONTROLLER_t; + +#define ISACTL(ctlp) ((ISACONTROLLER_t *)((ctlp)->bus_ctlp)) + +/*************************************************************************** +Function: sControllerEOI +Purpose: Strobe the MUDBAC's End Of Interrupt bit. +Call: sControllerEOI(MudbacCtlP,CtlP) + CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure + CONTROLLER_T *CtlP; Ptr to controller structure +*/ +#define sControllerEOI(MudbacCtlP,CtlP) \ + rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2 | INT_STROB) + +/*************************************************************************** +Function: sDisAiop +Purpose: Disable I/O access to an AIOP +Call: sDisAiop(MudbacCtlP,CtlP) + CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure + CONTROLLER_T *CtlP; Ptr to controller structure + int AiopNum; Number of AIOP on controller +*/ +#define sDisAiop(MudbacCtlP,CtlP,AIOPNUM) \ +{ \ + ISACTL(CtlP)->MReg3 &= rp_sBitMapClrTbl[AIOPNUM]; \ + rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \ +} + +/*************************************************************************** +Function: sEnAiop +Purpose: Enable I/O access to an AIOP +Call: sEnAiop(MudbacCtlP,CtlP) + CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure + CONTROLLER_T *CtlP; Ptr to controller structure + int AiopNum; Number of AIOP on controller +*/ +#define sEnAiop(MudbacCtlP,CtlP,AIOPNUM) \ +{ \ + ISACTL(CtlP)->MReg3 |= rp_sBitMapSetTbl[AIOPNUM]; \ + rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \ +} + +/*************************************************************************** +Function: sGetControllerIntStatus +Purpose: Get the controller interrupt status +Call: sGetControllerIntStatus(MudbacCtlP,CtlP) + CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure + CONTROLLER_T *CtlP; Ptr to controller structure +Return: Byte_t: The controller interrupt status in the lower 4 + bits. Bits 0 through 3 represent AIOP's 0 + through 3 respectively. If a bit is set that + AIOP is interrupting. Bits 4 through 7 will + always be cleared. +*/ +#define sGetControllerIntStatus(MudbacCtlP,CtlP) \ + (rp_readio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg1IO) & 0x0f) + +static devclass_t rp_devclass; +static CONTROLLER_t *rp_controller; +static int rp_nisadevs; + +static int rp_probe(device_t dev); +static int rp_attach(device_t dev); +static void rp_isareleaseresource(CONTROLLER_t *ctlp); +static int sInitController(CONTROLLER_T *CtlP, + CONTROLLER_T *MudbacCtlP, + int AiopNum, + int IRQNum, + Byte_t Frequency, + int PeriodicOnly); +static rp_aiop2rid_t rp_isa_aiop2rid; +static rp_aiop2off_t rp_isa_aiop2off; +static rp_ctlmask_t rp_isa_ctlmask; + +static int +rp_probe(device_t dev) +{ + int unit; + CONTROLLER_t *controller; + int num_aiops; + CONTROLLER_t *ctlp; + int retval; + + /* + * We have no PnP RocketPort cards. + * (At least according to LINT) + */ + if (isa_get_logicalid(dev) != 0) + return (ENXIO); + + /* We need IO port resource to configure an ISA device. */ + if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 0) + return (ENXIO); + + unit = device_get_unit(dev); + if (unit >= 4) { + device_printf(dev, "rpprobe: unit number %d invalid.\n", unit); + return (ENXIO); + } + device_printf(dev, "probing for RocketPort(ISA) unit %d.\n", unit); + + ctlp = device_get_softc(dev); + bzero(ctlp, sizeof(*ctlp)); + ctlp->dev = dev; + ctlp->aiop2rid = rp_isa_aiop2rid; + ctlp->aiop2off = rp_isa_aiop2off; + ctlp->ctlmask = rp_isa_ctlmask; + + /* The IO ports of AIOPs for an ISA controller are discrete. */ + ctlp->io_num = 1; + ctlp->io_rid = malloc(sizeof(*(ctlp->io_rid)) * MAX_AIOPS_PER_BOARD, M_DEVBUF, M_NOWAIT); + ctlp->io = malloc(sizeof(*(ctlp->io)) * MAX_AIOPS_PER_BOARD, M_DEVBUF, M_NOWAIT); + if (ctlp->io_rid == NULL || ctlp->io == NULL) { + device_printf(dev, "rp_attach: Out of memory.\n"); + retval = ENOMEM; + goto nogo; + } + bzero(ctlp->io_rid, sizeof(*(ctlp->io_rid)) * MAX_AIOPS_PER_BOARD); + bzero(ctlp->io, sizeof(*(ctlp->io)) * MAX_AIOPS_PER_BOARD); + + ctlp->bus_ctlp = malloc(sizeof(ISACONTROLLER_t) * 1, M_DEVBUF, M_NOWAIT); + if (ctlp->bus_ctlp == NULL) { + device_printf(dev, "rp_attach: Out of memory.\n"); + retval = ENOMEM; + goto nogo; + } + bzero(ctlp->bus_ctlp, sizeof(ISACONTROLLER_t) * 1); + + ctlp->io_rid[0] = 0; + if (rp_controller != NULL) { + controller = rp_controller; + ctlp->io[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0, ~0, 0x40, RF_ACTIVE); + } else { + controller = rp_controller = ctlp; + ctlp->io[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0, ~0, 0x44, RF_ACTIVE); + } + if (ctlp->io[0] == NULL) { + device_printf(dev, "rp_attach: Resource not available.\n"); + retval = ENXIO; + goto nogo; + } + + num_aiops = sInitController(ctlp, + controller, + MAX_AIOPS_PER_BOARD, 0, + FREQ_DIS, 0); + if (num_aiops <= 0) { + device_printf(dev, "board%d init failed.\n", unit); + retval = ENXIO; + goto nogo; + } + + if (rp_controller == NULL) + rp_controller = controller; + rp_nisadevs++; + + device_set_desc(dev, "RocketPort ISA"); + + return (0); + +nogo: + rp_isareleaseresource(ctlp); + + return (retval); +} + +static int +rp_attach(device_t dev) +{ + int unit; + int num_ports, num_aiops; + int aiop; + CONTROLLER_t *ctlp; + int retval; + + unit = device_get_unit(dev); + + ctlp = device_get_softc(dev); + +#if notdef + num_aiops = sInitController(ctlp, + rp_controller, + MAX_AIOPS_PER_BOARD, 0, + FREQ_DIS, 0); +#else + num_aiops = ctlp->NumAiop; +#endif /* notdef */ + + num_ports = 0; + for(aiop=0; aiop < num_aiops; aiop++) { + sResetAiopByNum(ctlp, aiop); + sEnAiop(rp_controller, ctlp, aiop); + num_ports += sGetAiopNumChan(ctlp, aiop); + } + + retval = rp_attachcommon(ctlp, num_aiops, num_ports); + if (retval != 0) + goto nogo; + + return (0); + +nogo: + rp_isareleaseresource(ctlp); + + return (retval); +} + +static void +rp_isareleaseresource(CONTROLLER_t *ctlp) +{ + int i; + + rp_releaseresource(ctlp); + + if (ctlp == rp_controller) + rp_controller = NULL; + if (ctlp->io != NULL) { + for (i = 0 ; i < MAX_AIOPS_PER_BOARD ; i++) + if (ctlp->io[i] != NULL) + bus_release_resource(ctlp->dev, SYS_RES_IOPORT, ctlp->io_rid[i], ctlp->io[i]); + free(ctlp->io, M_DEVBUF); + } + if (ctlp->io_rid != NULL) + free(ctlp->io_rid, M_DEVBUF); + if (rp_controller != NULL && rp_controller->io[ISACTL(ctlp)->MBaseIO] != NULL) { + bus_release_resource(rp_controller->dev, SYS_RES_IOPORT, rp_controller->io_rid[ISACTL(ctlp)->MBaseIO], rp_controller->io[ISACTL(ctlp)->MBaseIO]); + rp_controller->io[ISACTL(ctlp)->MBaseIO] = NULL; + rp_controller->io_rid[ISACTL(ctlp)->MBaseIO] = 0; + } + if (ctlp->bus_ctlp != NULL) + free(ctlp->bus_ctlp, M_DEVBUF); +} + +/*************************************************************************** +Function: sInitController +Purpose: Initialization of controller global registers and controller + structure. +Call: sInitController(CtlP,MudbacCtlP,AiopNum, + IRQNum,Frequency,PeriodicOnly) + CONTROLLER_T *CtlP; Ptr to controller structure + CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure + int AiopNum; Number of Aiops + int IRQNum; Interrupt Request number. Can be any of the following: + 0: Disable global interrupts + 3: IRQ 3 + 4: IRQ 4 + 5: IRQ 5 + 9: IRQ 9 + 10: IRQ 10 + 11: IRQ 11 + 12: IRQ 12 + 15: IRQ 15 + Byte_t Frequency: A flag identifying the frequency + of the periodic interrupt, can be any one of the following: + FREQ_DIS - periodic interrupt disabled + FREQ_137HZ - 137 Hertz + FREQ_69HZ - 69 Hertz + FREQ_34HZ - 34 Hertz + FREQ_17HZ - 17 Hertz + FREQ_9HZ - 9 Hertz + FREQ_4HZ - 4 Hertz + If IRQNum is set to 0 the Frequency parameter is + overidden, it is forced to a value of FREQ_DIS. + int PeriodicOnly: TRUE if all interrupts except the periodic + interrupt are to be blocked. + FALSE is both the periodic interrupt and + other channel interrupts are allowed. + If IRQNum is set to 0 the PeriodicOnly parameter is + overidden, it is forced to a value of FALSE. +Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller + initialization failed. + +Comments: + If periodic interrupts are to be disabled but AIOP interrupts + are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE. + + If interrupts are to be completely disabled set IRQNum to 0. + + Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an + invalid combination. + + This function performs initialization of global interrupt modes, + but it does not actually enable global interrupts. To enable + and disable global interrupts use functions sEnGlobalInt() and + sDisGlobalInt(). Enabling of global interrupts is normally not + done until all other initializations are complete. + + Even if interrupts are globally enabled, they must also be + individually enabled for each channel that is to generate + interrupts. + +Warnings: No range checking on any of the parameters is done. + + No context switches are allowed while executing this function. + + After this function all AIOPs on the controller are disabled, + they can be enabled with sEnAiop(). +*/ +static int +sInitController( CONTROLLER_T *CtlP, + CONTROLLER_T *MudbacCtlP, + int AiopNum, + int IRQNum, + Byte_t Frequency, + int PeriodicOnly) +{ + int i; + int ctl_base, aiop_base, aiop_size; + + CtlP->CtlID = CTLID_0001; /* controller release 1 */ + + ISACTL(CtlP)->MBaseIO = rp_nisadevs; + if (MudbacCtlP->io[ISACTL(CtlP)->MBaseIO] != NULL) { + ISACTL(CtlP)->MReg0IO = 0x40 + 0; + ISACTL(CtlP)->MReg1IO = 0x40 + 1; + ISACTL(CtlP)->MReg2IO = 0x40 + 2; + ISACTL(CtlP)->MReg3IO = 0x40 + 3; + } else { + MudbacCtlP->io_rid[ISACTL(CtlP)->MBaseIO] = ISACTL(CtlP)->MBaseIO; + ctl_base = rman_get_start(MudbacCtlP->io[0]) + 0x40 + 0x400 * rp_nisadevs; + MudbacCtlP->io[ISACTL(CtlP)->MBaseIO] = bus_alloc_resource(MudbacCtlP->dev, SYS_RES_IOPORT, &CtlP->io_rid[ISACTL(CtlP)->MBaseIO], ctl_base, ctl_base + 3, 4, RF_ACTIVE); + ISACTL(CtlP)->MReg0IO = 0; + ISACTL(CtlP)->MReg1IO = 1; + ISACTL(CtlP)->MReg2IO = 2; + ISACTL(CtlP)->MReg3IO = 3; + } +#if 1 + ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */ + ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */ +#else + if(sIRQMap[IRQNum] == 0) /* interrupts globally disabled */ + { + ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */ + ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */ + } + else + { + ISACTL(CtlP)->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */ + ISACTL(CtlP)->MReg3 = Frequency; /* set frequency */ + if(PeriodicOnly) /* periodic interrupt only */ + { + ISACTL(CtlP)->MReg3 |= PERIODIC_ONLY; + } + } +#endif + rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2); + rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); + sControllerEOI(MudbacCtlP,CtlP); /* clear EOI if warm init */ + + /* Init AIOPs */ + CtlP->NumAiop = 0; + for(i=0; i < AiopNum; i++) + { + if (CtlP->io[i] == NULL) { + CtlP->io_rid[i] = i; + aiop_base = rman_get_start(CtlP->io[0]) + 0x400 * i; + if (rp_nisadevs == 0) + aiop_size = 0x44; + else + aiop_size = 0x40; + CtlP->io[i] = bus_alloc_resource(CtlP->dev, SYS_RES_IOPORT, &CtlP->io_rid[i], aiop_base, aiop_base + aiop_size - 1, aiop_size, RF_ACTIVE); + } else + aiop_base = rman_get_start(CtlP->io[i]); + rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO, + ISACTL(CtlP)->MReg2IO, + ISACTL(CtlP)->MReg2 | (i & 0x03)); /* AIOP index */ + rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO, + ISACTL(CtlP)->MReg0IO, + (Byte_t)(aiop_base >> 6)); /* set up AIOP I/O in MUDBAC */ + sEnAiop(MudbacCtlP,CtlP,i); /* enable the AIOP */ + + CtlP->AiopID[i] = sReadAiopID(CtlP, i); /* read AIOP ID */ + if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ + { + sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */ + bus_release_resource(CtlP->dev, SYS_RES_IOPORT, CtlP->io_rid[i], CtlP->io[i]); + CtlP->io[i] = NULL; + break; /* done looking for AIOPs */ + } + + CtlP->AiopNumChan[i] = sReadAiopNumChan(CtlP, i); /* num channels in AIOP */ + rp_writeaiop2(CtlP,i,_INDX_ADDR,_CLK_PRE); /* clock prescaler */ + rp_writeaiop1(CtlP,i,_INDX_DATA,CLOCK_PRESC); + CtlP->NumAiop++; /* bump count of AIOPs */ + sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */ + } + + if(CtlP->NumAiop == 0) + return(-1); + else + return(CtlP->NumAiop); +} + +/* + * ARGSUSED + * Maps (aiop, offset) to rid. + */ +static int +rp_isa_aiop2rid(int aiop, int offset) +{ + /* rid equals to aiop for an ISA controller. */ + return aiop; +} + +/* + * ARGSUSED + * Maps (aiop, offset) to the offset of resource. + */ +static int +rp_isa_aiop2off(int aiop, int offset) +{ + /* Each aiop has its own resource. */ + return offset; +} + +/* Read the int status for an ISA controller. */ +unsigned char +rp_isa_ctlmask(CONTROLLER_t *ctlp) +{ + return sGetControllerIntStatus(rp_controller,ctlp); +} + +static device_method_t rp_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rp_probe), + DEVMETHOD(device_attach, rp_attach), + + { 0, 0 } +}; + +static driver_t rp_driver = { + "rp", + rp_methods, + sizeof(CONTROLLER_t), +}; + +/* + * rp can be attached to an isa bus. + */ +DRIVER_MODULE(rp, isa, rp_driver, rp_devclass, 0, 0); |