2010-12-11 21:25:02 +03:00
|
|
|
/* $NetBSD: ppb.c,v 1.43 2010/12/11 18:25:02 matt Exp $ */
|
1996-02-28 04:46:32 +03:00
|
|
|
|
|
|
|
/*
|
1998-03-04 09:31:46 +03:00
|
|
|
* Copyright (c) 1996, 1998 Christopher G. Demetriou. All rights reserved.
|
1996-02-28 04:46:32 +03:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by Christopher G. Demetriou
|
|
|
|
* for the NetBSD Project.
|
|
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2001-11-13 10:48:40 +03:00
|
|
|
#include <sys/cdefs.h>
|
2010-12-11 21:25:02 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: ppb.c,v 1.43 2010/12/11 18:25:02 matt Exp $");
|
2001-11-13 10:48:40 +03:00
|
|
|
|
1996-02-28 04:46:32 +03:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/device.h>
|
|
|
|
|
|
|
|
#include <dev/pci/pcireg.h>
|
|
|
|
#include <dev/pci/pcivar.h>
|
|
|
|
#include <dev/pci/ppbreg.h>
|
2007-12-09 23:27:42 +03:00
|
|
|
#include <dev/pci/pcidevs.h>
|
1996-02-28 04:46:32 +03:00
|
|
|
|
2002-05-16 05:01:28 +04:00
|
|
|
struct ppb_softc {
|
2008-05-03 09:44:06 +04:00
|
|
|
device_t sc_dev; /* generic device glue */
|
2002-05-16 05:01:28 +04:00
|
|
|
pci_chipset_tag_t sc_pc; /* our PCI chipset... */
|
|
|
|
pcitag_t sc_tag; /* ...and tag. */
|
2007-12-09 23:27:42 +03:00
|
|
|
|
|
|
|
pcireg_t sc_pciconfext[48];
|
2002-05-16 05:01:28 +04:00
|
|
|
};
|
|
|
|
|
2010-02-25 01:37:54 +03:00
|
|
|
static bool ppb_resume(device_t, const pmf_qual_t *);
|
|
|
|
static bool ppb_suspend(device_t, const pmf_qual_t *);
|
2007-12-09 23:27:42 +03:00
|
|
|
|
2005-06-28 04:28:41 +04:00
|
|
|
static int
|
2008-05-03 09:44:06 +04:00
|
|
|
ppbmatch(device_t parent, cfdata_t match, void *aux)
|
1996-02-28 04:46:32 +03:00
|
|
|
{
|
|
|
|
struct pci_attach_args *pa = aux;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the ID register to see that it's a PCI bridge.
|
|
|
|
* If it is, we assume that we can deal with it; it _should_
|
|
|
|
* work in a standardized way...
|
|
|
|
*/
|
|
|
|
if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
|
|
|
|
PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_PCI)
|
2008-05-03 09:44:06 +04:00
|
|
|
return 1;
|
1996-02-28 04:46:32 +03:00
|
|
|
|
2010-12-11 21:25:02 +03:00
|
|
|
#ifdef __powerpc__
|
|
|
|
if (PCI_CLASS(pa->pa_class) == PCI_CLASS_PROCESSOR &&
|
|
|
|
PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_PROCESSOR_POWERPC) {
|
|
|
|
pcireg_t bhlc = pci_conf_read(pa->pa_pc, pa->pa_tag,
|
|
|
|
PCI_BHLC_REG);
|
|
|
|
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_FREESCALE
|
|
|
|
&& PCI_HDRTYPE(bhlc) == PCI_HDRTYPE_RC)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-05-03 09:44:06 +04:00
|
|
|
return 0;
|
1996-02-28 04:46:32 +03:00
|
|
|
}
|
|
|
|
|
2007-10-16 22:27:00 +04:00
|
|
|
static void
|
2007-12-09 23:27:42 +03:00
|
|
|
ppb_fix_pcix(device_t self)
|
2007-10-16 22:27:00 +04:00
|
|
|
{
|
2007-12-09 23:27:42 +03:00
|
|
|
struct ppb_softc *sc = device_private(self);
|
2007-10-16 22:27:00 +04:00
|
|
|
pcireg_t reg;
|
|
|
|
int off;
|
|
|
|
|
2007-12-09 23:27:42 +03:00
|
|
|
if (!pci_get_capability(sc->sc_pc, sc->sc_tag, PCI_CAP_PCIEXPRESS,
|
2007-10-16 22:27:00 +04:00
|
|
|
&off, ®))
|
|
|
|
return; /* Not a PCIe device */
|
|
|
|
|
|
|
|
if ((reg & 0x000f0000) != 0x00010000) {
|
2008-05-03 09:02:41 +04:00
|
|
|
aprint_normal_dev(self, "unsupported PCI Express version\n");
|
2007-10-16 22:27:00 +04:00
|
|
|
return;
|
|
|
|
}
|
2007-12-09 23:27:42 +03:00
|
|
|
reg = pci_conf_read(sc->sc_pc, sc->sc_tag, off + 0x18);
|
2007-10-16 22:27:00 +04:00
|
|
|
if (reg & 0x003f) {
|
|
|
|
aprint_normal_dev(self, "disabling notification events\n");
|
|
|
|
reg &= ~0x003f;
|
2007-12-09 23:27:42 +03:00
|
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, off + 0x18, reg);
|
2007-10-16 22:27:00 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-28 04:28:41 +04:00
|
|
|
static void
|
2008-02-23 01:15:31 +03:00
|
|
|
ppbattach(device_t parent, device_t self, void *aux)
|
1996-02-28 04:46:32 +03:00
|
|
|
{
|
2008-02-23 01:15:31 +03:00
|
|
|
struct ppb_softc *sc = device_private(self);
|
1996-02-28 04:46:32 +03:00
|
|
|
struct pci_attach_args *pa = aux;
|
modify these to provide a new, better-specified PCI interface
(soon to be documented on mailing lists; eventually in section 9 manual
pages), most importantly:
(1) support interrupt pin swizzling on non-i386 systems with
PCI-PCI bridges (per PPB spec; done, but meaningless, on i386).
(2) provide pci_{io,mem}_find(), to determine what I/O or memory
space is described by a given PCI configuration space
mapping register.
(3) provide pci_intr_map(), pci_intr_string(), and
pci_intr_{,dis}establish() to manipulate and print info about
PCI interrupts.
(4) make pci functions take as an argument a machine-dependent
cookie, to allow more flexibility in implementation.
1996-03-27 07:08:24 +03:00
|
|
|
pci_chipset_tag_t pc = pa->pa_pc;
|
1996-02-28 04:46:32 +03:00
|
|
|
struct pcibus_attach_args pba;
|
modify these to provide a new, better-specified PCI interface
(soon to be documented on mailing lists; eventually in section 9 manual
pages), most importantly:
(1) support interrupt pin swizzling on non-i386 systems with
PCI-PCI bridges (per PPB spec; done, but meaningless, on i386).
(2) provide pci_{io,mem}_find(), to determine what I/O or memory
space is described by a given PCI configuration space
mapping register.
(3) provide pci_intr_map(), pci_intr_string(), and
pci_intr_{,dis}establish() to manipulate and print info about
PCI interrupts.
(4) make pci functions take as an argument a machine-dependent
cookie, to allow more flexibility in implementation.
1996-03-27 07:08:24 +03:00
|
|
|
pcireg_t busdata;
|
1996-02-28 04:46:32 +03:00
|
|
|
char devinfo[256];
|
|
|
|
|
2004-04-24 01:13:05 +04:00
|
|
|
pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
|
2003-12-09 22:51:39 +03:00
|
|
|
aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
|
|
|
|
PCI_REVISION(pa->pa_class));
|
|
|
|
aprint_naive("\n");
|
1996-02-28 04:46:32 +03:00
|
|
|
|
2002-05-16 05:01:28 +04:00
|
|
|
sc->sc_pc = pc;
|
|
|
|
sc->sc_tag = pa->pa_tag;
|
2008-05-03 09:44:06 +04:00
|
|
|
sc->sc_dev = self;
|
2002-05-16 05:01:28 +04:00
|
|
|
|
modify these to provide a new, better-specified PCI interface
(soon to be documented on mailing lists; eventually in section 9 manual
pages), most importantly:
(1) support interrupt pin swizzling on non-i386 systems with
PCI-PCI bridges (per PPB spec; done, but meaningless, on i386).
(2) provide pci_{io,mem}_find(), to determine what I/O or memory
space is described by a given PCI configuration space
mapping register.
(3) provide pci_intr_map(), pci_intr_string(), and
pci_intr_{,dis}establish() to manipulate and print info about
PCI interrupts.
(4) make pci functions take as an argument a machine-dependent
cookie, to allow more flexibility in implementation.
1996-03-27 07:08:24 +03:00
|
|
|
busdata = pci_conf_read(pc, pa->pa_tag, PPB_REG_BUSINFO);
|
1996-02-28 04:46:32 +03:00
|
|
|
|
modify these to provide a new, better-specified PCI interface
(soon to be documented on mailing lists; eventually in section 9 manual
pages), most importantly:
(1) support interrupt pin swizzling on non-i386 systems with
PCI-PCI bridges (per PPB spec; done, but meaningless, on i386).
(2) provide pci_{io,mem}_find(), to determine what I/O or memory
space is described by a given PCI configuration space
mapping register.
(3) provide pci_intr_map(), pci_intr_string(), and
pci_intr_{,dis}establish() to manipulate and print info about
PCI interrupts.
(4) make pci functions take as an argument a machine-dependent
cookie, to allow more flexibility in implementation.
1996-03-27 07:08:24 +03:00
|
|
|
if (PPB_BUSINFO_SECONDARY(busdata) == 0) {
|
2008-02-23 01:15:31 +03:00
|
|
|
aprint_normal_dev(self, "not configured by system firmware\n");
|
1996-02-28 04:46:32 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-12-09 23:27:42 +03:00
|
|
|
ppb_fix_pcix(self);
|
2007-10-16 22:27:00 +04:00
|
|
|
|
1996-02-28 04:46:32 +03:00
|
|
|
#if 0
|
|
|
|
/*
|
|
|
|
* XXX can't do this, because we're not given our bus number
|
modify these to provide a new, better-specified PCI interface
(soon to be documented on mailing lists; eventually in section 9 manual
pages), most importantly:
(1) support interrupt pin swizzling on non-i386 systems with
PCI-PCI bridges (per PPB spec; done, but meaningless, on i386).
(2) provide pci_{io,mem}_find(), to determine what I/O or memory
space is described by a given PCI configuration space
mapping register.
(3) provide pci_intr_map(), pci_intr_string(), and
pci_intr_{,dis}establish() to manipulate and print info about
PCI interrupts.
(4) make pci functions take as an argument a machine-dependent
cookie, to allow more flexibility in implementation.
1996-03-27 07:08:24 +03:00
|
|
|
* (we shouldn't need it), and because we've no way to
|
|
|
|
* decompose our tag.
|
1996-02-28 04:46:32 +03:00
|
|
|
*/
|
|
|
|
/* sanity check. */
|
modify these to provide a new, better-specified PCI interface
(soon to be documented on mailing lists; eventually in section 9 manual
pages), most importantly:
(1) support interrupt pin swizzling on non-i386 systems with
PCI-PCI bridges (per PPB spec; done, but meaningless, on i386).
(2) provide pci_{io,mem}_find(), to determine what I/O or memory
space is described by a given PCI configuration space
mapping register.
(3) provide pci_intr_map(), pci_intr_string(), and
pci_intr_{,dis}establish() to manipulate and print info about
PCI interrupts.
(4) make pci functions take as an argument a machine-dependent
cookie, to allow more flexibility in implementation.
1996-03-27 07:08:24 +03:00
|
|
|
if (pa->pa_bus != PPB_BUSINFO_PRIMARY(busdata))
|
1996-02-28 04:46:32 +03:00
|
|
|
panic("ppbattach: bus in tag (%d) != bus in reg (%d)",
|
modify these to provide a new, better-specified PCI interface
(soon to be documented on mailing lists; eventually in section 9 manual
pages), most importantly:
(1) support interrupt pin swizzling on non-i386 systems with
PCI-PCI bridges (per PPB spec; done, but meaningless, on i386).
(2) provide pci_{io,mem}_find(), to determine what I/O or memory
space is described by a given PCI configuration space
mapping register.
(3) provide pci_intr_map(), pci_intr_string(), and
pci_intr_{,dis}establish() to manipulate and print info about
PCI interrupts.
(4) make pci functions take as an argument a machine-dependent
cookie, to allow more flexibility in implementation.
1996-03-27 07:08:24 +03:00
|
|
|
pa->pa_bus, PPB_BUSINFO_PRIMARY(busdata));
|
1996-02-28 04:46:32 +03:00
|
|
|
#endif
|
|
|
|
|
2007-12-09 23:27:42 +03:00
|
|
|
if (!pmf_device_register(self, ppb_suspend, ppb_resume))
|
|
|
|
aprint_error_dev(self, "couldn't establish power handler\n");
|
|
|
|
|
1996-02-28 04:46:32 +03:00
|
|
|
/*
|
|
|
|
* Attach the PCI bus than hangs off of it.
|
1999-11-04 22:04:04 +03:00
|
|
|
*
|
|
|
|
* XXX Don't pass-through Memory Read Multiple. Should we?
|
|
|
|
* XXX Consult the spec...
|
1996-02-28 04:46:32 +03:00
|
|
|
*/
|
1996-10-22 02:56:24 +04:00
|
|
|
pba.pba_iot = pa->pa_iot;
|
|
|
|
pba.pba_memt = pa->pa_memt;
|
1997-08-30 10:53:57 +04:00
|
|
|
pba.pba_dmat = pa->pa_dmat;
|
2003-06-16 03:08:53 +04:00
|
|
|
pba.pba_dmat64 = pa->pa_dmat64;
|
modify these to provide a new, better-specified PCI interface
(soon to be documented on mailing lists; eventually in section 9 manual
pages), most importantly:
(1) support interrupt pin swizzling on non-i386 systems with
PCI-PCI bridges (per PPB spec; done, but meaningless, on i386).
(2) provide pci_{io,mem}_find(), to determine what I/O or memory
space is described by a given PCI configuration space
mapping register.
(3) provide pci_intr_map(), pci_intr_string(), and
pci_intr_{,dis}establish() to manipulate and print info about
PCI interrupts.
(4) make pci functions take as an argument a machine-dependent
cookie, to allow more flexibility in implementation.
1996-03-27 07:08:24 +03:00
|
|
|
pba.pba_pc = pc;
|
1999-11-04 22:04:04 +03:00
|
|
|
pba.pba_flags = pa->pa_flags & ~PCI_FLAGS_MRM_OKAY;
|
modify these to provide a new, better-specified PCI interface
(soon to be documented on mailing lists; eventually in section 9 manual
pages), most importantly:
(1) support interrupt pin swizzling on non-i386 systems with
PCI-PCI bridges (per PPB spec; done, but meaningless, on i386).
(2) provide pci_{io,mem}_find(), to determine what I/O or memory
space is described by a given PCI configuration space
mapping register.
(3) provide pci_intr_map(), pci_intr_string(), and
pci_intr_{,dis}establish() to manipulate and print info about
PCI interrupts.
(4) make pci functions take as an argument a machine-dependent
cookie, to allow more flexibility in implementation.
1996-03-27 07:08:24 +03:00
|
|
|
pba.pba_bus = PPB_BUSINFO_SECONDARY(busdata);
|
2002-05-16 05:01:28 +04:00
|
|
|
pba.pba_bridgetag = &sc->sc_tag;
|
modify these to provide a new, better-specified PCI interface
(soon to be documented on mailing lists; eventually in section 9 manual
pages), most importantly:
(1) support interrupt pin swizzling on non-i386 systems with
PCI-PCI bridges (per PPB spec; done, but meaningless, on i386).
(2) provide pci_{io,mem}_find(), to determine what I/O or memory
space is described by a given PCI configuration space
mapping register.
(3) provide pci_intr_map(), pci_intr_string(), and
pci_intr_{,dis}establish() to manipulate and print info about
PCI interrupts.
(4) make pci functions take as an argument a machine-dependent
cookie, to allow more flexibility in implementation.
1996-03-27 07:08:24 +03:00
|
|
|
pba.pba_intrswiz = pa->pa_intrswiz;
|
|
|
|
pba.pba_intrtag = pa->pa_intrtag;
|
1996-02-28 04:46:32 +03:00
|
|
|
|
2004-08-30 19:05:15 +04:00
|
|
|
config_found_ia(self, "pcibus", &pba, pcibusprint);
|
1996-02-28 04:46:32 +03:00
|
|
|
}
|
2005-06-28 04:28:41 +04:00
|
|
|
|
2008-02-23 01:15:31 +03:00
|
|
|
static int
|
|
|
|
ppbdetach(device_t self, int flags)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if ((rc = config_detach_children(self, flags)) != 0)
|
|
|
|
return rc;
|
|
|
|
pmf_device_deregister(self);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-12-09 23:27:42 +03:00
|
|
|
static bool
|
2010-02-25 01:37:54 +03:00
|
|
|
ppb_resume(device_t dv, const pmf_qual_t *qual)
|
2007-12-09 23:27:42 +03:00
|
|
|
{
|
|
|
|
struct ppb_softc *sc = device_private(dv);
|
|
|
|
int off;
|
|
|
|
pcireg_t val;
|
|
|
|
|
|
|
|
for (off = 0x40; off <= 0xff; off += 4) {
|
|
|
|
val = pci_conf_read(sc->sc_pc, sc->sc_tag, off);
|
|
|
|
if (val != sc->sc_pciconfext[(off - 0x40) / 4])
|
|
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, off,
|
|
|
|
sc->sc_pciconfext[(off - 0x40)/4]);
|
|
|
|
}
|
|
|
|
|
|
|
|
ppb_fix_pcix(dv);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2010-02-25 01:37:54 +03:00
|
|
|
ppb_suspend(device_t dv, const pmf_qual_t *qual)
|
2007-12-09 23:27:42 +03:00
|
|
|
{
|
|
|
|
struct ppb_softc *sc = device_private(dv);
|
|
|
|
int off;
|
|
|
|
|
|
|
|
for (off = 0x40; off <= 0xff; off += 4)
|
|
|
|
sc->sc_pciconfext[(off - 0x40) / 4] =
|
|
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, off);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-02-23 01:15:31 +03:00
|
|
|
static void
|
|
|
|
ppbchilddet(device_t self, device_t child)
|
|
|
|
{
|
|
|
|
/* we keep no references to child devices, so do nothing */
|
|
|
|
}
|
|
|
|
|
During shutdown, detach devices in an orderly fashion.
Call the detach routine for every device in the device tree, starting
with the leaves and moving toward the root, expecting that each
(pseudo-)device driver will use the opportunity to gracefully commit
outstandings transactions to the underlying (pseudo-)device and to
relinquish control of the hardware to the system BIOS.
Detaching devices is not suitable for every shutdown: in an emergency,
or if the system state is inconsistent, we should resort to a fast,
simple shutdown that uses only the pmf(9) shutdown hooks and the
(deprecated) shutdownhooks. For now, if the flag RB_NOSYNC is set in
boothowto, opt for the fast, simple shutdown.
Add a device flag, DVF_DETACH_SHUTDOWN, that indicates by its presence
that it is safe to detach a device during shutdown. Introduce macros
CFATTACH_DECL3() and CFATTACH_DECL3_NEW() for creating autoconf
attachments with default device flags. Add DVF_DETACH_SHUTDOWN
to configuration attachments for atabus(4), atw(4) at cardbus(4),
cardbus(4), cardslot(4), com(4) at isa(4), elanpar(4), elanpex(4),
elansc(4), gpio(4), npx(4) at isa(4), nsphyter(4), pci(4), pcib(4),
pcmcia(4), ppb(4), sip(4), wd(4), and wdc(4) at isa(4).
Add a device-detachment "reason" flag, DETACH_SHUTDOWN, that tells the
autoconf code and a device driver that the reason for detachment is
system shutdown.
Add a sysctl, kern.detachall, that tells the system to try to detach
every device at shutdown, regardless of any device's DVF_DETACH_SHUTDOWN
flag. The default for kern.detachall is 0. SET IT TO 1, PLEASE, TO
HELP TEST AND DEBUG DEVICE DETACHMENT AT SHUTDOWN.
This is a work in progress. In future work, I aim to treat
pseudo-devices more thoroughly, and to gracefully tear down a stack of
(pseudo-)disk drivers and filesystems, including cgd(4), vnd(4), and
raid(4) instances at shutdown.
Also commit some changes that are not easily untangled from the rest:
(1) begin to simplify device_t locking: rename struct pmf_private to
device_lock, and incorporate device_lock into struct device.
(2) #include <sys/device.h> in sys/pmf.h in order to get some
definitions that it needs. Stop unnecessarily #including <sys/device.h>
in sys/arch/x86/include/pic.h to keep the amd64, xen, and i386 releases
building.
2009-04-02 04:09:32 +04:00
|
|
|
CFATTACH_DECL3_NEW(ppb, sizeof(struct ppb_softc),
|
|
|
|
ppbmatch, ppbattach, ppbdetach, NULL, NULL, ppbchilddet,
|
|
|
|
DVF_DETACH_SHUTDOWN);
|