1997-08-14 14:01:36 +00:00
|
|
|
/*-
|
2017-11-27 14:52:40 +00:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
|
|
|
*
|
2002-03-23 15:36:13 +00:00
|
|
|
* Copyright (c) 1997-2000 Nicolas Souchu
|
2001-01-25 10:51:41 +00:00
|
|
|
* Copyright (c) 2001 Alcove - Nicolas Souchu
|
1997-08-14 14:01:36 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2003-06-11 00:34:37 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
#include "opt_ppc.h"
|
|
|
|
|
1997-08-14 14:01:36 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
2008-09-15 22:26:32 +00:00
|
|
|
#include <sys/bus.h>
|
1998-09-13 18:26:44 +00:00
|
|
|
#include <sys/kernel.h>
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
#include <sys/lock.h>
|
2008-09-15 22:26:32 +00:00
|
|
|
#include <sys/interrupt.h>
|
2004-05-30 20:08:47 +00:00
|
|
|
#include <sys/module.h>
|
2000-01-14 00:18:06 +00:00
|
|
|
#include <sys/malloc.h>
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
#include <sys/mutex.h>
|
2008-09-15 22:26:32 +00:00
|
|
|
#include <sys/proc.h>
|
2008-11-16 17:42:02 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
#include <machine/bus.h>
|
|
|
|
#include <machine/resource.h>
|
|
|
|
#include <sys/rman.h>
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2006-04-24 23:31:51 +00:00
|
|
|
#ifdef __i386__
|
|
|
|
#include <vm/vm.h>
|
|
|
|
#include <vm/pmap.h>
|
|
|
|
#include <machine/vmparam.h>
|
|
|
|
#endif
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
#include <dev/ppbus/ppbconf.h>
|
1998-08-03 19:14:33 +00:00
|
|
|
#include <dev/ppbus/ppb_msq.h>
|
|
|
|
|
2003-08-01 02:25:32 +00:00
|
|
|
#include <dev/ppc/ppcvar.h>
|
|
|
|
#include <dev/ppc/ppcreg.h>
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
#include "ppbus_if.h"
|
1999-01-10 12:04:56 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
static void ppcintr(void *arg);
|
|
|
|
|
2006-04-24 23:31:51 +00:00
|
|
|
#define IO_LPTSIZE_EXTENDED 8 /* "Extended" LPT controllers */
|
|
|
|
#define IO_LPTSIZE_NORMAL 4 /* "Normal" LPT controllers */
|
|
|
|
|
2003-08-01 02:25:32 +00:00
|
|
|
#define LOG_PPC(function, ppc, string) \
|
|
|
|
if (bootverbose) printf("%s: %s\n", function, string)
|
2000-01-14 00:18:06 +00:00
|
|
|
|
2003-08-01 02:25:32 +00:00
|
|
|
#define DEVTOSOFTC(dev) ((struct ppc_data *)device_get_softc(dev))
|
2000-01-14 00:18:06 +00:00
|
|
|
|
2013-02-21 00:27:51 +00:00
|
|
|
/*
|
2013-02-21 12:40:52 +00:00
|
|
|
* We use critical enter/exit for the simple config locking needed to
|
2013-02-21 00:27:51 +00:00
|
|
|
* detect the devices. We just want to make sure that both of our writes
|
|
|
|
* happen without someone else also writing to those config registers. Since
|
|
|
|
* we just do this at startup, Giant keeps multiple threads from executing,
|
|
|
|
* and critical_enter() then is all that's needed to keep us from being preempted
|
|
|
|
* during the critical sequences with the hardware.
|
|
|
|
*
|
|
|
|
* Note: this doesn't prevent multiple threads from putting the chips into
|
|
|
|
* config mode, but since we only do that to detect the type at startup the
|
|
|
|
* extra overhead isn't needed since Giant protects us from multiple entry
|
|
|
|
* and no other code changes these registers.
|
|
|
|
*/
|
|
|
|
#define PPC_CONFIG_LOCK(ppc) critical_enter()
|
2013-02-21 12:40:52 +00:00
|
|
|
#define PPC_CONFIG_UNLOCK(ppc) critical_exit()
|
2013-02-21 00:27:51 +00:00
|
|
|
|
2003-08-01 02:25:32 +00:00
|
|
|
devclass_t ppc_devclass;
|
2007-02-23 23:05:31 +00:00
|
|
|
const char ppc_driver_name[] = "ppc";
|
2003-08-01 02:25:32 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
static char *ppc_models[] = {
|
1998-08-03 19:14:33 +00:00
|
|
|
"SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306",
|
2000-07-18 09:01:09 +00:00
|
|
|
"82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334",
|
2000-07-20 09:28:07 +00:00
|
|
|
"SMC FDC37C935", "PC87303", 0
|
1998-08-03 19:14:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* list of available modes */
|
|
|
|
static char *ppc_avms[] = {
|
|
|
|
"COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only",
|
|
|
|
"EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only",
|
|
|
|
"ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP",
|
|
|
|
"ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0
|
1997-08-14 14:01:36 +00:00
|
|
|
};
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
/* list of current executing modes
|
|
|
|
* Note that few modes do not actually exist.
|
|
|
|
*/
|
1997-08-14 14:01:36 +00:00
|
|
|
static char *ppc_modes[] = {
|
1998-08-03 19:14:33 +00:00
|
|
|
"COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP",
|
|
|
|
"EPP", "EPP", "EPP", "ECP",
|
|
|
|
"ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP",
|
|
|
|
"ECP+EPP", "ECP+EPP", "ECP+EPP", 0
|
1997-08-14 14:01:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 };
|
|
|
|
|
2000-01-25 22:21:45 +00:00
|
|
|
#ifdef __i386__
|
1997-08-14 14:01:36 +00:00
|
|
|
/*
|
|
|
|
* BIOS printer list - used by BIOS probe.
|
|
|
|
*/
|
|
|
|
#define BIOS_PPC_PORTS 0x408
|
|
|
|
#define BIOS_PORTS (short *)(KERNBASE+BIOS_PPC_PORTS)
|
|
|
|
#define BIOS_MAX_PPC 4
|
2000-01-25 22:21:45 +00:00
|
|
|
#endif
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* ppc_ecp_sync() XXX
|
|
|
|
*/
|
2009-02-05 19:31:55 +00:00
|
|
|
int
|
2008-11-16 17:42:02 +00:00
|
|
|
ppc_ecp_sync(device_t dev)
|
|
|
|
{
|
1997-08-14 14:01:36 +00:00
|
|
|
int i, r;
|
2000-01-14 00:18:06 +00:00
|
|
|
struct ppc_data *ppc = DEVTOSOFTC(dev);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
PPC_ASSERT_LOCKED(ppc);
|
2001-01-25 10:51:41 +00:00
|
|
|
if (!(ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_dtm & PPB_ECP))
|
2009-02-05 19:31:55 +00:00
|
|
|
return 0;
|
1999-01-10 12:04:56 +00:00
|
|
|
|
1997-08-14 14:01:36 +00:00
|
|
|
r = r_ecr(ppc);
|
1999-01-10 12:04:56 +00:00
|
|
|
if ((r & 0xe0) != PPC_ECR_EPP)
|
2009-02-05 19:31:55 +00:00
|
|
|
return 0;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
for (i = 0; i < 100; i++) {
|
|
|
|
r = r_ecr(ppc);
|
|
|
|
if (r & 0x1)
|
2009-02-05 19:31:55 +00:00
|
|
|
return 0;
|
1997-08-14 14:01:36 +00:00
|
|
|
DELAY(100);
|
|
|
|
}
|
|
|
|
|
2008-10-21 18:30:10 +00:00
|
|
|
device_printf(dev, "ECP sync failed as data still present in FIFO.\n");
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2009-02-05 19:31:55 +00:00
|
|
|
return 0;
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
|
|
|
|
1999-01-10 12:04:56 +00:00
|
|
|
/*
|
|
|
|
* ppc_detect_fifo()
|
|
|
|
*
|
|
|
|
* Detect parallel port FIFO
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ppc_detect_fifo(struct ppc_data *ppc)
|
1997-08-14 14:01:36 +00:00
|
|
|
{
|
1999-01-10 12:04:56 +00:00
|
|
|
char ecr_sav;
|
|
|
|
char ctr_sav, ctr, cc;
|
|
|
|
short i;
|
2008-11-16 17:42:02 +00:00
|
|
|
|
1999-01-10 12:04:56 +00:00
|
|
|
/* save registers */
|
|
|
|
ecr_sav = r_ecr(ppc);
|
|
|
|
ctr_sav = r_ctr(ppc);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1999-01-10 12:04:56 +00:00
|
|
|
/* enter ECP configuration mode, no interrupt, no DMA */
|
|
|
|
w_ecr(ppc, 0xf4);
|
|
|
|
|
|
|
|
/* read PWord size - transfers in FIFO mode must be PWord aligned */
|
|
|
|
ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK);
|
|
|
|
|
|
|
|
/* XXX 16 and 32 bits implementations not supported */
|
|
|
|
if (ppc->ppc_pword != PPC_PWORD_8) {
|
2001-12-10 08:09:49 +00:00
|
|
|
LOG_PPC(__func__, ppc, "PWord not supported");
|
1999-01-10 12:04:56 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */
|
|
|
|
ctr = r_ctr(ppc);
|
|
|
|
w_ctr(ppc, ctr | PCD); /* set direction to 1 */
|
|
|
|
|
|
|
|
/* enter ECP test mode, no interrupt, no DMA */
|
|
|
|
w_ecr(ppc, 0xd4);
|
|
|
|
|
|
|
|
/* flush the FIFO */
|
|
|
|
for (i=0; i<1024; i++) {
|
|
|
|
if (r_ecr(ppc) & PPC_FIFO_EMPTY)
|
|
|
|
break;
|
|
|
|
cc = r_fifo(ppc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= 1024) {
|
2001-12-10 08:09:49 +00:00
|
|
|
LOG_PPC(__func__, ppc, "can't flush FIFO");
|
1999-01-10 12:04:56 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* enable interrupts, no DMA */
|
|
|
|
w_ecr(ppc, 0xd0);
|
|
|
|
|
|
|
|
/* determine readIntrThreshold
|
|
|
|
* fill the FIFO until serviceIntr is set
|
|
|
|
*/
|
|
|
|
for (i=0; i<1024; i++) {
|
|
|
|
w_fifo(ppc, (char)i);
|
|
|
|
if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) {
|
|
|
|
/* readThreshold reached */
|
|
|
|
ppc->ppc_rthr = i+1;
|
|
|
|
}
|
|
|
|
if (r_ecr(ppc) & PPC_FIFO_FULL) {
|
|
|
|
ppc->ppc_fifo = i+1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= 1024) {
|
2001-12-10 08:09:49 +00:00
|
|
|
LOG_PPC(__func__, ppc, "can't fill FIFO");
|
1999-01-10 12:04:56 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */
|
|
|
|
w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */
|
|
|
|
w_ecr(ppc, 0xd0); /* enable interrupts */
|
|
|
|
|
|
|
|
/* determine writeIntrThreshold
|
|
|
|
* empty the FIFO until serviceIntr is set
|
|
|
|
*/
|
|
|
|
for (i=ppc->ppc_fifo; i>0; i--) {
|
|
|
|
if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) {
|
2001-12-10 08:09:49 +00:00
|
|
|
LOG_PPC(__func__, ppc, "invalid data in FIFO");
|
1999-01-10 12:04:56 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (r_ecr(ppc) & PPC_SERVICE_INTR) {
|
|
|
|
/* writeIntrThreshold reached */
|
|
|
|
ppc->ppc_wthr = ppc->ppc_fifo - i+1;
|
|
|
|
}
|
|
|
|
/* if FIFO empty before the last byte, error */
|
|
|
|
if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) {
|
2001-12-10 08:09:49 +00:00
|
|
|
LOG_PPC(__func__, ppc, "data lost in FIFO");
|
1999-01-10 12:04:56 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIFO must be empty after the last byte */
|
|
|
|
if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {
|
2001-12-10 08:09:49 +00:00
|
|
|
LOG_PPC(__func__, ppc, "can't empty the FIFO");
|
1999-01-10 12:04:56 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2008-11-16 17:42:02 +00:00
|
|
|
|
1999-01-10 12:04:56 +00:00
|
|
|
w_ctr(ppc, ctr_sav);
|
|
|
|
w_ecr(ppc, ecr_sav);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
error:
|
|
|
|
w_ctr(ppc, ctr_sav);
|
|
|
|
w_ecr(ppc, ecr_sav);
|
|
|
|
|
|
|
|
return (EINVAL);
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
static int
|
|
|
|
ppc_detect_port(struct ppc_data *ppc)
|
|
|
|
{
|
|
|
|
|
|
|
|
w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */
|
|
|
|
w_dtr(ppc, 0xaa);
|
1999-01-10 16:41:14 +00:00
|
|
|
if (r_dtr(ppc) != 0xaa)
|
1998-08-03 19:14:33 +00:00
|
|
|
return (0);
|
|
|
|
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
/*
|
|
|
|
* EPP timeout, according to the PC87332 manual
|
|
|
|
* Semantics of clearing EPP timeout bit.
|
|
|
|
* PC87332 - reading SPP_STR does it...
|
|
|
|
* SMC - write 1 to EPP timeout bit XXX
|
|
|
|
* Others - (?) write 0 to EPP timeout bit
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ppc_reset_epp_timeout(struct ppc_data *ppc)
|
|
|
|
{
|
2017-05-17 00:34:34 +00:00
|
|
|
char r;
|
2000-01-14 00:18:06 +00:00
|
|
|
|
|
|
|
r = r_str(ppc);
|
|
|
|
w_str(ppc, r | 0x1);
|
|
|
|
w_str(ppc, r & 0xfe);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ppc_check_epp_timeout(struct ppc_data *ppc)
|
|
|
|
{
|
|
|
|
ppc_reset_epp_timeout(ppc);
|
|
|
|
|
|
|
|
return (!(r_str(ppc) & TIMEOUT));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configure current operating mode
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ppc_generic_setmode(struct ppc_data *ppc, int mode)
|
|
|
|
{
|
|
|
|
u_char ecr = 0;
|
|
|
|
|
|
|
|
/* check if mode is available */
|
|
|
|
if (mode && !(ppc->ppc_avm & mode))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
/* if ECP mode, configure ecr register */
|
2001-01-25 10:51:41 +00:00
|
|
|
if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) {
|
2000-01-14 00:18:06 +00:00
|
|
|
/* return to byte mode (keeping direction bit),
|
|
|
|
* no interrupt, no DMA to be able to change to
|
|
|
|
* ECP
|
|
|
|
*/
|
|
|
|
w_ecr(ppc, PPC_ECR_RESET);
|
|
|
|
ecr = PPC_DISABLE_INTR;
|
|
|
|
|
|
|
|
if (mode & PPB_EPP)
|
|
|
|
return (EINVAL);
|
|
|
|
else if (mode & PPB_ECP)
|
|
|
|
/* select ECP mode */
|
|
|
|
ecr |= PPC_ECR_ECP;
|
|
|
|
else if (mode & PPB_PS2)
|
|
|
|
/* select PS2 mode with ECP */
|
|
|
|
ecr |= PPC_ECR_PS2;
|
|
|
|
else
|
|
|
|
/* select COMPATIBLE/NIBBLE mode */
|
|
|
|
ecr |= PPC_ECR_STD;
|
|
|
|
|
|
|
|
w_ecr(ppc, ecr);
|
|
|
|
}
|
|
|
|
|
|
|
|
ppc->ppc_mode = mode;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The ppc driver is free to choose options like FIFO or DMA
|
|
|
|
* if ECP mode is available.
|
|
|
|
*
|
|
|
|
* The 'RAW' option allows the upper drivers to force the ppc mode
|
|
|
|
* even with FIFO, DMA available.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ppc_smclike_setmode(struct ppc_data *ppc, int mode)
|
|
|
|
{
|
|
|
|
u_char ecr = 0;
|
|
|
|
|
|
|
|
/* check if mode is available */
|
|
|
|
if (mode && !(ppc->ppc_avm & mode))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
/* if ECP mode, configure ecr register */
|
2001-01-25 10:51:41 +00:00
|
|
|
if ((ppc->ppc_avm & PPB_ECP) || (ppc->ppc_dtm & PPB_ECP)) {
|
2000-01-14 00:18:06 +00:00
|
|
|
/* return to byte mode (keeping direction bit),
|
|
|
|
* no interrupt, no DMA to be able to change to
|
|
|
|
* ECP or EPP mode
|
|
|
|
*/
|
|
|
|
w_ecr(ppc, PPC_ECR_RESET);
|
|
|
|
ecr = PPC_DISABLE_INTR;
|
|
|
|
|
|
|
|
if (mode & PPB_EPP)
|
|
|
|
/* select EPP mode */
|
|
|
|
ecr |= PPC_ECR_EPP;
|
|
|
|
else if (mode & PPB_ECP)
|
|
|
|
/* select ECP mode */
|
|
|
|
ecr |= PPC_ECR_ECP;
|
|
|
|
else if (mode & PPB_PS2)
|
|
|
|
/* select PS2 mode with ECP */
|
|
|
|
ecr |= PPC_ECR_PS2;
|
|
|
|
else
|
|
|
|
/* select COMPATIBLE/NIBBLE mode */
|
|
|
|
ecr |= PPC_ECR_STD;
|
|
|
|
|
|
|
|
w_ecr(ppc, ecr);
|
|
|
|
}
|
|
|
|
|
|
|
|
ppc->ppc_mode = mode;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef PPC_PROBE_CHIPSET
|
1997-08-14 14:01:36 +00:00
|
|
|
/*
|
|
|
|
* ppc_pc873xx_detect
|
|
|
|
*
|
|
|
|
* Probe for a Natsemi PC873xx-family part.
|
|
|
|
*
|
|
|
|
* References in this function are to the National Semiconductor
|
|
|
|
* PC87332 datasheet TL/C/11930, May 1995 revision.
|
|
|
|
*/
|
|
|
|
static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0};
|
|
|
|
static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0};
|
1998-10-31 11:37:09 +00:00
|
|
|
static int pc873xx_irqtab[] = {5, 7, 5, 0};
|
|
|
|
|
|
|
|
static int pc873xx_regstab[] = {
|
|
|
|
PC873_FER, PC873_FAR, PC873_PTR,
|
|
|
|
PC873_FCR, PC873_PCR, PC873_PMC,
|
|
|
|
PC873_TUP, PC873_SID, PC873_PNP0,
|
|
|
|
PC873_PNP1, PC873_LPTBA, -1
|
|
|
|
};
|
|
|
|
|
|
|
|
static char *pc873xx_rnametab[] = {
|
|
|
|
"FER", "FAR", "PTR", "FCR", "PCR",
|
|
|
|
"PMC", "TUP", "SID", "PNP0", "PNP1",
|
|
|
|
"LPTBA", NULL
|
|
|
|
};
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
static int
|
1998-08-03 19:14:33 +00:00
|
|
|
ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */
|
1997-08-14 14:01:36 +00:00
|
|
|
{
|
|
|
|
static int index = 0;
|
1998-12-07 21:58:50 +00:00
|
|
|
int idport, irq;
|
1998-10-31 11:37:09 +00:00
|
|
|
int ptr, pcr, val, i;
|
2008-11-16 17:42:02 +00:00
|
|
|
|
1997-08-14 14:01:36 +00:00
|
|
|
while ((idport = pc873xx_basetab[index++])) {
|
2008-11-16 17:42:02 +00:00
|
|
|
|
1997-08-14 14:01:36 +00:00
|
|
|
/* XXX should check first to see if this location is already claimed */
|
|
|
|
|
|
|
|
/*
|
1998-10-31 11:37:09 +00:00
|
|
|
* Pull the 873xx through the power-on ID cycle (2.2,1.).
|
|
|
|
* We can't use this to locate the chip as it may already have
|
|
|
|
* been used by the BIOS.
|
1997-08-14 14:01:36 +00:00
|
|
|
*/
|
1998-10-31 11:37:09 +00:00
|
|
|
(void)inb(idport); (void)inb(idport);
|
|
|
|
(void)inb(idport); (void)inb(idport);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the SID byte. Possible values are :
|
|
|
|
*
|
1998-10-31 11:37:09 +00:00
|
|
|
* 01010xxx PC87334
|
1997-08-14 14:01:36 +00:00
|
|
|
* 0001xxxx PC87332
|
|
|
|
* 01110xxx PC87306
|
2000-07-20 09:28:07 +00:00
|
|
|
* 00110xxx PC87303
|
1997-08-14 14:01:36 +00:00
|
|
|
*/
|
|
|
|
outb(idport, PC873_SID);
|
|
|
|
val = inb(idport + 1);
|
|
|
|
if ((val & 0xf0) == 0x10) {
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_model = NS_PC87332;
|
1997-08-14 14:01:36 +00:00
|
|
|
} else if ((val & 0xf8) == 0x70) {
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_model = NS_PC87306;
|
1998-10-31 11:37:09 +00:00
|
|
|
} else if ((val & 0xf8) == 0x50) {
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_model = NS_PC87334;
|
2000-07-20 09:28:07 +00:00
|
|
|
} else if ((val & 0xf8) == 0x40) { /* Should be 0x30 by the
|
|
|
|
documentation, but probing
|
|
|
|
yielded 0x40... */
|
|
|
|
ppc->ppc_model = NS_PC87303;
|
1997-08-14 14:01:36 +00:00
|
|
|
} else {
|
|
|
|
if (bootverbose && (val != 0xff))
|
|
|
|
printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val);
|
|
|
|
continue ; /* not recognised */
|
|
|
|
}
|
1998-10-31 11:37:09 +00:00
|
|
|
|
|
|
|
/* print registers */
|
|
|
|
if (bootverbose) {
|
|
|
|
printf("PC873xx");
|
|
|
|
for (i=0; pc873xx_regstab[i] != -1; i++) {
|
|
|
|
outb(idport, pc873xx_regstab[i]);
|
|
|
|
printf(" %s=0x%x", pc873xx_rnametab[i],
|
|
|
|
inb(idport + 1) & 0xff);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
2008-11-16 17:42:02 +00:00
|
|
|
|
1997-08-14 14:01:36 +00:00
|
|
|
/*
|
1998-10-31 11:37:09 +00:00
|
|
|
* We think we have one. Is it enabled and where we want it to be?
|
1997-08-14 14:01:36 +00:00
|
|
|
*/
|
|
|
|
outb(idport, PC873_FER);
|
|
|
|
val = inb(idport + 1);
|
|
|
|
if (!(val & PC873_PPENABLE)) {
|
|
|
|
if (bootverbose)
|
|
|
|
printf("PC873xx parallel port disabled\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
outb(idport, PC873_FAR);
|
2000-07-20 09:28:07 +00:00
|
|
|
val = inb(idport + 1);
|
1997-08-14 14:01:36 +00:00
|
|
|
/* XXX we should create a driver instance for every port found */
|
2000-07-20 09:28:07 +00:00
|
|
|
if (pc873xx_porttab[val & 0x3] != ppc->ppc_base) {
|
|
|
|
|
|
|
|
/* First try to change the port address to that requested... */
|
|
|
|
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
switch (ppc->ppc_base) {
|
2000-07-20 09:28:07 +00:00
|
|
|
case 0x378:
|
|
|
|
val &= 0xfc;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x3bc:
|
|
|
|
val &= 0xfd;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x278:
|
|
|
|
val &= 0xfe;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
val &= 0xfd;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
outb(idport, PC873_FAR);
|
|
|
|
outb(idport + 1, val);
|
|
|
|
outb(idport + 1, val);
|
|
|
|
|
|
|
|
/* Check for success by reading back the value we supposedly
|
|
|
|
wrote and comparing...*/
|
|
|
|
|
|
|
|
outb(idport, PC873_FAR);
|
|
|
|
val = inb(idport + 1) & 0x3;
|
|
|
|
|
|
|
|
/* If we fail, report the failure... */
|
|
|
|
|
|
|
|
if (pc873xx_porttab[val] != ppc->ppc_base) {
|
|
|
|
if (bootverbose)
|
|
|
|
printf("PC873xx at 0x%x not for driver at port 0x%x\n",
|
|
|
|
pc873xx_porttab[val], ppc->ppc_base);
|
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
continue;
|
|
|
|
}
|
1998-10-31 11:37:09 +00:00
|
|
|
|
|
|
|
outb(idport, PC873_PTR);
|
2008-11-16 17:42:02 +00:00
|
|
|
ptr = inb(idport + 1);
|
1998-10-31 11:37:09 +00:00
|
|
|
|
|
|
|
/* get irq settings */
|
|
|
|
if (ppc->ppc_base == 0x378)
|
|
|
|
irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5;
|
|
|
|
else
|
|
|
|
irq = pc873xx_irqtab[val];
|
|
|
|
|
|
|
|
if (bootverbose)
|
|
|
|
printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base);
|
2008-11-16 17:42:02 +00:00
|
|
|
|
1998-10-31 11:37:09 +00:00
|
|
|
/*
|
|
|
|
* Check if irq settings are correct
|
1997-08-14 14:01:36 +00:00
|
|
|
*/
|
1998-10-31 11:37:09 +00:00
|
|
|
if (irq != ppc->ppc_irq) {
|
|
|
|
/*
|
|
|
|
* If the chipset is not locked and base address is 0x378,
|
|
|
|
* we have another chance
|
|
|
|
*/
|
|
|
|
if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) {
|
|
|
|
if (ppc->ppc_irq == 7) {
|
|
|
|
outb(idport + 1, (ptr | PC873_LPTBIRQ7));
|
|
|
|
outb(idport + 1, (ptr | PC873_LPTBIRQ7));
|
|
|
|
} else {
|
|
|
|
outb(idport + 1, (ptr & ~PC873_LPTBIRQ7));
|
|
|
|
outb(idport + 1, (ptr & ~PC873_LPTBIRQ7));
|
|
|
|
}
|
|
|
|
if (bootverbose)
|
|
|
|
printf("PC873xx irq set to %d\n", ppc->ppc_irq);
|
|
|
|
} else {
|
|
|
|
if (bootverbose)
|
|
|
|
printf("PC873xx sorry, can't change irq setting\n");
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (bootverbose)
|
1998-10-31 11:37:09 +00:00
|
|
|
printf("PC873xx irq settings are correct\n");
|
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-10-31 11:37:09 +00:00
|
|
|
outb(idport, PC873_PCR);
|
|
|
|
pcr = inb(idport + 1);
|
2008-11-16 17:42:02 +00:00
|
|
|
|
1998-10-31 11:37:09 +00:00
|
|
|
if ((ptr & PC873_CFGLOCK) || !chipset_mode) {
|
1997-08-14 14:01:36 +00:00
|
|
|
if (bootverbose)
|
1998-10-31 11:37:09 +00:00
|
|
|
printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked");
|
|
|
|
|
|
|
|
ppc->ppc_avm |= PPB_NIBBLE;
|
|
|
|
if (bootverbose)
|
|
|
|
printf(", NIBBLE");
|
|
|
|
|
|
|
|
if (pcr & PC873_EPPEN) {
|
2008-11-16 17:42:02 +00:00
|
|
|
ppc->ppc_avm |= PPB_EPP;
|
1998-10-31 11:37:09 +00:00
|
|
|
|
1997-08-14 14:01:36 +00:00
|
|
|
if (bootverbose)
|
1998-10-31 11:37:09 +00:00
|
|
|
printf(", EPP");
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-10-31 11:37:09 +00:00
|
|
|
if (pcr & PC873_EPP19)
|
|
|
|
ppc->ppc_epp = EPP_1_9;
|
|
|
|
else
|
|
|
|
ppc->ppc_epp = EPP_1_7;
|
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
if ((ppc->ppc_model == NS_PC87332) && bootverbose) {
|
1998-10-31 11:37:09 +00:00
|
|
|
outb(idport, PC873_PTR);
|
|
|
|
ptr = inb(idport + 1);
|
|
|
|
if (ptr & PC873_EPPRDIR)
|
|
|
|
printf(", Regular mode");
|
|
|
|
else
|
|
|
|
printf(", Automatic mode");
|
|
|
|
}
|
|
|
|
} else if (pcr & PC873_ECPEN) {
|
|
|
|
ppc->ppc_avm |= PPB_ECP;
|
1997-08-14 14:01:36 +00:00
|
|
|
if (bootverbose)
|
1998-10-31 11:37:09 +00:00
|
|
|
printf(", ECP");
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-10-31 11:37:09 +00:00
|
|
|
if (pcr & PC873_ECPCLK) { /* XXX */
|
|
|
|
ppc->ppc_avm |= PPB_PS2;
|
|
|
|
if (bootverbose)
|
|
|
|
printf(", PS/2");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
outb(idport, PC873_PTR);
|
|
|
|
ptr = inb(idport + 1);
|
|
|
|
if (ptr & PC873_EXTENDED) {
|
|
|
|
ppc->ppc_avm |= PPB_SPP;
|
2008-11-16 17:42:02 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(", SPP");
|
1998-10-31 11:37:09 +00:00
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
1998-10-31 11:37:09 +00:00
|
|
|
} else {
|
|
|
|
if (bootverbose)
|
|
|
|
printf("PC873xx unlocked");
|
|
|
|
|
|
|
|
if (chipset_mode & PPB_ECP) {
|
|
|
|
if ((chipset_mode & PPB_EPP) && bootverbose)
|
|
|
|
printf(", ECP+EPP not supported");
|
|
|
|
|
|
|
|
pcr &= ~PC873_EPPEN;
|
|
|
|
pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */
|
|
|
|
outb(idport + 1, pcr);
|
|
|
|
outb(idport + 1, pcr);
|
|
|
|
|
|
|
|
if (bootverbose)
|
|
|
|
printf(", ECP");
|
|
|
|
|
|
|
|
} else if (chipset_mode & PPB_EPP) {
|
|
|
|
pcr &= ~(PC873_ECPEN | PC873_ECPCLK);
|
|
|
|
pcr |= (PC873_EPPEN | PC873_EPP19);
|
|
|
|
outb(idport + 1, pcr);
|
|
|
|
outb(idport + 1, pcr);
|
|
|
|
|
|
|
|
ppc->ppc_epp = EPP_1_9; /* XXX */
|
|
|
|
|
|
|
|
if (bootverbose)
|
|
|
|
printf(", EPP1.9");
|
|
|
|
|
|
|
|
/* enable automatic direction turnover */
|
2000-01-14 00:18:06 +00:00
|
|
|
if (ppc->ppc_model == NS_PC87332) {
|
1998-10-31 11:37:09 +00:00
|
|
|
outb(idport, PC873_PTR);
|
|
|
|
ptr = inb(idport + 1);
|
|
|
|
ptr &= ~PC873_EPPRDIR;
|
|
|
|
outb(idport + 1, ptr);
|
|
|
|
outb(idport + 1, ptr);
|
|
|
|
|
|
|
|
if (bootverbose)
|
|
|
|
printf(", Automatic mode");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN);
|
|
|
|
outb(idport + 1, pcr);
|
|
|
|
outb(idport + 1, pcr);
|
|
|
|
|
|
|
|
/* configure extended bit in PTR */
|
|
|
|
outb(idport, PC873_PTR);
|
|
|
|
ptr = inb(idport + 1);
|
|
|
|
|
|
|
|
if (chipset_mode & PPB_PS2) {
|
|
|
|
ptr |= PC873_EXTENDED;
|
|
|
|
|
|
|
|
if (bootverbose)
|
|
|
|
printf(", PS/2");
|
2008-11-16 17:42:02 +00:00
|
|
|
|
1998-10-31 11:37:09 +00:00
|
|
|
} else {
|
|
|
|
/* default to NIBBLE mode */
|
|
|
|
ptr &= ~PC873_EXTENDED;
|
|
|
|
|
|
|
|
if (bootverbose)
|
|
|
|
printf(", NIBBLE");
|
|
|
|
}
|
|
|
|
outb(idport + 1, ptr);
|
|
|
|
outb(idport + 1, ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
ppc->ppc_avm = chipset_mode;
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
1998-08-03 19:14:33 +00:00
|
|
|
|
1998-10-31 11:37:09 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf("\n");
|
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_type = PPC_TYPE_GENERIC;
|
|
|
|
ppc_generic_setmode(ppc, chipset_mode);
|
1998-10-31 11:37:09 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
return(chipset_mode);
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
1998-08-03 19:14:33 +00:00
|
|
|
return(-1);
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ppc_smc37c66xgt_detect
|
|
|
|
*
|
|
|
|
* SMC FDC37C66xGT configuration.
|
|
|
|
*/
|
|
|
|
static int
|
1998-08-03 19:14:33 +00:00
|
|
|
ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode)
|
1997-08-14 14:01:36 +00:00
|
|
|
{
|
2013-02-21 00:27:51 +00:00
|
|
|
int i;
|
1999-01-31 11:52:04 +00:00
|
|
|
u_char r;
|
1997-08-14 14:01:36 +00:00
|
|
|
int type = -1;
|
|
|
|
int csr = SMC66x_CSR; /* initial value is 0x3F0 */
|
|
|
|
|
|
|
|
int port_address[] = { -1 /* disabled */ , 0x3bc, 0x378, 0x278 };
|
|
|
|
|
|
|
|
|
|
|
|
#define cio csr+1 /* config IO port is either 0x3F1 or 0x371 */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Detection: enter configuration mode and read CRD register.
|
|
|
|
*/
|
2013-02-21 00:27:51 +00:00
|
|
|
PPC_CONFIG_LOCK(ppc);
|
1997-08-14 14:01:36 +00:00
|
|
|
outb(csr, SMC665_iCODE);
|
|
|
|
outb(csr, SMC665_iCODE);
|
2013-02-21 00:27:51 +00:00
|
|
|
PPC_CONFIG_UNLOCK(ppc);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
outb(csr, 0xd);
|
|
|
|
if (inb(cio) == 0x65) {
|
|
|
|
type = SMC_37C665GT;
|
|
|
|
goto config;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
2013-02-21 00:27:51 +00:00
|
|
|
PPC_CONFIG_LOCK(ppc);
|
1997-08-14 14:01:36 +00:00
|
|
|
outb(csr, SMC666_iCODE);
|
|
|
|
outb(csr, SMC666_iCODE);
|
2013-02-21 00:27:51 +00:00
|
|
|
PPC_CONFIG_UNLOCK(ppc);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
outb(csr, 0xd);
|
|
|
|
if (inb(cio) == 0x66) {
|
|
|
|
type = SMC_37C666GT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Another chance, CSR may be hard-configured to be at 0x370 */
|
|
|
|
csr = SMC666_CSR;
|
|
|
|
}
|
|
|
|
|
|
|
|
config:
|
|
|
|
/*
|
|
|
|
* If chipset not found, do not continue.
|
|
|
|
*/
|
2013-02-21 00:27:51 +00:00
|
|
|
if (type == -1) {
|
|
|
|
outb(csr, 0xaa); /* end config mode */
|
1998-08-03 19:14:33 +00:00
|
|
|
return (-1);
|
2013-02-21 00:27:51 +00:00
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
/* select CR1 */
|
|
|
|
outb(csr, 0x1);
|
|
|
|
|
|
|
|
/* read the port's address: bits 0 and 1 of CR1 */
|
|
|
|
r = inb(cio) & SMC_CR1_ADDR;
|
2013-02-21 00:27:51 +00:00
|
|
|
if (port_address[(int)r] != ppc->ppc_base) {
|
|
|
|
outb(csr, 0xaa); /* end config mode */
|
1998-08-03 19:14:33 +00:00
|
|
|
return (-1);
|
2013-02-21 00:27:51 +00:00
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_model = type;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* CR1 and CR4 registers bits 3 and 0/1 for mode configuration
|
1998-08-03 19:14:33 +00:00
|
|
|
* If SPP mode is detected, try to set ECP+EPP mode
|
1997-08-14 14:01:36 +00:00
|
|
|
*/
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
if (bootverbose) {
|
|
|
|
outb(csr, 0x1);
|
2008-10-22 19:39:16 +00:00
|
|
|
device_printf(ppc->ppc_dev, "SMC registers CR1=0x%x",
|
|
|
|
inb(cio) & 0xff);
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
outb(csr, 0x4);
|
|
|
|
printf(" CR4=0x%x", inb(cio) & 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* select CR1 */
|
1997-08-14 14:01:36 +00:00
|
|
|
outb(csr, 0x1);
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
if (!chipset_mode) {
|
1997-08-14 14:01:36 +00:00
|
|
|
/* autodetect mode */
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
/* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
|
|
|
|
if (type == SMC_37C666GT) {
|
|
|
|
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" configuration hardwired, supposing " \
|
|
|
|
"ECP+EPP SPP");
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
} else
|
|
|
|
if ((inb(cio) & SMC_CR1_MODE) == 0) {
|
1997-08-14 14:01:36 +00:00
|
|
|
/* already in extended parallel port mode, read CR4 */
|
|
|
|
outb(csr, 0x4);
|
|
|
|
r = (inb(cio) & SMC_CR4_EMODE);
|
|
|
|
|
|
|
|
switch (r) {
|
|
|
|
case SMC_SPP:
|
1998-08-03 19:14:33 +00:00
|
|
|
ppc->ppc_avm |= PPB_SPP;
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" SPP");
|
1997-08-14 14:01:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SMC_EPPSPP:
|
1998-08-03 19:14:33 +00:00
|
|
|
ppc->ppc_avm |= PPB_EPP | PPB_SPP;
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" EPP SPP");
|
1997-08-14 14:01:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SMC_ECP:
|
1998-08-03 19:14:33 +00:00
|
|
|
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" ECP SPP");
|
1997-08-14 14:01:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SMC_ECPEPP:
|
1998-08-03 19:14:33 +00:00
|
|
|
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" ECP+EPP SPP");
|
1997-08-14 14:01:36 +00:00
|
|
|
break;
|
|
|
|
}
|
1998-08-03 19:14:33 +00:00
|
|
|
} else {
|
|
|
|
/* not an extended port mode */
|
|
|
|
ppc->ppc_avm |= PPB_SPP;
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" SPP");
|
1998-08-03 19:14:33 +00:00
|
|
|
}
|
|
|
|
|
1997-08-14 14:01:36 +00:00
|
|
|
} else {
|
|
|
|
/* mode forced */
|
1998-09-13 18:26:44 +00:00
|
|
|
ppc->ppc_avm = chipset_mode;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
/* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
|
1997-08-14 14:01:36 +00:00
|
|
|
if (type == SMC_37C666GT)
|
|
|
|
goto end_detect;
|
|
|
|
|
|
|
|
r = inb(cio);
|
1998-08-03 19:14:33 +00:00
|
|
|
if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) {
|
|
|
|
/* do not use ECP when the mode is not forced to */
|
1997-08-14 14:01:36 +00:00
|
|
|
outb(cio, r | SMC_CR1_MODE);
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" SPP");
|
1997-08-14 14:01:36 +00:00
|
|
|
} else {
|
|
|
|
/* an extended mode is selected */
|
|
|
|
outb(cio, r & ~SMC_CR1_MODE);
|
|
|
|
|
|
|
|
/* read CR4 register and reset mode field */
|
|
|
|
outb(csr, 0x4);
|
|
|
|
r = inb(cio) & ~SMC_CR4_EMODE;
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
if (chipset_mode & PPB_ECP) {
|
|
|
|
if (chipset_mode & PPB_EPP) {
|
|
|
|
outb(cio, r | SMC_ECPEPP);
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" ECP+EPP");
|
1998-08-03 19:14:33 +00:00
|
|
|
} else {
|
|
|
|
outb(cio, r | SMC_ECP);
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" ECP");
|
1998-08-03 19:14:33 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* PPB_EPP is set */
|
1997-08-14 14:01:36 +00:00
|
|
|
outb(cio, r | SMC_EPPSPP);
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" EPP SPP");
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
|
|
|
}
|
1998-08-03 19:14:33 +00:00
|
|
|
ppc->ppc_avm = chipset_mode;
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
|
|
|
|
1999-01-10 12:04:56 +00:00
|
|
|
/* set FIFO threshold to 16 */
|
|
|
|
if (ppc->ppc_avm & PPB_ECP) {
|
|
|
|
/* select CRA */
|
|
|
|
outb(csr, 0xa);
|
|
|
|
outb(cio, 16);
|
|
|
|
}
|
|
|
|
|
1997-08-14 14:01:36 +00:00
|
|
|
end_detect:
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
if (bootverbose)
|
|
|
|
printf ("\n");
|
|
|
|
|
1998-09-13 18:26:44 +00:00
|
|
|
if (ppc->ppc_avm & PPB_EPP) {
|
1997-08-14 14:01:36 +00:00
|
|
|
/* select CR4 */
|
|
|
|
outb(csr, 0x4);
|
|
|
|
r = inb(cio);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the EPP protocol...
|
|
|
|
* Low=EPP 1.9 (1284 standard) and High=EPP 1.7
|
|
|
|
*/
|
|
|
|
if (ppc->ppc_epp == EPP_1_9)
|
|
|
|
outb(cio, (r & ~SMC_CR4_EPPTYPE));
|
|
|
|
else
|
|
|
|
outb(cio, (r | SMC_CR4_EPPTYPE));
|
|
|
|
}
|
|
|
|
|
2013-02-21 00:27:51 +00:00
|
|
|
outb(csr, 0xaa); /* end config mode */
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_type = PPC_TYPE_SMCLIKE;
|
|
|
|
ppc_smclike_setmode(ppc, chipset_mode);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
return (chipset_mode);
|
|
|
|
}
|
|
|
|
|
2000-07-18 09:01:09 +00:00
|
|
|
/*
|
|
|
|
* SMC FDC37C935 configuration
|
|
|
|
* Found on many Alpha machines
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ppc_smc37c935_detect(struct ppc_data *ppc, int chipset_mode)
|
|
|
|
{
|
|
|
|
int type = -1;
|
|
|
|
|
2013-02-21 00:27:51 +00:00
|
|
|
PPC_CONFIG_LOCK(ppc);
|
2000-07-18 09:01:09 +00:00
|
|
|
outb(SMC935_CFG, 0x55); /* enter config mode */
|
|
|
|
outb(SMC935_CFG, 0x55);
|
2013-02-21 00:27:51 +00:00
|
|
|
PPC_CONFIG_UNLOCK(ppc);
|
2000-07-18 09:01:09 +00:00
|
|
|
|
|
|
|
outb(SMC935_IND, SMC935_ID); /* check device id */
|
|
|
|
if (inb(SMC935_DAT) == 0x2)
|
|
|
|
type = SMC_37C935;
|
|
|
|
|
|
|
|
if (type == -1) {
|
|
|
|
outb(SMC935_CFG, 0xaa); /* exit config mode */
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
ppc->ppc_model = type;
|
|
|
|
|
|
|
|
outb(SMC935_IND, SMC935_LOGDEV); /* select parallel port, */
|
2008-11-16 17:42:02 +00:00
|
|
|
outb(SMC935_DAT, 3); /* which is logical device 3 */
|
2000-07-18 09:01:09 +00:00
|
|
|
|
|
|
|
/* set io port base */
|
|
|
|
outb(SMC935_IND, SMC935_PORTHI);
|
|
|
|
outb(SMC935_DAT, (u_char)((ppc->ppc_base & 0xff00) >> 8));
|
|
|
|
outb(SMC935_IND, SMC935_PORTLO);
|
|
|
|
outb(SMC935_DAT, (u_char)(ppc->ppc_base & 0xff));
|
|
|
|
|
|
|
|
if (!chipset_mode)
|
|
|
|
ppc->ppc_avm = PPB_COMPATIBLE; /* default mode */
|
|
|
|
else {
|
|
|
|
ppc->ppc_avm = chipset_mode;
|
|
|
|
outb(SMC935_IND, SMC935_PPMODE);
|
|
|
|
outb(SMC935_DAT, SMC935_CENT); /* start in compatible mode */
|
|
|
|
|
|
|
|
/* SPP + EPP or just plain SPP */
|
|
|
|
if (chipset_mode & (PPB_SPP)) {
|
|
|
|
if (chipset_mode & PPB_EPP) {
|
|
|
|
if (ppc->ppc_epp == EPP_1_9) {
|
|
|
|
outb(SMC935_IND, SMC935_PPMODE);
|
|
|
|
outb(SMC935_DAT, SMC935_EPP19SPP);
|
|
|
|
}
|
|
|
|
if (ppc->ppc_epp == EPP_1_7) {
|
|
|
|
outb(SMC935_IND, SMC935_PPMODE);
|
|
|
|
outb(SMC935_DAT, SMC935_EPP17SPP);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
outb(SMC935_IND, SMC935_PPMODE);
|
|
|
|
outb(SMC935_DAT, SMC935_SPP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ECP + EPP or just plain ECP */
|
|
|
|
if (chipset_mode & PPB_ECP) {
|
|
|
|
if (chipset_mode & PPB_EPP) {
|
|
|
|
if (ppc->ppc_epp == EPP_1_9) {
|
|
|
|
outb(SMC935_IND, SMC935_PPMODE);
|
|
|
|
outb(SMC935_DAT, SMC935_ECPEPP19);
|
|
|
|
}
|
|
|
|
if (ppc->ppc_epp == EPP_1_7) {
|
|
|
|
outb(SMC935_IND, SMC935_PPMODE);
|
|
|
|
outb(SMC935_DAT, SMC935_ECPEPP17);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
outb(SMC935_IND, SMC935_PPMODE);
|
|
|
|
outb(SMC935_DAT, SMC935_ECP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
outb(SMC935_CFG, 0xaa); /* exit config mode */
|
|
|
|
|
|
|
|
ppc->ppc_type = PPC_TYPE_SMCLIKE;
|
|
|
|
ppc_smclike_setmode(ppc, chipset_mode);
|
|
|
|
|
|
|
|
return (chipset_mode);
|
|
|
|
}
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
/*
|
|
|
|
* Winbond W83877F stuff
|
|
|
|
*
|
|
|
|
* EFER: extended function enable register
|
|
|
|
* EFIR: extended function index register
|
|
|
|
* EFDR: extended function data register
|
|
|
|
*/
|
|
|
|
#define efir ((efer == 0x250) ? 0x251 : 0x3f0)
|
|
|
|
#define efdr ((efer == 0x250) ? 0x252 : 0x3f1)
|
|
|
|
|
|
|
|
static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 };
|
2008-11-16 17:42:02 +00:00
|
|
|
static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 };
|
1998-08-03 19:14:33 +00:00
|
|
|
static int w83877f_keyiter[] = { 1, 2, 2, 1 };
|
|
|
|
static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 };
|
|
|
|
|
|
|
|
static int
|
|
|
|
ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode)
|
|
|
|
{
|
1998-12-07 21:58:50 +00:00
|
|
|
int i, j, efer;
|
1998-08-03 19:14:33 +00:00
|
|
|
unsigned char r, hefere, hefras;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i ++) {
|
|
|
|
/* first try to enable configuration registers */
|
|
|
|
efer = w83877f_efers[i];
|
|
|
|
|
|
|
|
/* write the key to the EFER */
|
|
|
|
for (j = 0; j < w83877f_keyiter[i]; j ++)
|
|
|
|
outb (efer, w83877f_keys[i]);
|
|
|
|
|
|
|
|
/* then check HEFERE and HEFRAS bits */
|
|
|
|
outb (efir, 0x0c);
|
|
|
|
hefere = inb(efdr) & WINB_HEFERE;
|
|
|
|
|
|
|
|
outb (efir, 0x16);
|
|
|
|
hefras = inb(efdr) & WINB_HEFRAS;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
/*
|
1998-08-03 19:14:33 +00:00
|
|
|
* HEFRAS HEFERE
|
|
|
|
* 0 1 write 89h to 250h (power-on default)
|
|
|
|
* 1 0 write 86h twice to 3f0h
|
|
|
|
* 1 1 write 87h twice to 3f0h
|
|
|
|
* 0 0 write 88h to 250h
|
1997-08-14 14:01:36 +00:00
|
|
|
*/
|
1998-08-03 19:14:33 +00:00
|
|
|
if ((hefere | hefras) == w83877f_hefs[i])
|
|
|
|
goto found;
|
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
return (-1); /* failed */
|
|
|
|
|
|
|
|
found:
|
|
|
|
/* check base port address - read from CR23 */
|
|
|
|
outb(efir, 0x23);
|
|
|
|
if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */
|
|
|
|
return (-1);
|
|
|
|
|
|
|
|
/* read CHIP ID from CR9/bits0-3 */
|
|
|
|
outb(efir, 0x9);
|
|
|
|
|
|
|
|
switch (inb(efdr) & WINB_CHIPID) {
|
|
|
|
case WINB_W83877F_ID:
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_model = WINB_W83877F;
|
1998-08-03 19:14:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case WINB_W83877AF_ID:
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_model = WINB_W83877AF;
|
1998-08-03 19:14:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_model = WINB_UNKNOWN;
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
if (bootverbose) {
|
|
|
|
/* dump of registers */
|
2008-10-22 19:39:16 +00:00
|
|
|
device_printf(ppc->ppc_dev, "0x%x - ", w83877f_keys[i]);
|
1998-08-03 19:14:33 +00:00
|
|
|
for (i = 0; i <= 0xd; i ++) {
|
|
|
|
outb(efir, i);
|
|
|
|
printf("0x%x ", inb(efdr));
|
|
|
|
}
|
|
|
|
for (i = 0x10; i <= 0x17; i ++) {
|
|
|
|
outb(efir, i);
|
|
|
|
printf("0x%x ", inb(efdr));
|
|
|
|
}
|
|
|
|
outb(efir, 0x1e);
|
|
|
|
printf("0x%x ", inb(efdr));
|
|
|
|
for (i = 0x20; i <= 0x29; i ++) {
|
|
|
|
outb(efir, i);
|
|
|
|
printf("0x%x ", inb(efdr));
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_type = PPC_TYPE_GENERIC;
|
1998-09-02 20:34:34 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
if (!chipset_mode) {
|
|
|
|
/* autodetect mode */
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
/* select CR0 */
|
|
|
|
outb(efir, 0x0);
|
|
|
|
r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1);
|
|
|
|
|
|
|
|
/* select CR9 */
|
|
|
|
outb(efir, 0x9);
|
|
|
|
r |= (inb(efdr) & WINB_PRTMODS2);
|
|
|
|
|
|
|
|
switch (r) {
|
|
|
|
case WINB_W83757:
|
|
|
|
if (bootverbose)
|
2008-10-22 19:39:16 +00:00
|
|
|
device_printf(ppc->ppc_dev,
|
|
|
|
"W83757 compatible mode\n");
|
1998-08-03 19:14:33 +00:00
|
|
|
return (-1); /* generic or SMC-like */
|
|
|
|
|
|
|
|
case WINB_EXTFDC:
|
|
|
|
case WINB_EXTADP:
|
|
|
|
case WINB_EXT2FDD:
|
|
|
|
case WINB_JOYSTICK:
|
|
|
|
if (bootverbose)
|
2008-10-22 19:39:16 +00:00
|
|
|
device_printf(ppc->ppc_dev,
|
2008-10-21 18:30:10 +00:00
|
|
|
"not in parallel port mode\n");
|
1998-08-03 19:14:33 +00:00
|
|
|
return (-1);
|
|
|
|
|
|
|
|
case (WINB_PARALLEL | WINB_EPP_SPP):
|
|
|
|
ppc->ppc_avm |= PPB_EPP | PPB_SPP;
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
2008-10-22 19:39:16 +00:00
|
|
|
device_printf(ppc->ppc_dev, "EPP SPP\n");
|
1998-08-03 19:14:33 +00:00
|
|
|
break;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
case (WINB_PARALLEL | WINB_ECP):
|
|
|
|
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
2008-10-22 19:39:16 +00:00
|
|
|
device_printf(ppc->ppc_dev, "ECP SPP\n");
|
1998-08-03 19:14:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case (WINB_PARALLEL | WINB_ECP_EPP):
|
|
|
|
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_type = PPC_TYPE_SMCLIKE;
|
1998-09-02 20:34:34 +00:00
|
|
|
|
|
|
|
if (bootverbose)
|
2008-10-22 19:39:16 +00:00
|
|
|
device_printf(ppc->ppc_dev, "ECP+EPP SPP\n");
|
1998-08-03 19:14:33 +00:00
|
|
|
break;
|
|
|
|
default:
|
2001-12-10 08:09:49 +00:00
|
|
|
printf("%s: unknown case (0x%x)!\n", __func__, r);
|
1998-08-03 19:14:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* mode forced */
|
|
|
|
|
|
|
|
/* select CR9 and set PRTMODS2 bit */
|
|
|
|
outb(efir, 0x9);
|
|
|
|
outb(efdr, inb(efdr) & ~WINB_PRTMODS2);
|
|
|
|
|
|
|
|
/* select CR0 and reset PRTMODSx bits */
|
|
|
|
outb(efir, 0x0);
|
|
|
|
outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1));
|
|
|
|
|
|
|
|
if (chipset_mode & PPB_ECP) {
|
1998-09-02 20:34:34 +00:00
|
|
|
if (chipset_mode & PPB_EPP) {
|
1998-08-03 19:14:33 +00:00
|
|
|
outb(efdr, inb(efdr) | WINB_ECP_EPP);
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
2008-10-22 19:39:16 +00:00
|
|
|
device_printf(ppc->ppc_dev,
|
|
|
|
"ECP+EPP\n");
|
1998-09-02 20:34:34 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_type = PPC_TYPE_SMCLIKE;
|
1998-09-02 20:34:34 +00:00
|
|
|
|
|
|
|
} else {
|
1998-08-03 19:14:33 +00:00
|
|
|
outb(efdr, inb(efdr) | WINB_ECP);
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
2008-10-22 19:39:16 +00:00
|
|
|
device_printf(ppc->ppc_dev, "ECP\n");
|
1998-09-02 20:34:34 +00:00
|
|
|
}
|
1998-08-03 19:14:33 +00:00
|
|
|
} else {
|
|
|
|
/* select EPP_SPP otherwise */
|
|
|
|
outb(efdr, inb(efdr) | WINB_EPP_SPP);
|
1998-09-02 20:34:34 +00:00
|
|
|
if (bootverbose)
|
2008-10-22 19:39:16 +00:00
|
|
|
device_printf(ppc->ppc_dev, "EPP SPP\n");
|
1998-08-03 19:14:33 +00:00
|
|
|
}
|
|
|
|
ppc->ppc_avm = chipset_mode;
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
1998-09-02 20:34:34 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
/* exit configuration mode */
|
|
|
|
outb(efer, 0xaa);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
switch (ppc->ppc_type) {
|
|
|
|
case PPC_TYPE_SMCLIKE:
|
|
|
|
ppc_smclike_setmode(ppc, chipset_mode);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ppc_generic_setmode(ppc, chipset_mode);
|
|
|
|
break;
|
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
return (chipset_mode);
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
2000-01-14 00:18:06 +00:00
|
|
|
#endif
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* ppc_generic_detect
|
|
|
|
*/
|
|
|
|
static int
|
1998-08-03 19:14:33 +00:00
|
|
|
ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
|
1997-08-14 14:01:36 +00:00
|
|
|
{
|
1998-09-02 20:34:34 +00:00
|
|
|
/* default to generic */
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_type = PPC_TYPE_GENERIC;
|
1998-09-02 20:34:34 +00:00
|
|
|
|
|
|
|
if (bootverbose)
|
2008-10-21 18:30:10 +00:00
|
|
|
device_printf(ppc->ppc_dev, "SPP");
|
1998-09-02 20:34:34 +00:00
|
|
|
|
2001-01-25 10:51:41 +00:00
|
|
|
/* first, check for ECP */
|
|
|
|
w_ecr(ppc, PPC_ECR_PS2);
|
|
|
|
if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) {
|
|
|
|
ppc->ppc_dtm |= PPB_ECP | PPB_SPP;
|
|
|
|
if (bootverbose)
|
2008-10-21 18:30:10 +00:00
|
|
|
printf(" ECP ");
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2001-01-25 10:51:41 +00:00
|
|
|
/* search for SMC style ECP+EPP mode */
|
|
|
|
w_ecr(ppc, PPC_ECR_EPP);
|
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2001-01-25 10:51:41 +00:00
|
|
|
/* try to reset EPP timeout bit */
|
|
|
|
if (ppc_check_epp_timeout(ppc)) {
|
|
|
|
ppc->ppc_dtm |= PPB_EPP;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2001-01-25 10:51:41 +00:00
|
|
|
if (ppc->ppc_dtm & PPB_ECP) {
|
|
|
|
/* SMC like chipset found */
|
|
|
|
ppc->ppc_model = SMC_LIKE;
|
|
|
|
ppc->ppc_type = PPC_TYPE_SMCLIKE;
|
1998-09-02 20:34:34 +00:00
|
|
|
|
2001-01-25 10:51:41 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" ECP+EPP");
|
1998-09-02 20:34:34 +00:00
|
|
|
} else {
|
2001-01-25 10:51:41 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf(" EPP");
|
1998-08-03 19:14:33 +00:00
|
|
|
}
|
2001-01-25 10:51:41 +00:00
|
|
|
} else {
|
|
|
|
/* restore to standard mode */
|
|
|
|
w_ecr(ppc, PPC_ECR_STD);
|
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2001-01-25 10:51:41 +00:00
|
|
|
/* XXX try to detect NIBBLE and PS2 modes */
|
|
|
|
ppc->ppc_dtm |= PPB_NIBBLE;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2001-01-25 10:51:41 +00:00
|
|
|
if (chipset_mode)
|
1998-08-03 19:14:33 +00:00
|
|
|
ppc->ppc_avm = chipset_mode;
|
2001-01-25 10:51:41 +00:00
|
|
|
else
|
|
|
|
ppc->ppc_avm = ppc->ppc_dtm;
|
1998-09-02 20:34:34 +00:00
|
|
|
|
|
|
|
if (bootverbose)
|
|
|
|
printf("\n");
|
1998-08-03 19:14:33 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
switch (ppc->ppc_type) {
|
|
|
|
case PPC_TYPE_SMCLIKE:
|
|
|
|
ppc_smclike_setmode(ppc, chipset_mode);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ppc_generic_setmode(ppc, chipset_mode);
|
|
|
|
break;
|
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
return (chipset_mode);
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ppc_detect()
|
|
|
|
*
|
|
|
|
* mode is the mode suggested at boot
|
|
|
|
*/
|
|
|
|
static int
|
1998-08-03 19:14:33 +00:00
|
|
|
ppc_detect(struct ppc_data *ppc, int chipset_mode) {
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
#ifdef PPC_PROBE_CHIPSET
|
1998-08-03 19:14:33 +00:00
|
|
|
int i, mode;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
/* list of supported chipsets */
|
|
|
|
int (*chipset_detect[])(struct ppc_data *, int) = {
|
|
|
|
ppc_pc873xx_detect,
|
|
|
|
ppc_smc37c66xgt_detect,
|
|
|
|
ppc_w83877f_detect,
|
2000-07-18 09:01:09 +00:00
|
|
|
ppc_smc37c935_detect,
|
1998-08-03 19:14:33 +00:00
|
|
|
ppc_generic_detect,
|
|
|
|
NULL
|
|
|
|
};
|
2000-01-14 00:18:06 +00:00
|
|
|
#endif
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
/* if can't find the port and mode not forced return error */
|
|
|
|
if (!ppc_detect_port(ppc) && chipset_mode == 0)
|
|
|
|
return (EIO); /* failed, port not present */
|
1997-08-14 14:01:36 +00:00
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
/* assume centronics compatible mode is supported */
|
|
|
|
ppc->ppc_avm = PPB_COMPATIBLE;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
#ifdef PPC_PROBE_CHIPSET
|
1998-08-03 19:14:33 +00:00
|
|
|
/* we have to differenciate available chipset modes,
|
|
|
|
* chipset running modes and IEEE-1284 operating modes
|
|
|
|
*
|
|
|
|
* after detection, the port must support running in compatible mode
|
|
|
|
*/
|
1998-10-31 11:37:09 +00:00
|
|
|
if (ppc->ppc_flags & 0x40) {
|
|
|
|
if (bootverbose)
|
|
|
|
printf("ppc: chipset forced to generic\n");
|
2000-01-14 00:18:06 +00:00
|
|
|
#endif
|
1998-10-31 11:37:09 +00:00
|
|
|
|
|
|
|
ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode);
|
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
#ifdef PPC_PROBE_CHIPSET
|
1998-10-31 11:37:09 +00:00
|
|
|
} else {
|
|
|
|
for (i=0; chipset_detect[i] != NULL; i++) {
|
|
|
|
if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) {
|
|
|
|
ppc->ppc_mode = mode;
|
|
|
|
break;
|
|
|
|
}
|
1998-08-03 19:14:33 +00:00
|
|
|
}
|
|
|
|
}
|
2000-01-14 00:18:06 +00:00
|
|
|
#endif
|
1998-08-03 19:14:33 +00:00
|
|
|
|
1999-01-10 12:04:56 +00:00
|
|
|
/* configure/detect ECP FIFO */
|
|
|
|
if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80))
|
|
|
|
ppc_detect_fifo(ppc);
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ppc_exec_microseq()
|
|
|
|
*
|
|
|
|
* Execute a microsequence.
|
|
|
|
* Microsequence mechanism is supposed to handle fast I/O operations.
|
|
|
|
*/
|
2003-08-01 02:25:32 +00:00
|
|
|
int
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq)
|
1998-08-03 19:14:33 +00:00
|
|
|
{
|
2000-01-14 00:18:06 +00:00
|
|
|
struct ppc_data *ppc = DEVTOSOFTC(dev);
|
1998-09-20 14:47:01 +00:00
|
|
|
struct ppb_microseq *mi;
|
1998-08-03 19:14:33 +00:00
|
|
|
char cc, *p;
|
1998-09-13 18:26:44 +00:00
|
|
|
int i, iter, len;
|
1998-08-03 19:14:33 +00:00
|
|
|
int error;
|
|
|
|
|
2017-05-17 00:34:34 +00:00
|
|
|
int reg;
|
|
|
|
char mask;
|
|
|
|
int accum = 0;
|
|
|
|
char *ptr = NULL;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
2017-02-20 03:43:12 +00:00
|
|
|
struct ppb_microseq *stack = NULL;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
/* microsequence registers are equivalent to PC-like port registers */
|
2001-06-23 06:52:54 +00:00
|
|
|
|
2008-08-22 18:43:19 +00:00
|
|
|
#define r_reg(reg,ppc) (bus_read_1((ppc)->res_ioport, reg))
|
|
|
|
#define w_reg(reg, ppc, byte) (bus_write_1((ppc)->res_ioport, reg, byte))
|
1998-08-03 19:14:33 +00:00
|
|
|
|
1998-09-20 14:47:01 +00:00
|
|
|
#define INCR_PC (mi ++) /* increment program counter */
|
1998-08-03 19:14:33 +00:00
|
|
|
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
PPC_ASSERT_LOCKED(ppc);
|
1998-09-20 14:47:01 +00:00
|
|
|
mi = *p_msq;
|
1998-08-03 19:14:33 +00:00
|
|
|
for (;;) {
|
2008-11-16 17:42:02 +00:00
|
|
|
switch (mi->opcode) {
|
1998-08-03 19:14:33 +00:00
|
|
|
case MS_OP_RSET:
|
|
|
|
cc = r_reg(mi->arg[0].i, ppc);
|
1998-09-13 18:26:44 +00:00
|
|
|
cc &= (char)mi->arg[2].i; /* clear mask */
|
|
|
|
cc |= (char)mi->arg[1].i; /* assert mask */
|
2008-11-16 17:42:02 +00:00
|
|
|
w_reg(mi->arg[0].i, ppc, cc);
|
1998-08-03 19:14:33 +00:00
|
|
|
INCR_PC;
|
2008-11-16 17:42:02 +00:00
|
|
|
break;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
case MS_OP_RASSERT_P:
|
1998-09-13 18:26:44 +00:00
|
|
|
reg = mi->arg[1].i;
|
|
|
|
ptr = ppc->ppc_ptr;
|
|
|
|
|
|
|
|
if ((len = mi->arg[0].i) == MS_ACCUM) {
|
|
|
|
accum = ppc->ppc_accum;
|
|
|
|
for (; accum; accum--)
|
|
|
|
w_reg(reg, ppc, *ptr++);
|
|
|
|
ppc->ppc_accum = accum;
|
|
|
|
} else
|
|
|
|
for (i=0; i<len; i++)
|
|
|
|
w_reg(reg, ppc, *ptr++);
|
|
|
|
ppc->ppc_ptr = ptr;
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
INCR_PC;
|
|
|
|
break;
|
|
|
|
|
2008-11-16 17:42:02 +00:00
|
|
|
case MS_OP_RFETCH_P:
|
1998-09-13 18:26:44 +00:00
|
|
|
reg = mi->arg[1].i;
|
|
|
|
mask = (char)mi->arg[2].i;
|
|
|
|
ptr = ppc->ppc_ptr;
|
|
|
|
|
|
|
|
if ((len = mi->arg[0].i) == MS_ACCUM) {
|
|
|
|
accum = ppc->ppc_accum;
|
|
|
|
for (; accum; accum--)
|
|
|
|
*ptr++ = r_reg(reg, ppc) & mask;
|
|
|
|
ppc->ppc_accum = accum;
|
|
|
|
} else
|
|
|
|
for (i=0; i<len; i++)
|
|
|
|
*ptr++ = r_reg(reg, ppc) & mask;
|
|
|
|
ppc->ppc_ptr = ptr;
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
INCR_PC;
|
2008-11-16 17:42:02 +00:00
|
|
|
break;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
2008-11-16 17:42:02 +00:00
|
|
|
case MS_OP_RFETCH:
|
1998-08-03 19:14:33 +00:00
|
|
|
*((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) &
|
1998-09-13 18:26:44 +00:00
|
|
|
(char)mi->arg[1].i;
|
1998-08-03 19:14:33 +00:00
|
|
|
INCR_PC;
|
2008-11-16 17:42:02 +00:00
|
|
|
break;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
case MS_OP_RASSERT:
|
2008-11-16 17:42:02 +00:00
|
|
|
case MS_OP_DELAY:
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
/* let's suppose the next instr. is the same */
|
|
|
|
prefetch:
|
|
|
|
for (;mi->opcode == MS_OP_RASSERT; INCR_PC)
|
1998-09-13 18:26:44 +00:00
|
|
|
w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i);
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
if (mi->opcode == MS_OP_DELAY) {
|
|
|
|
DELAY(mi->arg[0].i);
|
|
|
|
INCR_PC;
|
|
|
|
goto prefetch;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
1998-09-13 18:26:44 +00:00
|
|
|
case MS_OP_ADELAY:
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
if (mi->arg[0].i) {
|
|
|
|
PPC_UNLOCK(ppc);
|
2007-02-23 16:25:08 +00:00
|
|
|
pause("ppbdelay", mi->arg[0].i * (hz/1000));
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
PPC_LOCK(ppc);
|
|
|
|
}
|
1998-08-03 19:14:33 +00:00
|
|
|
INCR_PC;
|
1998-09-13 18:26:44 +00:00
|
|
|
break;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
case MS_OP_TRIG:
|
|
|
|
reg = mi->arg[0].i;
|
|
|
|
iter = mi->arg[1].i;
|
|
|
|
p = (char *)mi->arg[2].p;
|
|
|
|
|
1998-09-13 18:26:44 +00:00
|
|
|
/* XXX delay limited to 255 us */
|
1998-08-03 19:14:33 +00:00
|
|
|
for (i=0; i<iter; i++) {
|
|
|
|
w_reg(reg, ppc, *p++);
|
|
|
|
DELAY((unsigned char)*p++);
|
|
|
|
}
|
|
|
|
INCR_PC;
|
|
|
|
break;
|
|
|
|
|
2008-11-16 17:42:02 +00:00
|
|
|
case MS_OP_SET:
|
|
|
|
ppc->ppc_accum = mi->arg[0].i;
|
1998-08-03 19:14:33 +00:00
|
|
|
INCR_PC;
|
2008-11-16 17:42:02 +00:00
|
|
|
break;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
2008-11-16 17:42:02 +00:00
|
|
|
case MS_OP_DBRA:
|
|
|
|
if (--ppc->ppc_accum > 0)
|
|
|
|
mi += mi->arg[0].i;
|
1999-01-30 15:35:39 +00:00
|
|
|
INCR_PC;
|
2008-11-16 17:42:02 +00:00
|
|
|
break;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
2008-11-16 17:42:02 +00:00
|
|
|
case MS_OP_BRSET:
|
|
|
|
cc = r_str(ppc);
|
|
|
|
if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i)
|
|
|
|
mi += mi->arg[1].i;
|
1999-01-30 15:35:39 +00:00
|
|
|
INCR_PC;
|
2008-11-16 17:42:02 +00:00
|
|
|
break;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
2008-11-16 17:42:02 +00:00
|
|
|
case MS_OP_BRCLEAR:
|
|
|
|
cc = r_str(ppc);
|
|
|
|
if ((cc & (char)mi->arg[0].i) == 0)
|
|
|
|
mi += mi->arg[1].i;
|
1999-01-30 15:35:39 +00:00
|
|
|
INCR_PC;
|
2008-11-16 17:42:02 +00:00
|
|
|
break;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
1998-09-13 18:26:44 +00:00
|
|
|
case MS_OP_BRSTAT:
|
|
|
|
cc = r_str(ppc);
|
|
|
|
if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) ==
|
|
|
|
(char)mi->arg[0].i)
|
1998-09-20 14:47:01 +00:00
|
|
|
mi += mi->arg[2].i;
|
1999-01-30 15:35:39 +00:00
|
|
|
INCR_PC;
|
1998-09-13 18:26:44 +00:00
|
|
|
break;
|
|
|
|
|
1998-08-03 19:14:33 +00:00
|
|
|
case MS_OP_C_CALL:
|
|
|
|
/*
|
|
|
|
* If the C call returns !0 then end the microseq.
|
|
|
|
* The current state of ptr is passed to the C function
|
|
|
|
*/
|
1998-09-13 18:26:44 +00:00
|
|
|
if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr)))
|
1998-08-03 19:14:33 +00:00
|
|
|
return (error);
|
|
|
|
|
|
|
|
INCR_PC;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MS_OP_PTR:
|
1998-09-13 18:26:44 +00:00
|
|
|
ppc->ppc_ptr = (char *)mi->arg[0].p;
|
1998-08-03 19:14:33 +00:00
|
|
|
INCR_PC;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MS_OP_CALL:
|
1998-09-20 14:47:01 +00:00
|
|
|
if (stack)
|
2001-12-10 08:09:49 +00:00
|
|
|
panic("%s: too much calls", __func__);
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
if (mi->arg[0].p) {
|
|
|
|
/* store the state of the actual
|
|
|
|
* microsequence
|
|
|
|
*/
|
1998-09-20 14:47:01 +00:00
|
|
|
stack = mi;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
/* jump to the new microsequence */
|
1998-09-20 14:47:01 +00:00
|
|
|
mi = (struct ppb_microseq *)mi->arg[0].p;
|
1998-08-03 19:14:33 +00:00
|
|
|
} else
|
|
|
|
INCR_PC;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MS_OP_SUBRET:
|
|
|
|
/* retrieve microseq and pc state before the call */
|
1998-09-20 14:47:01 +00:00
|
|
|
mi = stack;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
/* reset the stack */
|
2017-02-20 03:43:12 +00:00
|
|
|
stack = NULL;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
/* XXX return code */
|
|
|
|
|
|
|
|
INCR_PC;
|
|
|
|
break;
|
|
|
|
|
2008-11-16 17:42:02 +00:00
|
|
|
case MS_OP_PUT:
|
|
|
|
case MS_OP_GET:
|
|
|
|
case MS_OP_RET:
|
1998-08-03 19:14:33 +00:00
|
|
|
/* can't return to ppb level during the execution
|
|
|
|
* of a submicrosequence */
|
1998-09-20 14:47:01 +00:00
|
|
|
if (stack)
|
1998-08-03 19:14:33 +00:00
|
|
|
panic("%s: can't return to ppb level",
|
2001-12-10 08:09:49 +00:00
|
|
|
__func__);
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
/* update pc for ppb level of execution */
|
1998-09-20 14:47:01 +00:00
|
|
|
*p_msq = mi;
|
1998-08-03 19:14:33 +00:00
|
|
|
|
|
|
|
/* return to ppb level of execution */
|
|
|
|
return (0);
|
|
|
|
|
2008-11-16 17:42:02 +00:00
|
|
|
default:
|
|
|
|
panic("%s: unknown microsequence opcode 0x%x",
|
|
|
|
__func__, mi->opcode);
|
|
|
|
}
|
1998-08-03 19:14:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* unreached */
|
|
|
|
}
|
|
|
|
|
1999-01-10 12:04:56 +00:00
|
|
|
static void
|
2000-01-14 00:18:06 +00:00
|
|
|
ppcintr(void *arg)
|
1999-01-10 12:04:56 +00:00
|
|
|
{
|
2008-09-15 22:26:32 +00:00
|
|
|
struct ppc_data *ppc = arg;
|
1999-02-14 12:03:35 +00:00
|
|
|
u_char ctr, ecr, str;
|
1999-01-10 12:04:56 +00:00
|
|
|
|
2008-09-15 22:26:32 +00:00
|
|
|
/*
|
|
|
|
* If we have any child interrupt handlers registered, let
|
|
|
|
* them handle this interrupt.
|
|
|
|
*
|
|
|
|
* XXX: If DMA is in progress should we just complete that w/o
|
|
|
|
* doing this?
|
|
|
|
*/
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
PPC_LOCK(ppc);
|
|
|
|
if (ppc->ppc_intr_hook != NULL &&
|
|
|
|
ppc->ppc_intr_hook(ppc->ppc_intr_arg) == 0) {
|
|
|
|
PPC_UNLOCK(ppc);
|
2008-09-15 22:26:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-02-14 12:03:35 +00:00
|
|
|
str = r_str(ppc);
|
1999-01-10 12:04:56 +00:00
|
|
|
ctr = r_ctr(ppc);
|
|
|
|
ecr = r_ecr(ppc);
|
|
|
|
|
2005-12-04 02:12:43 +00:00
|
|
|
#if defined(PPC_DEBUG) && PPC_DEBUG > 1
|
1999-02-14 12:03:35 +00:00
|
|
|
printf("![%x/%x/%x]", ctr, ecr, str);
|
1999-01-10 12:04:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* don't use ecp mode with IRQENABLE set */
|
|
|
|
if (ctr & IRQENABLE) {
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
PPC_UNLOCK(ppc);
|
1999-01-10 12:04:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-02-14 12:03:35 +00:00
|
|
|
/* interrupts are generated by nFault signal
|
|
|
|
* only in ECP mode */
|
|
|
|
if ((str & nFAULT) && (ppc->ppc_mode & PPB_ECP)) {
|
|
|
|
/* check if ppc driver has programmed the
|
|
|
|
* nFault interrupt */
|
1999-01-10 12:04:56 +00:00
|
|
|
if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) {
|
|
|
|
|
|
|
|
w_ecr(ppc, ecr | PPC_nFAULT_INTR);
|
|
|
|
ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT;
|
|
|
|
} else {
|
2000-01-14 00:18:06 +00:00
|
|
|
/* shall be handled by underlying layers XXX */
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
PPC_UNLOCK(ppc);
|
1999-01-10 12:04:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppc->ppc_irqstat & PPC_IRQ_DMA) {
|
|
|
|
/* disable interrupts (should be done by hardware though) */
|
|
|
|
w_ecr(ppc, ecr | PPC_SERVICE_INTR);
|
|
|
|
ppc->ppc_irqstat &= ~PPC_IRQ_DMA;
|
|
|
|
ecr = r_ecr(ppc);
|
|
|
|
|
|
|
|
/* check if DMA completed */
|
|
|
|
if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) {
|
|
|
|
#ifdef PPC_DEBUG
|
|
|
|
printf("a");
|
|
|
|
#endif
|
|
|
|
/* stop DMA */
|
|
|
|
w_ecr(ppc, ecr & ~PPC_ENABLE_DMA);
|
|
|
|
ecr = r_ecr(ppc);
|
|
|
|
|
|
|
|
if (ppc->ppc_dmastat == PPC_DMA_STARTED) {
|
|
|
|
#ifdef PPC_DEBUG
|
|
|
|
printf("d");
|
|
|
|
#endif
|
2006-04-24 23:31:51 +00:00
|
|
|
ppc->ppc_dmadone(ppc);
|
1999-01-10 12:04:56 +00:00
|
|
|
ppc->ppc_dmastat = PPC_DMA_COMPLETE;
|
|
|
|
|
|
|
|
/* wakeup the waiting process */
|
2003-03-02 16:54:40 +00:00
|
|
|
wakeup(ppc);
|
1999-01-10 12:04:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) {
|
|
|
|
|
|
|
|
/* classic interrupt I/O */
|
|
|
|
ppc->ppc_irqstat &= ~PPC_IRQ_FIFO;
|
|
|
|
}
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
PPC_UNLOCK(ppc);
|
1999-01-10 12:04:56 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-08-01 02:25:32 +00:00
|
|
|
int
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc_read(device_t dev, char *buf, int len, int mode)
|
1999-01-10 12:04:56 +00:00
|
|
|
{
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
2003-08-01 02:25:32 +00:00
|
|
|
int
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc_write(device_t dev, char *buf, int len, int how)
|
1999-01-10 12:04:56 +00:00
|
|
|
{
|
2006-04-24 23:31:51 +00:00
|
|
|
return (EINVAL);
|
1999-01-10 12:04:56 +00:00
|
|
|
}
|
|
|
|
|
2009-02-05 19:31:55 +00:00
|
|
|
int
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc_reset_epp(device_t dev)
|
1998-08-03 19:14:33 +00:00
|
|
|
{
|
2000-01-14 00:18:06 +00:00
|
|
|
struct ppc_data *ppc = DEVTOSOFTC(dev);
|
2008-11-16 17:42:02 +00:00
|
|
|
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
PPC_ASSERT_LOCKED(ppc);
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc_reset_epp_timeout(ppc);
|
1998-08-03 19:14:33 +00:00
|
|
|
|
2009-02-05 19:31:55 +00:00
|
|
|
return 0;
|
2000-01-14 00:18:06 +00:00
|
|
|
}
|
1998-08-03 19:14:33 +00:00
|
|
|
|
2003-08-01 02:25:32 +00:00
|
|
|
int
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc_setmode(device_t dev, int mode)
|
|
|
|
{
|
|
|
|
struct ppc_data *ppc = DEVTOSOFTC(dev);
|
1998-09-02 20:34:34 +00:00
|
|
|
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
PPC_ASSERT_LOCKED(ppc);
|
2000-01-14 00:18:06 +00:00
|
|
|
switch (ppc->ppc_type) {
|
|
|
|
case PPC_TYPE_SMCLIKE:
|
|
|
|
return (ppc_smclike_setmode(ppc, mode));
|
|
|
|
break;
|
1999-01-10 12:04:56 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
case PPC_TYPE_GENERIC:
|
|
|
|
default:
|
|
|
|
return (ppc_generic_setmode(ppc, mode));
|
|
|
|
break;
|
1998-09-02 20:34:34 +00:00
|
|
|
}
|
1998-08-03 19:14:33 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
/* not reached */
|
|
|
|
return (ENXIO);
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
|
|
|
|
2003-08-01 02:25:32 +00:00
|
|
|
int
|
2006-04-24 23:31:51 +00:00
|
|
|
ppc_probe(device_t dev, int rid)
|
2003-08-01 02:25:32 +00:00
|
|
|
{
|
|
|
|
#ifdef __i386__
|
|
|
|
static short next_bios_ppc = 0;
|
|
|
|
#endif
|
|
|
|
struct ppc_data *ppc;
|
|
|
|
int error;
|
2016-01-27 02:23:54 +00:00
|
|
|
rman_res_t port;
|
2003-08-01 02:25:32 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
/*
|
|
|
|
* Allocate the ppc_data structure.
|
|
|
|
*/
|
|
|
|
ppc = DEVTOSOFTC(dev);
|
|
|
|
bzero(ppc, sizeof(struct ppc_data));
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2006-04-24 23:31:51 +00:00
|
|
|
ppc->rid_ioport = rid;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
/* retrieve ISA parameters */
|
2006-04-24 23:31:51 +00:00
|
|
|
error = bus_get_resource(dev, SYS_RES_IOPORT, rid, &port, NULL);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-25 22:21:45 +00:00
|
|
|
#ifdef __i386__
|
1997-08-14 14:01:36 +00:00
|
|
|
/*
|
|
|
|
* If port not specified, use bios list.
|
|
|
|
*/
|
2000-01-25 22:21:45 +00:00
|
|
|
if (error) {
|
2008-11-16 17:42:02 +00:00
|
|
|
if ((next_bios_ppc < BIOS_MAX_PPC) &&
|
|
|
|
(*(BIOS_PORTS + next_bios_ppc) != 0)) {
|
|
|
|
port = *(BIOS_PORTS + next_bios_ppc++);
|
1999-01-10 12:04:56 +00:00
|
|
|
if (bootverbose)
|
2008-11-16 17:42:02 +00:00
|
|
|
device_printf(dev,
|
Use uintmax_t (typedef'd to rman_res_t type) for rman ranges.
On some architectures, u_long isn't large enough for resource definitions.
Particularly, powerpc and arm allow 36-bit (or larger) physical addresses, but
type `long' is only 32-bit. This extends rman's resources to uintmax_t. With
this change, any resource can feasibly be placed anywhere in physical memory
(within the constraints of the driver).
Why uintmax_t and not something machine dependent, or uint64_t? Though it's
possible for uintmax_t to grow, it's highly unlikely it will become 128-bit on
32-bit architectures. 64-bit architectures should have plenty of RAM to absorb
the increase on resource sizes if and when this occurs, and the number of
resources on memory-constrained systems should be sufficiently small as to not
pose a drastic overhead. That being said, uintmax_t was chosen for source
clarity. If it's specified as uint64_t, all printf()-like calls would either
need casts to uintmax_t, or be littered with PRI*64 macros. Casts to uintmax_t
aren't horrible, but it would also bake into the API for
resource_list_print_type() either a hidden assumption that entries get cast to
uintmax_t for printing, or these calls would need the PRI*64 macros. Since
source code is meant to be read more often than written, I chose the clearest
path of simply using uintmax_t.
Tested on a PowerPC p5020-based board, which places all device resources in
0xfxxxxxxxx, and has 8GB RAM.
Regression tested on qemu-system-i386
Regression tested on qemu-system-mips (malta profile)
Tested PAE and devinfo on virtualbox (live CD)
Special thanks to bz for his testing on ARM.
Reviewed By: bz, jhb (previous)
Relnotes: Yes
Sponsored by: Alex Perez/Inertial Computing
Differential Revision: https://reviews.freebsd.org/D4544
2016-03-18 01:28:41 +00:00
|
|
|
"parallel port found at 0x%jx\n", port);
|
2000-01-14 00:18:06 +00:00
|
|
|
} else {
|
|
|
|
device_printf(dev, "parallel port not found.\n");
|
2008-11-16 17:42:02 +00:00
|
|
|
return (ENXIO);
|
2000-01-14 00:18:06 +00:00
|
|
|
}
|
2006-04-24 23:31:51 +00:00
|
|
|
bus_set_resource(dev, SYS_RES_IOPORT, rid, port,
|
2000-07-18 09:01:09 +00:00
|
|
|
IO_LPTSIZE_EXTENDED);
|
2000-01-25 22:21:45 +00:00
|
|
|
}
|
|
|
|
#endif
|
2000-01-14 00:18:06 +00:00
|
|
|
|
|
|
|
/* IO port is mandatory */
|
2000-07-18 09:01:09 +00:00
|
|
|
|
|
|
|
/* Try "extended" IO port range...*/
|
2016-02-27 03:38:01 +00:00
|
|
|
ppc->res_ioport = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT,
|
|
|
|
&ppc->rid_ioport,
|
|
|
|
IO_LPTSIZE_EXTENDED,
|
|
|
|
RF_ACTIVE);
|
2000-05-14 13:47:57 +00:00
|
|
|
|
2000-07-18 09:01:09 +00:00
|
|
|
if (ppc->res_ioport != 0) {
|
2000-06-25 09:20:56 +00:00
|
|
|
if (bootverbose)
|
2000-07-18 09:01:09 +00:00
|
|
|
device_printf(dev, "using extended I/O port range\n");
|
|
|
|
} else {
|
|
|
|
/* Failed? If so, then try the "normal" IO port range... */
|
2016-02-27 03:38:01 +00:00
|
|
|
ppc->res_ioport = bus_alloc_resource_anywhere(dev,
|
|
|
|
SYS_RES_IOPORT,
|
|
|
|
&ppc->rid_ioport,
|
|
|
|
IO_LPTSIZE_NORMAL,
|
|
|
|
RF_ACTIVE);
|
2000-07-18 09:01:09 +00:00
|
|
|
if (ppc->res_ioport != 0) {
|
|
|
|
if (bootverbose)
|
|
|
|
device_printf(dev, "using normal I/O port range\n");
|
|
|
|
} else {
|
2017-09-18 18:42:28 +00:00
|
|
|
if (bootverbose)
|
|
|
|
device_printf(dev, "cannot reserve I/O port range\n");
|
2000-07-18 09:01:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2000-06-25 09:20:56 +00:00
|
|
|
}
|
2000-05-14 13:47:57 +00:00
|
|
|
|
|
|
|
ppc->ppc_base = rman_get_start(ppc->res_ioport);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_flags = device_get_flags(dev);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
if (!(ppc->ppc_flags & 0x20)) {
|
2004-03-17 17:50:55 +00:00
|
|
|
ppc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
|
|
|
|
&ppc->rid_irq,
|
|
|
|
RF_SHAREABLE);
|
|
|
|
ppc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ,
|
|
|
|
&ppc->rid_drq,
|
|
|
|
RF_ACTIVE);
|
2000-01-14 00:18:06 +00:00
|
|
|
}
|
1998-10-31 11:37:09 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
if (ppc->res_irq)
|
2000-01-25 22:21:45 +00:00
|
|
|
ppc->ppc_irq = rman_get_start(ppc->res_irq);
|
2000-01-14 00:18:06 +00:00
|
|
|
if (ppc->res_drq)
|
2000-01-25 22:21:45 +00:00
|
|
|
ppc->ppc_dmachan = rman_get_start(ppc->res_drq);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2008-10-21 18:30:10 +00:00
|
|
|
ppc->ppc_dev = dev;
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_model = GENERIC;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_mode = PPB_COMPATIBLE;
|
|
|
|
ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4;
|
1999-01-10 12:04:56 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc->ppc_type = PPC_TYPE_GENERIC;
|
1998-09-02 20:34:34 +00:00
|
|
|
|
1997-08-14 14:01:36 +00:00
|
|
|
/*
|
1998-04-17 22:37:19 +00:00
|
|
|
* Try to detect the chipset and its mode.
|
1997-08-14 14:01:36 +00:00
|
|
|
*/
|
2000-01-14 00:18:06 +00:00
|
|
|
if (ppc_detect(ppc, ppc->ppc_flags & 0xf))
|
1997-08-14 14:01:36 +00:00
|
|
|
goto error;
|
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
return (0);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
|
|
|
error:
|
2000-01-14 00:18:06 +00:00
|
|
|
if (ppc->res_irq != 0) {
|
|
|
|
bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq,
|
|
|
|
ppc->res_irq);
|
|
|
|
}
|
|
|
|
if (ppc->res_ioport != 0) {
|
|
|
|
bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport,
|
|
|
|
ppc->res_ioport);
|
|
|
|
}
|
|
|
|
if (ppc->res_drq != 0) {
|
|
|
|
bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq,
|
|
|
|
ppc->res_drq);
|
|
|
|
}
|
|
|
|
return (ENXIO);
|
1997-08-14 14:01:36 +00:00
|
|
|
}
|
|
|
|
|
2003-08-01 02:25:32 +00:00
|
|
|
int
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc_attach(device_t dev)
|
1997-08-14 14:01:36 +00:00
|
|
|
{
|
2000-01-14 00:18:06 +00:00
|
|
|
struct ppc_data *ppc = DEVTOSOFTC(dev);
|
2008-09-15 22:26:32 +00:00
|
|
|
int error;
|
1997-08-14 14:01:36 +00:00
|
|
|
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
mtx_init(&ppc->ppc_lock, device_get_nameunit(dev), "ppc", MTX_DEF);
|
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
device_printf(dev, "%s chipset (%s) in %s mode%s\n",
|
|
|
|
ppc_models[ppc->ppc_model], ppc_avms[ppc->ppc_avm],
|
|
|
|
ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ?
|
|
|
|
ppc_epp_protocol[ppc->ppc_epp] : "");
|
2008-11-16 17:42:02 +00:00
|
|
|
|
1999-01-10 12:04:56 +00:00
|
|
|
if (ppc->ppc_fifo)
|
2000-01-14 00:18:06 +00:00
|
|
|
device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n",
|
|
|
|
ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr);
|
1999-01-10 12:04:56 +00:00
|
|
|
|
2008-09-15 22:26:32 +00:00
|
|
|
if (ppc->res_irq) {
|
|
|
|
/* default to the tty mask for registration */ /* XXX */
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
error = bus_setup_intr(dev, ppc->res_irq, INTR_TYPE_TTY |
|
|
|
|
INTR_MPSAFE, NULL, ppcintr, ppc, &ppc->intr_cookie);
|
2008-09-15 22:26:32 +00:00
|
|
|
if (error) {
|
|
|
|
device_printf(dev,
|
|
|
|
"failed to register interrupt handler: %d\n",
|
|
|
|
error);
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
mtx_destroy(&ppc->ppc_lock);
|
2008-09-15 22:26:32 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
/* add ppbus as a child of this isa to parallel bridge */
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
ppc->ppbus = device_add_child(dev, "ppbus", -1);
|
1998-10-22 05:58:45 +00:00
|
|
|
|
1997-08-14 14:01:36 +00:00
|
|
|
/*
|
2000-01-14 00:18:06 +00:00
|
|
|
* Probe the ppbus and attach devices found.
|
1997-08-14 14:01:36 +00:00
|
|
|
*/
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
device_probe_and_attach(ppc->ppbus);
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
return (0);
|
|
|
|
}
|
1999-01-10 12:04:56 +00:00
|
|
|
|
2006-04-15 12:31:34 +00:00
|
|
|
int
|
|
|
|
ppc_detach(device_t dev)
|
|
|
|
{
|
|
|
|
struct ppc_data *ppc = DEVTOSOFTC(dev);
|
|
|
|
|
|
|
|
if (ppc->res_irq == 0) {
|
|
|
|
return (ENXIO);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* detach & delete all children */
|
2011-11-22 21:56:55 +00:00
|
|
|
device_delete_children(dev);
|
2006-04-15 12:31:34 +00:00
|
|
|
|
|
|
|
if (ppc->res_irq != 0) {
|
|
|
|
bus_teardown_intr(dev, ppc->res_irq, ppc->intr_cookie);
|
|
|
|
bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq,
|
|
|
|
ppc->res_irq);
|
|
|
|
}
|
|
|
|
if (ppc->res_ioport != 0) {
|
|
|
|
bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport,
|
|
|
|
ppc->res_ioport);
|
|
|
|
}
|
|
|
|
if (ppc->res_drq != 0) {
|
|
|
|
bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq,
|
|
|
|
ppc->res_drq);
|
|
|
|
}
|
|
|
|
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
mtx_destroy(&ppc->ppc_lock);
|
|
|
|
|
2006-04-15 12:31:34 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2003-08-01 02:25:32 +00:00
|
|
|
u_char
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte)
|
|
|
|
{
|
|
|
|
struct ppc_data *ppc = DEVTOSOFTC(ppcdev);
|
2008-11-16 17:42:02 +00:00
|
|
|
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
PPC_ASSERT_LOCKED(ppc);
|
2000-01-14 00:18:06 +00:00
|
|
|
switch (iop) {
|
|
|
|
case PPB_OUTSB_EPP:
|
2008-08-22 18:43:19 +00:00
|
|
|
bus_write_multi_1(ppc->res_ioport, PPC_EPP_DATA, addr, cnt);
|
2000-01-14 00:18:06 +00:00
|
|
|
break;
|
|
|
|
case PPB_OUTSW_EPP:
|
2008-08-22 18:43:19 +00:00
|
|
|
bus_write_multi_2(ppc->res_ioport, PPC_EPP_DATA, (u_int16_t *)addr, cnt);
|
2000-01-14 00:18:06 +00:00
|
|
|
break;
|
|
|
|
case PPB_OUTSL_EPP:
|
2008-08-22 18:43:19 +00:00
|
|
|
bus_write_multi_4(ppc->res_ioport, PPC_EPP_DATA, (u_int32_t *)addr, cnt);
|
2000-01-14 00:18:06 +00:00
|
|
|
break;
|
|
|
|
case PPB_INSB_EPP:
|
2008-08-22 18:43:19 +00:00
|
|
|
bus_read_multi_1(ppc->res_ioport, PPC_EPP_DATA, addr, cnt);
|
2000-01-14 00:18:06 +00:00
|
|
|
break;
|
|
|
|
case PPB_INSW_EPP:
|
2008-08-22 18:43:19 +00:00
|
|
|
bus_read_multi_2(ppc->res_ioport, PPC_EPP_DATA, (u_int16_t *)addr, cnt);
|
2000-01-14 00:18:06 +00:00
|
|
|
break;
|
|
|
|
case PPB_INSL_EPP:
|
2008-08-22 18:43:19 +00:00
|
|
|
bus_read_multi_4(ppc->res_ioport, PPC_EPP_DATA, (u_int32_t *)addr, cnt);
|
2000-01-14 00:18:06 +00:00
|
|
|
break;
|
|
|
|
case PPB_RDTR:
|
|
|
|
return (r_dtr(ppc));
|
|
|
|
case PPB_RSTR:
|
|
|
|
return (r_str(ppc));
|
|
|
|
case PPB_RCTR:
|
|
|
|
return (r_ctr(ppc));
|
|
|
|
case PPB_REPP_A:
|
|
|
|
return (r_epp_A(ppc));
|
|
|
|
case PPB_REPP_D:
|
|
|
|
return (r_epp_D(ppc));
|
|
|
|
case PPB_RECR:
|
|
|
|
return (r_ecr(ppc));
|
|
|
|
case PPB_RFIFO:
|
|
|
|
return (r_fifo(ppc));
|
|
|
|
case PPB_WDTR:
|
|
|
|
w_dtr(ppc, byte);
|
|
|
|
break;
|
|
|
|
case PPB_WSTR:
|
|
|
|
w_str(ppc, byte);
|
|
|
|
break;
|
|
|
|
case PPB_WCTR:
|
|
|
|
w_ctr(ppc, byte);
|
|
|
|
break;
|
|
|
|
case PPB_WEPP_A:
|
|
|
|
w_epp_A(ppc, byte);
|
|
|
|
break;
|
|
|
|
case PPB_WEPP_D:
|
|
|
|
w_epp_D(ppc, byte);
|
|
|
|
break;
|
|
|
|
case PPB_WECR:
|
|
|
|
w_ecr(ppc, byte);
|
|
|
|
break;
|
|
|
|
case PPB_WFIFO:
|
|
|
|
w_fifo(ppc, byte);
|
|
|
|
break;
|
|
|
|
default:
|
2001-12-10 08:09:49 +00:00
|
|
|
panic("%s: unknown I/O operation", __func__);
|
2000-01-14 00:18:06 +00:00
|
|
|
break;
|
1999-01-10 12:04:56 +00:00
|
|
|
}
|
|
|
|
|
2000-01-14 00:18:06 +00:00
|
|
|
return (0); /* not significative */
|
|
|
|
}
|
1997-08-14 14:01:36 +00:00
|
|
|
|
2003-08-01 02:25:32 +00:00
|
|
|
int
|
2000-01-14 00:18:06 +00:00
|
|
|
ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val)
|
|
|
|
{
|
|
|
|
struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus);
|
|
|
|
|
|
|
|
switch (index) {
|
|
|
|
case PPC_IVAR_EPP_PROTO:
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
PPC_ASSERT_LOCKED(ppc);
|
2000-01-14 00:18:06 +00:00
|
|
|
*val = (u_long)ppc->ppc_epp;
|
|
|
|
break;
|
Add locking to ppc and ppbus and mark the whole lot MPSAFE:
- To avoid having a bunch of locks that end up always getting acquired as
a group, give each ppc(4) device a mutex which it shares with all the
child devices including ppbus(4), lpt(4), plip(4), etc. This mutex
is then used for all the locking.
- Rework the interrupt handling stuff yet again. Now ppbus drivers setup
their interrupt handler during attach and tear it down during detach
like most other drivers. ppbus(4) only invokes the interrupt handler
of the device that currently owns the bus (if any) when an interrupt
occurs, however. Also, interrupt handlers in general now accept their
softc pointers as their argument rather than the device_t. Another
feature of the ppbus interrupt handlers is that they are called with
the parent ppc device's lock already held. This minimizes the number
of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
- Add a mutex to protect the global tables in plip(4) and free them on
module unload.
- Add a detach routine.
- Split out the init/stop code from the ioctl routine into separate
functions.
- Other lpt(4) changes:
- Use device_printf().
- Use a dedicated callout for the lptout timer.
- Allocate the I/O buffers at attach and detach rather than during
open and close as this simplifies the locking at the cost of
1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
- Use an sx lock to serialize open and close.
- Remove unused HADBUS flag.
- Add a detach routine.
- Use a malloc'd buffer for each read and write to avoid races with
concurrent read/write.
- Other pps(4) changes:
- Use a callout rather than a callout handle with timeout().
- Conform to the new ppbus requirements (regular mutex, non-filter
interrupt handler). pps(4) is probably going to have to become a
standalone driver that doesn't use ppbus(4) to satisfy it's
requirements for low latency as a result.
- Use an sx lock to serialize open and close.
- Other vpo(4) changes:
- Use the parent ppc device's lock to create the CAM sim instead of
Giant.
- Other ppc(4) changes:
- Fix ppc_isa's detach method to detach instead of calling attach.
Tested by: no one :-(
2009-01-21 23:10:06 +00:00
|
|
|
case PPC_IVAR_LOCK:
|
|
|
|
*val = (uintptr_t)&ppc->ppc_lock;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return (ENOENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ppc_write_ivar(device_t bus, device_t dev, int index, uintptr_t val)
|
|
|
|
{
|
|
|
|
struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus);
|
|
|
|
|
|
|
|
switch (index) {
|
|
|
|
case PPC_IVAR_INTR_HANDLER:
|
|
|
|
PPC_ASSERT_LOCKED(ppc);
|
|
|
|
if (dev != ppc->ppbus)
|
|
|
|
return (EINVAL);
|
|
|
|
if (val == 0) {
|
|
|
|
ppc->ppc_intr_hook = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ppc->ppc_intr_hook != NULL)
|
|
|
|
return (EBUSY);
|
|
|
|
ppc->ppc_intr_hook = (void *)val;
|
|
|
|
ppc->ppc_intr_arg = device_get_softc(dev);
|
|
|
|
break;
|
2000-01-14 00:18:06 +00:00
|
|
|
default:
|
|
|
|
return (ENOENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-09-15 22:26:32 +00:00
|
|
|
* We allow child devices to allocate an IRQ resource at rid 0 for their
|
|
|
|
* interrupt handlers.
|
2000-01-14 00:18:06 +00:00
|
|
|
*/
|
2008-09-15 22:26:32 +00:00
|
|
|
struct resource *
|
|
|
|
ppc_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
2016-01-27 02:23:54 +00:00
|
|
|
rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
|
2000-01-14 00:18:06 +00:00
|
|
|
{
|
|
|
|
struct ppc_data *ppc = DEVTOSOFTC(bus);
|
|
|
|
|
2008-09-15 22:26:32 +00:00
|
|
|
switch (type) {
|
|
|
|
case SYS_RES_IRQ:
|
|
|
|
if (*rid == 0)
|
|
|
|
return (ppc->res_irq);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (NULL);
|
|
|
|
}
|
2000-01-14 00:18:06 +00:00
|
|
|
|
2008-09-15 22:26:32 +00:00
|
|
|
int
|
|
|
|
ppc_release_resource(device_t bus, device_t child, int type, int rid,
|
|
|
|
struct resource *r)
|
|
|
|
{
|
|
|
|
#ifdef INVARIANTS
|
|
|
|
struct ppc_data *ppc = DEVTOSOFTC(bus);
|
|
|
|
#endif
|
2000-01-14 00:18:06 +00:00
|
|
|
|
2008-09-15 22:26:32 +00:00
|
|
|
switch (type) {
|
|
|
|
case SYS_RES_IRQ:
|
|
|
|
if (rid == 0) {
|
|
|
|
KASSERT(r == ppc->res_irq,
|
|
|
|
("ppc child IRQ resource mismatch"));
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
break;
|
2000-01-14 00:18:06 +00:00
|
|
|
}
|
2008-09-15 22:26:32 +00:00
|
|
|
return (EINVAL);
|
2000-01-14 00:18:06 +00:00
|
|
|
}
|
|
|
|
|
2005-12-21 10:54:47 +00:00
|
|
|
MODULE_DEPEND(ppc, ppbus, 1, 1, 1);
|