NetBSD/sys/dev/pci/cy_pci.c
sommerfeld 851de295eb Change pci_intr_map to get interrupt source information from a "struct
pci_attach_args *" instead of from four separate parameters which in
all cases were extracted from the same "struct pci_attach_args".

This both simplifies the driver api, and allows for alternate PCI
interrupt mapping schemes, such as one using the tables described in
the Intel Multiprocessor Spec which describe interrupt wirings for
devices behind pci-pci bridges based on the device's location rather
the bridge's location.

Tested on alpha and i386; welcome to 1.5Q
2000-12-28 22:59:06 +00:00

206 lines
5.0 KiB
C

/* $NetBSD: cy_pci.c,v 1.10 2000/12/28 22:59:11 sommerfeld Exp $ */
/*
* cy_pci.c
*
* Driver for Cyclades Cyclom-8/16/32 multiport serial cards
* (currently not tested with Cyclom-32 cards)
*
* Timo Rossi, 1996
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
#include <dev/ic/cd1400reg.h>
#include <dev/ic/cyreg.h>
#include <dev/ic/cyvar.h>
static int cy_match_pci __P((struct device *, struct cfdata *, void *));
static void cy_attach_pci __P((struct device *, struct device *, void *));
static int cy_map_pci __P((struct pci_attach_args *, bus_space_tag_t *,
bus_space_handle_t *, bus_size_t *, bus_space_tag_t *,
bus_space_handle_t *, bus_size_t *));
static void cy_unmap_pci __P((bus_space_tag_t, bus_space_handle_t,
bus_size_t, bus_space_tag_t, bus_space_handle_t, bus_size_t));
struct cfattach cy_pci_ca = {
sizeof(struct cy_softc), cy_match_pci, cy_attach_pci
};
static int
cy_map_pci(pap, iotp, iohp, iosizep, memtp, memhp, memsizep)
struct pci_attach_args *pap;
bus_space_tag_t *iotp, *memtp;
bus_space_handle_t *iohp, *memhp;
bus_size_t *iosizep, *memsizep;
{
int ioh_valid, memh_valid;
pcireg_t expected;
/* Map I/O (if possible). */
ioh_valid = (pci_mapreg_map(pap, 0x14, PCI_MAPREG_TYPE_IO, 0,
iotp, iohp, NULL, iosizep) == 0);
/* Map mem (if possible). Expected mem type depends on board ID. */
expected = PCI_MAPREG_TYPE_MEM;
switch (PCI_PRODUCT(pap->pa_id)) {
case PCI_PRODUCT_CYCLADES_CYCLOMY_1:
case PCI_PRODUCT_CYCLADES_CYCLOM4Y_1:
case PCI_PRODUCT_CYCLADES_CYCLOM8Y_1:
expected |= PCI_MAPREG_MEM_TYPE_32BIT_1M;
break;
default:
expected |= PCI_MAPREG_MEM_TYPE_32BIT;
}
memh_valid = (pci_mapreg_map(pap, 0x18, expected, 0,
memtp, memhp, NULL, memsizep) == 0);
if (ioh_valid && memh_valid)
return (1);
if (ioh_valid)
bus_space_unmap(*iotp, *iohp, *iosizep);
if (memh_valid)
bus_space_unmap(*memtp, *memhp, *memsizep);
return (0);
}
static void
cy_unmap_pci(iot, ioh, iosize, memt, memh, memsize)
bus_space_tag_t iot, memt;
bus_space_handle_t ioh, memh;
bus_size_t iosize, memsize;
{
bus_space_unmap(iot, ioh, iosize);
bus_space_unmap(memt, memh, memsize);
}
static int
cy_match_pci(parent, match, aux)
struct device *parent;
struct cfdata *match;
void *aux;
{
struct pci_attach_args *pap = aux;
bus_space_tag_t iot, memt;
bus_space_handle_t ioh, memh;
bus_size_t iosize, memsize;
if (PCI_VENDOR(pap->pa_id) != PCI_VENDOR_CYCLADES)
return 0;
switch (PCI_PRODUCT(pap->pa_id)) {
case PCI_PRODUCT_CYCLADES_CYCLOMY_1:
case PCI_PRODUCT_CYCLADES_CYCLOMY_2:
case PCI_PRODUCT_CYCLADES_CYCLOM4Y_1:
case PCI_PRODUCT_CYCLADES_CYCLOM4Y_2:
case PCI_PRODUCT_CYCLADES_CYCLOM8Y_1:
case PCI_PRODUCT_CYCLADES_CYCLOM8Y_2:
break;
default:
return 0;
}
#ifdef CY_DEBUG
printf("cy: Found Cyclades PCI device, id = 0x%x\n", pap->pa_id);
#endif
if (cy_map_pci(pap, &iot, &ioh, &iosize, &memt, &memh, &memsize) == 0)
return (0);
#if 0
XXX probably should do something like this, but this code is just
XXX too broken.
#ifdef CY_DEBUG
printf("%s: pci mapped mem 0x%lx (size %d), io 0x%x (size %d)\n",
sc.sc_dev.dv_xname, memaddr, memsize, iobase, iosize);
#endif
if ((rv = cy_find(&sc)) == 0)
printf("%s: PCI Cyclom card with no CD1400s!?\n",
sc.sc_dev.dv_xname);
#endif /* 0 */
cy_unmap_pci(iot, ioh, iosize, memt, memh, memsize);
return (1);
}
static void
cy_attach_pci(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct cy_softc *sc = (void *) self;
struct pci_attach_args *pap = aux;
pci_intr_handle_t intrhandle;
bus_space_tag_t iot, memt;
bus_space_handle_t ioh, memh;
bus_size_t iosize, memsize;
const char *intrstr;
int plx_ver;
sc->sc_bustype = CY_BUSTYPE_PCI;
if (cy_map_pci(pap, &iot, &ioh, &iosize, &memt, &memh,
&memsize) == 0) {
printf(": unable to map device registers\n");
return;
}
sc->sc_memt = memt;
sc->sc_bsh = memh;
if (cy_find(sc) == 0) {
printf(": cannot find CD1400s\n");
return;
}
/* Set up interrupt handler. */
if (pci_intr_map(pap, &intrhandle) != 0) {
printf(": couldn't map PCI interrupt\n");
return;
}
intrstr = pci_intr_string(pap->pa_pc, intrhandle);
sc->sc_ih = pci_intr_establish(pap->pa_pc, intrhandle, IPL_TTY,
cy_intr, sc);
if (sc->sc_ih == NULL) {
printf(": couldn't establish interrupt");
if (intrstr != NULL)
printf(" at %s", intrstr);
printf("\n");
return;
}
if (intrstr != NULL)
printf(": interrupting at %s\n%s", intrstr, self->dv_xname);
/* attach the hardware */
cy_attach(parent, self, aux);
plx_ver = bus_space_read_1(memt, memh, CY_PLX_VER) & 0x0f;
/* Enable PCI card interrupts */
switch (plx_ver) {
case CY_PLX_9050:
bus_space_write_2(iot, ioh, CY_PCI_INTENA_9050,
bus_space_read_2(iot, ioh, CY_PCI_INTENA_9050) | 0x40);
break;
case CY_PLX_9060:
case CY_PLX_9080:
default:
bus_space_write_2(iot, ioh, CY_PCI_INTENA,
bus_space_read_2(iot, ioh, CY_PCI_INTENA) | 0x900);
}
}