code:
/*	$OpenBSD: cardbus_map.c,v 1.15 2015/03/14 03:38:47 jsg Exp $	*/
/*	$NetBSD: cardbus_map.c,v 1.10 2000/03/07 00:31:46 mycroft Exp $	*/

/*
 * Copyright (c) 1999 and 2000
 *      HAYAKAWA Koichi.  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 ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/systm.h>

#include <machine/bus.h>

#include <dev/cardbus/cardbusvar.h>

#include <dev/pci/pcireg.h>	/* XXX */

#if defined DEBUG && !defined CARDBUS_MAP_DEBUG
#define CARDBUS_MAP_DEBUG
#endif

#if defined CARDBUS_MAP_DEBUG
#define STATIC
#define DPRINTF(a) printf a
#else
#ifdef DDB
#define STATIC
#else
#define STATIC static
#endif
#define DPRINTF(a)
#endif

/*
 * int cardbus_mapreg_map(struct cardbus_softc *, int, int, pcireg_t,
 *			  int bus_space_tag_t *, bus_space_handle_t *,
 *			  bus_addr_t *, bus_size_t *)
 *    This function maps bus-space on the value of Base Address
 *   Register (BAR) indexed by the argument `reg' (the second argument).
 *   When the value of the BAR is not valid, such as 0x00000000, a new
 *   address should be allocated for the BAR and new address values is
 *   written on the BAR.
 */
int
cardbus_mapreg_map(struct cardbus_softc *sc, int func, int reg,
    pcireg_t type, int busflags, bus_space_tag_t *tagp,
    bus_space_handle_t *handlep, bus_addr_t *basep, bus_size_t *sizep)
{
	cardbus_chipset_tag_t cc = sc->sc_cc;
	pci_chipset_tag_t pc = sc->sc_pc;
	cardbus_function_tag_t cf = sc->sc_cf;
	bus_space_tag_t bustag;
	rbus_tag_t rbustag;
	bus_space_handle_t handle;
	bus_addr_t base;
	bus_size_t size;
	int flags;
	int status = 0;

	pcitag_t tag = pci_make_tag(pc, sc->sc_bus,
	    sc->sc_device, func);

	DPRINTF(("cardbus_mapreg_map called: %s %x\n", sc->sc_dev.dv_xname,
	   type));

	if (pci_mapreg_info(pc, tag, reg, type, &base, &size, &flags))
		status = 1;

	if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
		bustag = sc->sc_iot;
		rbustag = sc->sc_rbus_iot;
	} else {
		bustag = sc->sc_memt;
		rbustag = sc->sc_rbus_memt;
	}
	if (status == 0) {
		bus_addr_t mask = size - 1;
		if (base != 0)
			mask = 0xffffffff;
		if ((*cf->cardbus_space_alloc)(cc, rbustag, base, size, mask,
		    size, busflags | flags, &base, &handle)) {
			panic("io alloc");
		}
	}
	pci_conf_write(pc, tag, reg, base);

	DPRINTF(("cardbus_mapreg_map: physaddr %lx\n", (unsigned long)base));

	if (tagp != 0)
		*tagp = bustag;
	if (handlep != 0)
		*handlep = handle;
	if (basep != 0)
		*basep = base;
	if (sizep != 0)
		*sizep = size;

	return (0);
}

/*
 * int cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg,
 *			    bus_space_tag_t tag, bus_space_handle_t handle,
 *			    bus_size_t size)
 *
 *   This function releases bus-space region and close memory or io
 *   window on the bridge.
 *
 *  Arguments:
 *   struct cardbus_softc *sc; the pointer to the device structure of cardbus.
 *   int func; the number of function on the device.
 *   int reg; the offset of BAR register.
 */
int
cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg,
    bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t size)
{
	cardbus_chipset_tag_t cc = sc->sc_cc;
	pci_chipset_tag_t pc = sc->sc_pc;
	cardbus_function_tag_t cf = sc->sc_cf;
	int st = 1;
	pcitag_t cardbustag;
	rbus_tag_t rbustag;

	if (sc->sc_iot == tag) {
		/* bus space is io space */
		DPRINTF(("%s: unmap i/o space\n", sc->sc_dev.dv_xname));
		rbustag = sc->sc_rbus_iot;
	} else if (sc->sc_memt == tag) {
		/* bus space is memory space */
		DPRINTF(("%s: unmap mem space\n", sc->sc_dev.dv_xname));
		rbustag = sc->sc_rbus_memt;
	} else
		return (1);

	cardbustag = pci_make_tag(pc, sc->sc_bus, sc->sc_device, func);

	pci_conf_write(pc, cardbustag, reg, 0);

	(*cf->cardbus_space_free)(cc, rbustag, handle, size);

	return (st);
}


code:
/*	$OpenBSD: cardbusvar.h,v 1.20 2014/12/18 10:51:35 mpi Exp $	*/
/*	$NetBSD: cardbusvar.h,v 1.17 2000/04/02 19:11:37 mycroft Exp $	*/

/*
 * Copyright (c) 1998, 1999 and 2000
 *       HAYAKAWA Koichi.  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 ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _DEV_CARDBUS_CARDBUSVAR_H_
#define _DEV_CARDBUS_CARDBUSVAR_H_

#include <dev/pci/pcivar.h>	/* for pcitag_t */
#include <dev/cardbus/rbus.h>

typedef void *cardbus_chipset_tag_t;
typedef int cardbus_intr_handle_t;

/* Base Registers */
#define CARDBUS_BASE0_REG  0x10
#define CARDBUS_BASE1_REG  0x14
#define CARDBUS_BASE2_REG  0x18
#define CARDBUS_BASE3_REG  0x1C
#define CARDBUS_BASE4_REG  0x20
#define CARDBUS_BASE5_REG  0x24
#define CARDBUS_CIS_REG    0x28
#define CARDBUS_ROM_REG	   0x30
#  define CARDBUS_CIS_ASIMASK 0x07
#    define CARDBUS_CIS_ASI(x) (CARDBUS_CIS_ASIMASK & (x))
#  define CARDBUS_CIS_ASI_TUPLE 0x00
#  define CARDBUS_CIS_ASI_BAR0  0x01
#  define CARDBUS_CIS_ASI_BAR1  0x02
#  define CARDBUS_CIS_ASI_BAR2  0x03
#  define CARDBUS_CIS_ASI_BAR3  0x04
#  define CARDBUS_CIS_ASI_BAR4  0x05
#  define CARDBUS_CIS_ASI_BAR5  0x06
#  define CARDBUS_CIS_ASI_ROM   0x07
#  define CARDBUS_CIS_ADDRMASK 0x0ffffff8
#    define CARDBUS_CIS_ADDR(x) (CARDBUS_CIS_ADDRMASK & (x))
#    define CARDBUS_CIS_ASI_BAR(x) (((CARDBUS_CIS_ASIMASK & (x))-1)*4+0x10)
#    define CARDBUS_CIS_ASI_ROM_IMAGE(x) (((x) >> 28) & 0xf)

/* XXX end */

typedef struct cardbus_functions {
	int (*cardbus_space_alloc)(cardbus_chipset_tag_t, rbus_tag_t,
	    bus_addr_t, bus_size_t, bus_addr_t, bus_size_t, int, bus_addr_t *,
	    bus_space_handle_t *);
	int (*cardbus_space_free)(cardbus_chipset_tag_t, rbus_tag_t,
	    bus_space_handle_t, bus_size_t);
	void *(*cardbus_intr_establish)(cardbus_chipset_tag_t, int, int,
	    int (*)(void *), void *, const char *);
	void (*cardbus_intr_disestablish)(cardbus_chipset_tag_t, void *);
	int (*cardbus_ctrl)(cardbus_chipset_tag_t, int);
	int (*cardbus_power)(cardbus_chipset_tag_t, int);
} cardbus_function_t, *cardbus_function_tag_t;

/*
 * struct cbslot_attach_args is the attach argument for cardbus card.
 */
struct cbslot_attach_args {
	char *cba_busname;
	bus_space_tag_t cba_iot;	/* cardbus i/o space tag */
	bus_space_tag_t cba_memt;	/* cardbus mem space tag */
	bus_dma_tag_t cba_dmat;		/* DMA tag */

	int cba_bus;			/* cardbus bus number */

	cardbus_chipset_tag_t cba_cc;	/* cardbus chipset */
	pci_chipset_tag_t cba_pc;	/* pci chipset */
	cardbus_function_tag_t cba_cf;	/* cardbus functions */
	int cba_intrline;		/* interrupt line */

	rbus_tag_t cba_rbus_iot;	/* CardBus i/o rbus tag */
	rbus_tag_t cba_rbus_memt;	/* CardBus mem rbus tag */

	int cba_cacheline;		/* cache line size */
	int cba_lattimer;		/* latency timer */
};

#define cbslotcf_dev  cf_loc[0]
#define cbslotcf_func cf_loc[1]
#define CBSLOT_UNK_DEV -1
#define CBSLOT_UNK_FUNC -1

struct cardbus_devfunc;

/*
 * struct cardbus_softc is the softc for cardbus card.
 */
struct cardbus_softc {
	struct device sc_dev;		/* fundamental device structure */

	int sc_bus;			/* cardbus bus number */
	int sc_device;			/* cardbus device number */
	int sc_intrline;		/* CardBus intrline */

	bus_space_tag_t sc_iot;		/* CardBus I/O space tag */
	bus_space_tag_t sc_memt;	/* CardBus MEM space tag */
	bus_dma_tag_t sc_dmat;		/* DMA tag */

	cardbus_chipset_tag_t sc_cc;	/* CardBus chipset */
	pci_chipset_tag_t sc_pc;	/* PCI chipset */
	cardbus_function_tag_t sc_cf;	/* CardBus function */

	rbus_tag_t sc_rbus_iot;		/* CardBus i/o rbus tag */
	rbus_tag_t sc_rbus_memt;	/* CardBus mem rbus tag */

	int sc_cacheline;		/* cache line size */
	int sc_lattimer;		/* latency timer */
	int sc_volt;			/* applied Vcc voltage */
#define PCCARD_33V  0x02
#define PCCARD_XXV  0x04
#define PCCARD_YYV  0x08
	int sc_poweron_func;
	struct cardbus_devfunc *sc_funcs[8];	/* cardbus device functions */
};

/*
 * struct cardbus_devfunc:
 *
 *   This is the data deposit for each function of a CardBus device.
 *   This structure is used for memory or i/o space allocation and
 *   disallocation.
 */
typedef struct cardbus_devfunc {
	cardbus_chipset_tag_t ct_cc;
	cardbus_function_tag_t ct_cf;
	struct cardbus_softc *ct_sc;	/* pointer to the parent */
	int ct_bus;			/* bus number */
	int ct_dev;			/* device number */
	int ct_func;			/* function number */

	rbus_tag_t ct_rbus_iot;		/* CardBus i/o rbus tag */
	rbus_tag_t ct_rbus_memt;	/* CardBus mem rbus tag */

	u_int32_t ct_lc;		/* Latency timer and cache line size */
	/* u_int32_t ct_cisreg; */	/* CIS reg: is it needed??? */

	struct device *ct_device;	/* pointer to the device */

	struct cardbus_devfunc *ct_next;

  /* some data structure needed for tuple??? */
} *cardbus_devfunc_t;

/* XXX various things extracted from CIS */
struct cardbus_cis_info {
	int32_t		manufacturer;
	int32_t		product;
	char		cis1_info_buf[256];
	char	       *cis1_info[4];
	struct cb_bar_info {
		unsigned int flags;
		unsigned int size;
	} bar[7];
	unsigned int	funcid;
	union {
		struct {
			int uart_type;
			int uart_present;
		} serial;
		struct {
			char netid[6];
			char netid_present;
			char __filler;
		} network;
	} funce;
};

struct cardbus_attach_args {
	int ca_unit;
	cardbus_devfunc_t ca_ct;
	pci_chipset_tag_t ca_pc;	/* PCI chipset */

	bus_space_tag_t ca_iot;		/* CardBus I/O space tag */
	bus_space_tag_t ca_memt;	/* CardBus MEM space tag */
	bus_dma_tag_t ca_dmat;		/* DMA tag */

	u_int ca_bus;
	u_int ca_device;
	u_int ca_function;
	pcitag_t ca_tag;
	pcireg_t ca_id;
	pcireg_t ca_class;

	/* Interrupt information */
	pci_intr_line_t ca_intrline;

	rbus_tag_t ca_rbus_iot;		/* CardBus i/o rbus tag */
	rbus_tag_t ca_rbus_memt;	/* CardBus mem rbus tag */

	struct cardbus_cis_info ca_cis;
};

#define CARDBUS_ENABLE  1	/* enable the channel */
#define CARDBUS_DISABLE 2	/* disable the channel */
#define CARDBUS_RESET   4
#define CARDBUS_CD	7
#  define CARDBUS_NOCARD 0
#  define CARDBUS_5V_CARD 0x01	/* XXX: It must not exist */
#  define CARDBUS_3V_CARD 0x02
#  define CARDBUS_XV_CARD 0x04
#  define CARDBUS_YV_CARD 0x08
#define CARDBUS_IO_ENABLE    100
#define CARDBUS_IO_DISABLE   101
#define CARDBUS_MEM_ENABLE   102
#define CARDBUS_MEM_DISABLE  103
#define CARDBUS_BM_ENABLE    104 /* bus master */
#define CARDBUS_BM_DISABLE   105

#define CARDBUS_VCC_UC  0x0000
#define CARDBUS_VCC_3V  0x0001
#define CARDBUS_VCC_XV  0x0002
#define CARDBUS_VCC_YV  0x0003
#define CARDBUS_VCC_0V  0x0004
#define CARDBUS_VCC_5V  0x0005	/* ??? */
#define CARDBUS_VCCMASK 0x000f
#define CARDBUS_VPP_UC  0x0000
#define CARDBUS_VPP_VCC 0x0010
#define CARDBUS_VPP_12V 0x0030
#define CARDBUS_VPP_0V  0x0040
#define CARDBUS_VPPMASK 0x00f0

#define CARDBUSCF_DEV			0
#define CARDBUSCF_DEV_DEFAULT		-1
#define CARDBUSCF_FUNCTION		1
#define CARDBUSCF_FUNCTION_DEFAULT	-1

/*
 * Locators devies that attach to 'cardbus', as specified to config.
 */
#define cardbuscf_dev cf_loc[CARDBUSCF_DEV]
#define CARDBUS_UNK_DEV CARDBUSCF_DEV_DEFAULT

#define cardbuscf_function cf_loc[CARDBUSCF_FUNCTION]
#define CARDBUS_UNK_FUNCTION CARDBUSCF_FUNCTION_DEFAULT

int	cardbus_attach_card(struct cardbus_softc *);
void	cardbus_detach_card(struct cardbus_softc *);
void   *cardbus_intr_establish(cardbus_chipset_tag_t, cardbus_function_tag_t,
	    cardbus_intr_handle_t irq, int level, int (*func) (void *),
	    void *arg, const char *);
void	cardbus_intr_disestablish(cardbus_chipset_tag_t,
	    cardbus_function_tag_t, void *handler);

int	cardbus_mapreg_map(struct cardbus_softc *, int, int, pcireg_t,
	    int, bus_space_tag_t *, bus_space_handle_t *, bus_addr_t *,
	    bus_size_t *);
int	cardbus_mapreg_unmap(struct cardbus_softc *, int, int,
	    bus_space_tag_t, bus_space_handle_t, bus_size_t);

int	cardbus_function_enable(struct cardbus_softc *, int function);
int	cardbus_function_disable(struct cardbus_softc *, int function);

int	cardbus_matchbyid(struct cardbus_attach_args *,
	    const struct pci_matchid *, int);

#define Cardbus_function_enable(ct)			\
    cardbus_function_enable((ct)->ct_sc, (ct)->ct_func)
#define Cardbus_function_disable(ct)			\
    cardbus_function_disable((ct)->ct_sc, (ct)->ct_func)

#define Cardbus_mapreg_map(ct, reg, type, busflags, tagp, handlep, basep, sizep) \
    cardbus_mapreg_map((ct)->ct_sc, (ct->ct_func), 	\
    (reg), (type), (busflags), (tagp), (handlep), (basep), (sizep))
#define Cardbus_mapreg_unmap(ct, reg, tag, handle, size)\
    cardbus_mapreg_unmap((ct)->ct_sc, (ct->ct_func), 	\
    (reg), (tag), (handle), (size))

#endif /* !_DEV_CARDBUS_CARDBUSVAR_H_ */

license: unknown


code:
/*	$OpenBSD: cardslot.c,v 1.19 2015/03/14 03:38:47 jsg Exp $	*/
/*	$NetBSD: cardslot.c,v 1.9 2000/03/22 09:35:06 haya Exp $	*/

/*
 * Copyright (c) 1999 and 2000
 *       HAYAKAWA Koichi.  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 ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/syslog.h>
#include <sys/kthread.h>
#include <sys/pool.h>
#include <sys/task.h>

#include <dev/cardbus/cardslotvar.h>
#include <dev/cardbus/cardbusvar.h>
#include <dev/pcmcia/pcmciavar.h>
#include <dev/pcmcia/pcmciachip.h>
#include <dev/ic/i82365var.h>

#if defined CARDSLOT_DEBUG
#define STATIC
#define DPRINTF(a) printf a
#else
#ifdef DDB
#define STATIC
#else
#define STATIC static
#endif
#define DPRINTF(a)
#endif

STATIC void cardslotattach(struct device *, struct device *, void *);

STATIC int cardslotmatch(struct device *, void *, void *);
STATIC void cardslot_event(void *arg);
STATIC void cardslot_process_event(struct cardslot_softc *);

STATIC int cardslot_cb_print(void *aux, const char *pcic);
STATIC int cardslot_16_print(void *, const char *);
STATIC int cardslot_16_submatch(struct device *, void *,void *);

struct cfattach cardslot_ca = {
	sizeof(struct cardslot_softc), cardslotmatch, cardslotattach
};

struct cfdriver cardslot_cd = {
	NULL, "cardslot", DV_DULL
};

struct pool cardsloteventpool;

STATIC int
cardslotmatch(struct device *parent, void *match, void *aux)
{
	struct cardslot_attach_args *caa = aux;

	if (caa->caa_cb_attach == NULL && caa->caa_16_attach == NULL) {
		/* Neither CardBus nor 16-bit PCMCIA are defined. */
		return (0);
	}

	return (1);
}

STATIC void
cardslotattach(struct device *parent, struct device *self, void *aux)
{
	struct cardslot_softc *sc = (struct cardslot_softc *)self;
	struct cardslot_attach_args *caa = aux;

	struct cbslot_attach_args *cba = caa->caa_cb_attach;
	struct pcmciabus_attach_args *pa = caa->caa_16_attach;

	struct cardbus_softc *csc = NULL;
	struct pcmcia_softc *psc = NULL;

	if (cardsloteventpool.pr_size == 0)
		pool_init(&cardsloteventpool, sizeof(struct cardslot_event),
		    0, 0, 0, "cardslot", NULL);

	sc->sc_slot = sc->sc_dev.dv_unit;
	sc->sc_cb_softc = NULL;
	sc->sc_16_softc = NULL;
	SIMPLEQ_INIT(&sc->sc_events);
	task_set(&sc->sc_event_task, cardslot_event, sc);

	printf(" slot %d flags %x\n", sc->sc_slot,
	    sc->sc_dev.dv_cfdata->cf_flags);

	DPRINTF(("%s attaching CardBus bus...\n", sc->sc_dev.dv_xname));
	if (cba != NULL) {
		if ((csc = (void *)config_found(self, cba,
		    cardslot_cb_print)) != NULL) {
			/* cardbus found */
			DPRINTF(("cardslotattach: found cardbus on %s\n",
			    sc->sc_dev.dv_xname));
			sc->sc_cb_softc = csc;
		}
	}

	if (pa != NULL) {
		if ((psc = (void *)config_found_sm(self, pa, cardslot_16_print,
		    cardslot_16_submatch)) != NULL) {
			/* pcmcia 16-bit bus found */
			DPRINTF(("cardslotattach: found 16-bit pcmcia bus\n"));
			sc->sc_16_softc = psc;
			/* XXX: dirty.  This code should be removed
			 * to achieve MI
			 */
			caa->caa_ph->pcmcia = (struct device *)psc;
		}
	}

	if (csc && (csc->sc_cf->cardbus_ctrl)(csc->sc_cc, CARDBUS_CD)) {
		DPRINTF(("cardslotattach: CardBus card found\n"));
		/* attach deferred */
		cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_CB);
	}

	if (psc && (psc->pct->card_detect)(psc->pch)) {
		DPRINTF(("cardbusattach: 16-bit card found\n"));
		/* attach deferred */
		cardslot_event_throw(sc, CARDSLOT_EVENT_INSERTION_16);
	}
}

STATIC int
cardslot_cb_print(void *aux, const char *pnp)
{
	struct cbslot_attach_args *cba = aux;

	if (pnp)
		printf("cardbus at %s subordinate bus %d", pnp, cba->cba_bus);

	return (UNCONF);
}

STATIC int
cardslot_16_submatch(struct device *parent, void *match, void *aux)
{
	struct cfdata *cf = match;

	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != 0)
		return (0);

	if (cf->cf_loc[0] == -1)
		return ((*cf->cf_attach->ca_match)(parent, cf, aux));

	return (0);
}

STATIC int
cardslot_16_print(void *arg, const char *pnp)
{
	if (pnp)
		printf("pcmciabus at %s", pnp);

	return (UNCONF);
}

/*
 * void cardslot_event_throw(struct cardslot_softc *sc, int ev)
 *
 *   This function throws an event to the event handler.  If the state
 *   of a slot is changed, it should be noticed using this function.
 */
void
cardslot_event_throw(struct cardslot_softc *sc, int ev)
{
	struct cardslot_event *ce;
	int s;

	DPRINTF(("cardslot_event_throw: an event %s comes\n",
	    ev == CARDSLOT_EVENT_INSERTION_CB ? "CardBus Card inserted" :
	    ev == CARDSLOT_EVENT_INSERTION_16 ? "16-bit Card inserted" :
	    ev == CARDSLOT_EVENT_REMOVAL_CB ? "CardBus Card removed" :
	    ev == CARDSLOT_EVENT_REMOVAL_16 ? "16-bit Card removed" : "???"));

	ce = pool_get(&cardsloteventpool, PR_NOWAIT);
	if (ce == NULL)
		return;
	ce->ce_type = ev;

	s = spltty();
	SIMPLEQ_INSERT_TAIL(&sc->sc_events, ce, ce_q);
	splx(s);

	task_add(systq, &sc->sc_event_task);
}

/*
 * STATIC void cardslot_event(void *arg)
 *
 *   This function is the main routine handing cardslot events such as
 *   insertions and removals.
 *
 */
STATIC void
cardslot_event(void *arg1)
{
	struct cardslot_softc *sc = arg1;

	while (!SIMPLEQ_EMPTY(&sc->sc_events))
		cardslot_process_event(sc);
}

STATIC void
cardslot_process_event(struct cardslot_softc *sc)
{
	struct cardslot_event *ce;
	int s, ev;

	s = spltty();
	if ((ce = SIMPLEQ_FIRST(&sc->sc_events)) == NULL) {
		splx(s);
		return;
	}
	SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q);

	if (IS_CARDSLOT_INSERT_REMOVE_EV(ce->ce_type)) {
		/* Chattering suppression */
		static int antonym_ev[4] = {
			CARDSLOT_EVENT_REMOVAL_16,
			CARDSLOT_EVENT_INSERTION_16,
			CARDSLOT_EVENT_REMOVAL_CB,
			CARDSLOT_EVENT_INSERTION_CB
		};

		while (1) {
			struct cardslot_event *ce1, *ce2;

			if ((ce1 = SIMPLEQ_FIRST(&sc->sc_events)) ==
			    NULL)
				break;
			if (ce1->ce_type != antonym_ev[ce->ce_type])
				break;
			if ((ce2 = SIMPLEQ_NEXT(ce1, ce_q)) == NULL)
				break;
			if (ce2->ce_type == ce->ce_type) {
				SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q);
				pool_put(&cardsloteventpool, ce1);
				SIMPLEQ_REMOVE_HEAD(&sc->sc_events, ce_q);
				pool_put(&cardsloteventpool, ce2);
			}
		}
	}
	splx(s);

	ev = ce->ce_type;
	pool_put(&cardsloteventpool, ce);

	switch (ev) {
	case CARDSLOT_EVENT_INSERTION_CB:
		if ((CARDSLOT_CARDTYPE(sc->sc_status) ==
		     CARDSLOT_STATUS_CARD_CB) ||
		    (CARDSLOT_CARDTYPE(sc->sc_status) ==
		     CARDSLOT_STATUS_CARD_16)) {
			if (CARDSLOT_WORK(sc->sc_status) ==
			    CARDSLOT_STATUS_WORKING) {
				/* A card has already been inserted
				 * and works.
				 */
				break;
			}
		}

		if (sc->sc_cb_softc) {
			CARDSLOT_SET_CARDTYPE(sc->sc_status,
			    CARDSLOT_STATUS_CARD_CB);
			if (cardbus_attach_card(sc->sc_cb_softc) > 0) {
				/* At least one function works */
				CARDSLOT_SET_WORK(sc->sc_status,
				    CARDSLOT_STATUS_WORKING);
			} else {
				/* No functions work or this card is
				 * not known
				 */
				CARDSLOT_SET_WORK(sc->sc_status,
				    CARDSLOT_STATUS_NOTWORK);
			}
		} else {
			printf("%s: CardBus support disabled\n",
			    sc->sc_dev.dv_xname);
		}
		break;

	case CARDSLOT_EVENT_INSERTION_16:
		if ((CARDSLOT_CARDTYPE(sc->sc_status) ==
		     CARDSLOT_STATUS_CARD_CB) ||
		    (CARDSLOT_CARDTYPE(sc->sc_status) ==
		     CARDSLOT_STATUS_CARD_16)) {
			if (CARDSLOT_WORK(sc->sc_status) ==
			    CARDSLOT_STATUS_WORKING) {
				/* A card has already been inserted
				 * and works.
				 */
				break;
			}
		}
		if (sc->sc_16_softc) {
			CARDSLOT_SET_CARDTYPE(sc->sc_status,
			    CARDSLOT_STATUS_CARD_16);
			if (pcmcia_card_attach(
			    (struct device *)sc->sc_16_softc)) {
				/* Do not attach */
				CARDSLOT_SET_WORK(sc->sc_status,
				    CARDSLOT_STATUS_NOTWORK);
			} else {
				/* working */
				CARDSLOT_SET_WORK(sc->sc_status,
				    CARDSLOT_STATUS_WORKING);
			}
		} else {
			panic("no 16-bit pcmcia on %s",
			    sc->sc_dev.dv_xname);
		}
		break;

	case CARDSLOT_EVENT_REMOVAL_CB:
		if (CARDSLOT_CARDTYPE(sc->sc_status) ==
		    CARDSLOT_STATUS_CARD_CB) {
			/* CardBus card has not been inserted. */
			if (CARDSLOT_WORK(sc->sc_status) ==
			    CARDSLOT_STATUS_WORKING) {
				cardbus_detach_card(sc->sc_cb_softc);
				CARDSLOT_SET_WORK(sc->sc_status,
				    CARDSLOT_STATUS_NOTWORK);
				CARDSLOT_SET_WORK(sc->sc_status,
				    CARDSLOT_STATUS_CARD_NONE);
			}
			CARDSLOT_SET_CARDTYPE(sc->sc_status,
			    CARDSLOT_STATUS_CARD_NONE);
		} else if (CARDSLOT_CARDTYPE(sc->sc_status) !=
		    CARDSLOT_STATUS_CARD_16) {
			/* Unknown card... */
			CARDSLOT_SET_CARDTYPE(sc->sc_status,
			    CARDSLOT_STATUS_CARD_NONE);
		}
		CARDSLOT_SET_WORK(sc->sc_status,
		    CARDSLOT_STATUS_NOTWORK);
		break;

	case CARDSLOT_EVENT_REMOVAL_16:
		DPRINTF(("%s: removal event\n", sc->sc_dev.dv_xname));
		if (CARDSLOT_CARDTYPE(sc->sc_status) !=
		    CARDSLOT_STATUS_CARD_16) {
			/* 16-bit card has not been inserted. */
			break;
		}
		if ((sc->sc_16_softc != NULL) &&
		    (CARDSLOT_WORK(sc->sc_status) ==
		     CARDSLOT_STATUS_WORKING)) {
			struct pcmcia_softc *psc = sc->sc_16_softc;

			pcmcia_card_deactivate((struct device *)psc);
			pcmcia_chip_socket_disable(psc->pct, psc->pch);
			pcmcia_card_detach((struct device *)psc,
			    DETACH_FORCE);
		}
		CARDSLOT_SET_CARDTYPE(sc->sc_status,
		    CARDSLOT_STATUS_CARD_NONE);
		CARDSLOT_SET_WORK(sc->sc_status,
		    CARDSLOT_STATUS_NOTWORK);
		break;

	default:
		panic("cardslot_event_thread: unknown event %d", ev);
	}
}


code:
/*	$OpenBSD: cardslotvar.h,v 1.6 2013/10/30 08:47:20 mpi Exp $	*/
/*	$NetBSD: cardslotvar.h,v 1.5 2000/03/13 23:52:38 soren Exp $	*/

/*
 * Copyright (c) 1999
 *       HAYAKAWA Koichi.  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 ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _DEV_CARDBUS_CARDSLOTVAR_H_
#define _DEV_CARDBUS_CARDSLOTVAR_H_

/* require sys/device.h */
/* require sys/queue.h */

struct cardslot_event;

/*
 * The data structure cardslot_attach_args is the attach argument for
 * PCMCIA (including CardBus and 16-bit card) slot.
 */
struct cardslot_attach_args {
	char *caa_busname;

	int caa_slot;

	/* for cardbus... */
	struct cbslot_attach_args *caa_cb_attach;

	/* for 16-bit pcmcia */
	struct pcmciabus_attach_args *caa_16_attach;

	/* XXX: for 16-bit pcmcia.  dirty!
	 * This should be removed to achieve MI.
	 */
	struct pcic_handle *caa_ph;
};

/*
 * The data structure cardslot_attach_args is the attach argument for
 * PCMCIA (including CardBus and 16-bit card) slot.
 */
struct cardslot_softc {
	struct device sc_dev;

	int sc_slot;			/* slot number */
	int sc_status;			/* the status of slot */

	struct cardbus_softc *sc_cb_softc;
	struct pcmcia_softc *sc_16_softc;

	/* An event queue for the thread which processes slot state events. */
	SIMPLEQ_HEAD(, cardslot_event) sc_events;
	struct task sc_event_task;
};

#define CARDSLOT_STATUS_CARD_MASK     0x07
#define CARDSLOT_STATUS_CARD_NONE     0x00  /* NO card inserted */
#define CARDSLOT_STATUS_CARD_16	      0x01  /* 16-bit pcmcia card inserted */
#define CARDSLOT_STATUS_CARD_CB	      0x02  /* CardBus pcmcia card inserted */
#define CARDSLOT_STATUS_UNKNOWN	      0x07  /* Unknown card inserted */

#define CARDSLOT_CARDTYPE(x) ((x) & CARDSLOT_STATUS_CARD_MASK)
#define CARDSLOT_SET_CARDTYPE(x, type) \
	do {(x) &= ~CARDSLOT_STATUS_CARD_MASK;\
	    (x) |= (CARDSLOT_STATUS_CARD_MASK & (type));} while(0)

#define CARDSLOT_STATUS_WORK_MASK     0x08
#define CARDSLOT_STATUS_WORKING	      0x08  /* at least one function works */
#define CARDSLOT_STATUS_NOTWORK	      0x00  /* no functions are working */

#define CARDSLOT_WORK(x) ((x) & CARDSLOT_STATUS_WORK_MASK)
#define CARDSLOT_SET_WORK(x, type) \
	do {(x) &= ~CARDSLOT_STATUS_WORK_MASK;\
	    (x) |= (CARDSLOT_STATUS_WORK_MASK & (type));} while(0)

struct cardslot_event {
	SIMPLEQ_ENTRY(cardslot_event) ce_q;

	int ce_type;
};

typedef struct cardslot_softc *cardslot_t;

/* ce_type */
#define	CARDSLOT_EVENT_INSERTION_16	0
#define	CARDSLOT_EVENT_REMOVAL_16	1

#define	CARDSLOT_EVENT_INSERTION_CB	2
#define	CARDSLOT_EVENT_REMOVAL_CB	3

#define IS_CARDSLOT_INSERT_REMOVE_EV(x) (0 <= (x) && (x) <= 3)

void	cardslot_event_throw(cardslot_t, int);

#endif /* !_DEV_CARDBUS_CARDSLOTVAR_H_ */


code:
/* $OpenBSD: com_cardbus.c,v 1.42 2012/07/12 08:20:53 deraadt Exp $ */
/* $NetBSD: com_cardbus.c,v 1.4 2000/04/17 09:21:59 joda Exp $ */

/*
 * Copyright (c) 2000 Johan Danielsson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of author nor the names of any contributors may
 *    be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 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 FOUNDATION 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.
 */

/* This is a driver for CardBus based serial devices. It is less
   generic than it could be, but it keeps the complexity down. So far
   it assumes that anything that reports itself as a `serial' device
   is infact a 16x50 or 8250, which is not necessarily true (in
   practice this shouldn't be a problem). It also does not handle
   devices in the `multiport serial' or `modem' sub-classes, I've
   never seen any of these, so I don't know what they might look like.

   If the CardBus device only has one BAR (that is not also the CIS
   BAR) listed in the CIS, it is assumed to be the one to use. For
   devices with more than one BAR, the list of known devies has to be
   updated below.  */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/tty.h>
#include <sys/device.h>

#include <dev/cardbus/cardbusvar.h>
#include <dev/pci/pcidevs.h>

#include <dev/pcmcia/pcmciareg.h>

#include "com.h"

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>
#include <dev/ic/ns16550reg.h>

#define	com_lcr		com_cfcr

struct com_cardbus_softc {
	struct com_softc	cc_com;
	void			*cc_ih;
	cardbus_devfunc_t	cc_ct;
	bus_addr_t		cc_addr;
	pcireg_t		cc_base;
	bus_size_t		cc_size;
	pcireg_t		cc_csr;
	int			cc_cben;
	pcitag_t		cc_tag;
	pcireg_t		cc_reg;
	int			cc_type;
	u_char			cc_bug;
	pci_chipset_tag_t	cc_pc;
};

#define DEVNAME(CSC) ((CSC)->cc_com.sc_dev.dv_xname)

int	com_cardbus_match(struct device *, void *, void *);
void	com_cardbus_attach(struct device *, struct device *, void *);
int	com_cardbus_detach(struct device *, int);

void	com_cardbus_setup(struct com_cardbus_softc *);
int	com_cardbus_enable(struct com_softc *);
void	com_cardbus_disable(struct com_softc *);
struct csdev *com_cardbus_find_csdev(struct cardbus_attach_args *);
int	com_cardbus_gofigure(struct cardbus_attach_args *,
    struct com_cardbus_softc *);

struct cfattach com_cardbus_ca = {
	sizeof(struct com_cardbus_softc), com_cardbus_match,
	com_cardbus_attach, com_cardbus_detach, com_activate
};

#define BUG_BROADCOM	0x01

/* XXX Keep this list syncronized with the corresponding one in pucdata.c */
static struct csdev {
	u_short		vendor;
	u_short		product;
	pcireg_t	reg;
	u_char		type;
	u_char		bug;
} csdevs[] = {
	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_GLOBALMODEM56,
	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_MODEM56,
	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL,
	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO, BUG_BROADCOM },
	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL_2,
	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO, BUG_BROADCOM },
	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL_GC,
	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56,
	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
	{ PCI_VENDOR_OXFORD2, PCI_PRODUCT_OXFORD2_OXCB950,
	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
	{ PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_CBEM56G,
	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
	{ PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56,
	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
	{ PCI_VENDOR_WCH, PCI_PRODUCT_WCH_CH352,
	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO },
	{ PCI_VENDOR_NETMOS, PCI_PRODUCT_NETMOS_NM9820,
	  CARDBUS_BASE0_REG, PCI_MAPREG_TYPE_IO }
};

static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);

struct csdev*
com_cardbus_find_csdev(struct cardbus_attach_args *ca)
{
	struct csdev *cp;

	for (cp = csdevs; cp < csdevs + ncsdevs; cp++)
		if (cp->vendor == PCI_VENDOR(ca->ca_id) &&
		    cp->product == PCI_PRODUCT(ca->ca_id))
			return (cp);
	return (NULL);
}

int
com_cardbus_match(struct device *parent, void *match, void *aux)
{
	struct cardbus_attach_args *ca = aux;

	/* known devices are ok */
	if (com_cardbus_find_csdev(ca) != NULL)
	    return (10);

	/* as are serial devices with a known UART */
	if (ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
	    ca->ca_cis.funce.serial.uart_present != 0 &&
	    (ca->ca_cis.funce.serial.uart_type == 0 ||	/* 8250 */
	    ca->ca_cis.funce.serial.uart_type == 1 ||	/* 16450 */
	    ca->ca_cis.funce.serial.uart_type == 2))	/* 16550 */
		return (1);

	return (0);
}

int
com_cardbus_gofigure(struct cardbus_attach_args *ca,
    struct com_cardbus_softc *csc)
{
	int i, index = -1;
	pcireg_t cis_ptr;
	struct csdev *cp;

	/* If this device is listed above, use the known values, */
	cp = com_cardbus_find_csdev(ca);
	if (cp != NULL) {
		csc->cc_reg = cp->reg;
		csc->cc_type = cp->type;
		csc->cc_bug = cp->bug;
		return (0);
	}

	cis_ptr = pci_conf_read(ca->ca_pc, csc->cc_tag, CARDBUS_CIS_REG);

	/* otherwise try to deduce which BAR and type to use from CIS.  If
	   there is only one BAR, it must be the one we should use, if
	   there are more, we're out of luck.  */
	for (i = 0; i < 7; i++) {
		/* ignore zero sized BARs */
		if (ca->ca_cis.bar[i].size == 0)
			continue;
		/* ignore the CIS BAR */
		if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
		    CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
			continue;
		if (index != -1)
			goto multi_bar;
		index = i;
	}
	if (index == -1) {
		printf(": couldn't find any base address tuple\n");
		return (1);
	}
	csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
	if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
		csc->cc_type = PCI_MAPREG_TYPE_MEM;
	else
		csc->cc_type = PCI_MAPREG_TYPE_IO;
	return (0);

  multi_bar:
	printf(": there are more than one possible base\n");

	printf("%s: address for this device, "
	    "please report the following information\n",
	    DEVNAME(csc));
	printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
	    PCI_VENDOR(ca->ca_id), PCI_PRODUCT(ca->ca_id));
	for (i = 0; i < 7; i++) {
		/* ignore zero sized BARs */
		if (ca->ca_cis.bar[i].size == 0)
			continue;
		/* ignore the CIS BAR */
		if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
		    CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
			continue;
		printf("%s: base address %x type %s size %x\n",
		    DEVNAME(csc), CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
		    (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
		    ca->ca_cis.bar[i].size);
	}
	return (1);
}

void
com_cardbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct com_softc *sc = (struct com_softc*)self;
	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self;
	struct cardbus_attach_args *ca = aux;
	cardbus_devfunc_t ct;

	csc->cc_ct = ct = ca->ca_ct;
	csc->cc_tag = pci_make_tag(ca->ca_pc, ct->ct_bus, ct->ct_dev, ct->ct_func);
	csc->cc_pc = ca->ca_pc;

	if (com_cardbus_gofigure(ca, csc) != 0)
		return;

	if (Cardbus_mapreg_map(ca->ca_ct, csc->cc_reg, csc->cc_type, 0,
	    &sc->sc_iot, &sc->sc_ioh, &csc->cc_addr, &csc->cc_size) != 0) {
		printf(": can't map memory\n");
		return;
	}

	csc->cc_base = csc->cc_addr;
	csc->cc_csr = PCI_COMMAND_MASTER_ENABLE;
	if (csc->cc_type == PCI_MAPREG_TYPE_IO) {
		csc->cc_base |= PCI_MAPREG_TYPE_IO;
		csc->cc_csr |= PCI_COMMAND_IO_ENABLE;
		csc->cc_cben = CARDBUS_IO_ENABLE;
	} else {
		csc->cc_csr |= PCI_COMMAND_MEM_ENABLE;
		csc->cc_cben = CARDBUS_MEM_ENABLE;
	}

	sc->sc_iobase = csc->cc_addr;
	sc->sc_frequency = COM_FREQ;

	sc->enable = com_cardbus_enable;
	sc->disable = com_cardbus_disable;
	sc->enabled = 0;

	if (com_cardbus_enable(sc))
		return;
	sc->enabled = 1;

	sc->sc_hwflags = 0;
	sc->sc_swflags = 0;

	if (csc->cc_bug & BUG_BROADCOM)
		sc->sc_fifolen = 15;

	com_attach_subr(sc);
}

void
com_cardbus_setup(struct com_cardbus_softc *csc)
{
	cardbus_devfunc_t ct = csc->cc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	pci_chipset_tag_t pc = csc->cc_pc;
	cardbus_function_tag_t cf = ct->ct_cf;
	pcireg_t reg;

	pci_conf_write(pc, csc->cc_tag, csc->cc_reg, csc->cc_base);

	/* enable accesses on cardbus bridge */
	cf->cardbus_ctrl(cc, csc->cc_cben);
	cf->cardbus_ctrl(cc, CARDBUS_BM_ENABLE);

	/* and the card itself */
	reg = pci_conf_read(pc, csc->cc_tag, PCI_COMMAND_STATUS_REG);
	reg &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE);
	reg |= csc->cc_csr;
	pci_conf_write(pc, csc->cc_tag, PCI_COMMAND_STATUS_REG, reg);

	/*
	 * Make sure the latency timer is set to some reasonable
	 * value.
	 */
	reg = pci_conf_read(pc, csc->cc_tag, PCI_BHLC_REG);
	if (PCI_LATTIMER(reg) < 0x20) {
			reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
			reg |= (0x20 << PCI_LATTIMER_SHIFT);
			pci_conf_write(pc, csc->cc_tag, PCI_BHLC_REG, reg);
	}
}

int
com_cardbus_enable(struct com_softc *sc)
{
	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
	struct cardbus_softc *psc =
	    (struct cardbus_softc *)sc->sc_dev.dv_parent;
	cardbus_chipset_tag_t cc = psc->sc_cc;
	cardbus_function_tag_t cf = psc->sc_cf;

	Cardbus_function_enable(csc->cc_ct);

	com_cardbus_setup(csc);

	/* establish the interrupt. */
	csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
	    IPL_TTY, comintr, sc, DEVNAME(csc));
	if (csc->cc_ih == NULL) {
		printf(": couldn't establish interrupt\n");
		return (1);
	}

	printf(": irq %d", psc->sc_intrline);

	return (0);
}

void
com_cardbus_disable(struct com_softc *sc)
{
	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
	struct cardbus_softc *psc =
	    (struct cardbus_softc *)sc->sc_dev.dv_parent;
	cardbus_chipset_tag_t cc = psc->sc_cc;
	cardbus_function_tag_t cf = psc->sc_cf;

	cardbus_intr_disestablish(cc, cf, csc->cc_ih);
	Cardbus_function_disable(csc->cc_ct);
}

int
com_cardbus_detach(struct device *self, int flags)
{
	struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self;
	struct com_softc *sc = (struct com_softc *) self;
	struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent;
	int error;

	if ((error = com_detach(self, flags)) != 0)
		return (error);

	cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);

	Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh,
	    csc->cc_size);

	return (0);
}


code:
/*	$OpenBSD: ehci_cardbus.c,v 1.21 2015/03/14 03:38:47 jsg Exp $ */
/*	$NetBSD: ehci_cardbus.c,v 1.6.6.3 2004/09/21 13:27:25 skrll Exp $	*/

/*
 * Copyright (c) 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Lennart Augustsson (lennart@augustsson.net) at
 * Carlstedt Research & Technology.
 *
 * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/rwlock.h>
#include <sys/device.h>

#include <machine/bus.h>

#include <dev/cardbus/cardbusvar.h>

#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_mem.h>

#include <dev/usb/ehcireg.h>
#include <dev/usb/ehcivar.h>

int	ehci_cardbus_match(struct device *, void *, void *);
void	ehci_cardbus_attach(struct device *, struct device *, void *);
int	ehci_cardbus_detach(struct device *, int);

struct ehci_cardbus_softc {
	struct ehci_softc	sc;
	cardbus_chipset_tag_t	sc_cc;
	cardbus_function_tag_t	sc_cf;
	cardbus_devfunc_t	sc_ct;
	void 			*sc_ih;		/* interrupt vectoring */
};

struct cfattach ehci_cardbus_ca = {
	sizeof(struct ehci_cardbus_softc), ehci_cardbus_match,
	ehci_cardbus_attach, ehci_cardbus_detach, ehci_activate
};

#define CARDBUS_CBMEM PCI_CBMEM
#define cardbus_findvendor pci_findvendor

int
ehci_cardbus_match(struct device *parent, void *match, void *aux)
{
	struct cardbus_attach_args *ca = (struct cardbus_attach_args *)aux;

	if (PCI_CLASS(ca->ca_class) == PCI_CLASS_SERIALBUS &&
	    PCI_SUBCLASS(ca->ca_class) == PCI_SUBCLASS_SERIALBUS_USB &&
	    PCI_INTERFACE(ca->ca_class) == PCI_INTERFACE_EHCI)
		return (1);

	return (0);
}

void
ehci_cardbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct ehci_cardbus_softc *sc = (struct ehci_cardbus_softc *)self;
	struct cardbus_attach_args *ca = aux;
	cardbus_devfunc_t ct = ca->ca_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	pci_chipset_tag_t pc = ca->ca_pc;
	cardbus_function_tag_t cf = ct->ct_cf;
	pcireg_t csr;
	usbd_status r;
	const char *vendor;
	const char *devname = sc->sc.sc_bus.bdev.dv_xname;

	/* Map I/O registers */
	if (Cardbus_mapreg_map(ct, CARDBUS_CBMEM, PCI_MAPREG_TYPE_MEM, 0,
			   &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size)) {
		printf(": can't map mem space\n");
		return;
	}

	sc->sc_cc = cc;
	sc->sc_cf = cf;
	sc->sc_ct = ct;
	sc->sc.sc_bus.dmatag = ca->ca_dmat;

	(ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
	(ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);

	/* Enable the device. */
	csr = pci_conf_read(pc, ca->ca_tag,
				PCI_COMMAND_STATUS_REG);
	pci_conf_write(pc, ca->ca_tag, PCI_COMMAND_STATUS_REG,
		       csr | PCI_COMMAND_MASTER_ENABLE
			   | PCI_COMMAND_MEM_ENABLE);

	/* Disable interrupts, so we don't get any spurious ones. */
	sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
	EOWRITE2(&sc->sc, EHCI_USBINTR, 0);

	sc->sc_ih = cardbus_intr_establish(cc, cf, ca->ca_intrline,
					   IPL_USB, ehci_intr, sc, devname);
	if (sc->sc_ih == NULL) {
		printf(": unable to establish interrupt\n");
		return;
	}
	printf(": irq %d\n", ca->ca_intrline);

	/* Figure out vendor for root hub descriptor. */
	vendor = cardbus_findvendor(ca->ca_id);
	sc->sc.sc_id_vendor = PCI_VENDOR(ca->ca_id);
	if (vendor)
		strlcpy(sc->sc.sc_vendor, vendor, sizeof(sc->sc.sc_vendor));
	else
		snprintf(sc->sc.sc_vendor, sizeof(sc->sc.sc_vendor),
		    "vendor 0x%04x", PCI_VENDOR(ca->ca_id));

	r = ehci_init(&sc->sc);
	if (r != USBD_NORMAL_COMPLETION) {
		printf("%s: init failed, error=%d\n", devname, r);

		/* Avoid spurious interrupts. */
		cardbus_intr_disestablish(sc->sc_cc, sc->sc_cf, sc->sc_ih);
		sc->sc_ih = NULL;

		return;
	}

	/* Attach usb device. */
	config_found(self, &sc->sc.sc_bus, usbctlprint);
}

int
ehci_cardbus_detach(struct device *self, int flags)
{
	struct ehci_cardbus_softc *sc = (struct ehci_cardbus_softc *)self;
	struct cardbus_devfunc *ct = sc->sc_ct;
	int rv;

	rv = ehci_detach(self, flags);
	if (rv)
		return (rv);
	if (sc->sc_ih != NULL) {
		cardbus_intr_disestablish(sc->sc_cc, sc->sc_cf, sc->sc_ih);
		sc->sc_ih = NULL;
	}
	if (sc->sc.sc_size) {
		Cardbus_mapreg_unmap(ct, CARDBUS_CBMEM, sc->sc.iot,
		    sc->sc.ioh, sc->sc.sc_size);
		sc->sc.sc_size = 0;
	}
	return (0);
}


code:
#	$OpenBSD: files.cardbus,v 1.30 2014/11/24 02:03:37 brad Exp $
#	$NetBSD: files.cardbus,v 1.8 2000/01/26 06:37:24 thorpej Exp $
#
# files.cardbus
#

device	cardslot: cbbus, pcmciabus
attach	cardslot at pcmciaslot
file	dev/cardbus/cardslot.c			cardslot

device	cardbus {[dev = -1], [function = -1]}
attach	cardbus at cbbus
file	dev/cardbus/cardbus.c			cardbus		needs-flag
file	dev/cardbus/cardbus_map.c		cardbus
file	dev/cardbus/cardbus_exrom.c		cardbus
file	dev/cardbus/rbus.c			cardbus

# Com ports
attach	com at cardbus with com_cardbus
file	dev/cardbus/com_cardbus.c		com_cardbus

# PCI "universal" communication device driver, for com, lpt, etc. ports
attach	puc at cardbus with puc_cardbus
file	dev/cardbus/puc_cardbus.c		puc_cardbus

#
# 3Com 3C575TX, 3C575BTX, and 3C575CTX
#
attach	xl at cardbus with xl_cardbus
file	dev/cardbus/if_xl_cardbus.c		xl_cardbus

#
# Tulip clone based CardBus cards
#
attach	dc at cardbus with dc_cardbus
file	dev/cardbus/if_dc_cardbus.c		dc_cardbus

#
# Intel PRO/100 8255x based CardBus cards
#
attach	fxp at cardbus with fxp_cardbus
file	dev/cardbus/if_fxp_cardbus.c		fxp_cardbus

#
# Realtek 8139 based CardBus cards
#
attach	rl at cardbus with rl_cardbus
file	dev/cardbus/if_rl_cardbus.c		rl_cardbus

#
# Realtek 8169/8169S/8110S
#
attach	re at cardbus with re_cardbus
file	dev/cardbus/if_re_cardbus.c		re_cardbus

#
# Atheros AR5k
#
attach	ath at cardbus with ath_cardbus
file	dev/cardbus/if_ath_cardbus.c		ath_cardbus

#
# Atheros AR9k
#
attach	athn at cardbus with athn_cardbus
file	dev/cardbus/if_athn_cardbus.c		athn_cardbus

#
# ADMtek ADM8211
#
attach	atw at cardbus with atw_cardbus
file	dev/cardbus/if_atw_cardbus.c		atw_cardbus

# Realtek RTL8180
#
attach	rtw at cardbus with rtw_cardbus
file	dev/cardbus/if_rtw_cardbus.c		rtw_cardbus

#
# Ralink RT2500
#
attach	ral at cardbus with ral_cardbus
file	dev/cardbus/if_ral_cardbus.c		ral_cardbus

#
# Texas Instruments ACX
#
attach	acx at cardbus with acx_cardbus
file	dev/cardbus/if_acx_cardbus.c		acx_cardbus

#
# Conexant PrismGT
#
attach	pgt at cardbus with pgt_cardbus
file	dev/cardbus/if_pgt_cardbus.c		pgt_cardbus

#
# EHCI USB controller
#
attach	ehci at cardbus with ehci_cardbus
file	dev/cardbus/ehci_cardbus.c		ehci_cardbus

#
# OHCI USB controller
#
attach	ohci at cardbus with ohci_cardbus
file	dev/cardbus/ohci_cardbus.c		ohci_cardbus

#
# Adaptec ADP-1480 SCSI controller
#
#attach	ahc at cardbus with ahc_cardbus: ahc_seeprom, smc93cx6
#file	dev/cardbus/ahc_cardbus.c		ahc_cardbus

#
# UHCI USB controller
#
attach	uhci at cardbus with uhci_cardbus
file	dev/cardbus/uhci_cardbus.c		uhci_cardbus

#
# Marvel Libertas Open
#
attach	malo at cardbus with malo_cardbus
file	dev/cardbus/if_malo_cardbus.c		malo_cardbus

#
# Broadcom AirForce
#
attach	bwi at cardbus with bwi_cardbus
file	dev/cardbus/if_bwi_cardbus.c		bwi_cardbus


code:
/*	$OpenBSD: if_acx_cardbus.c,v 1.21 2015/03/14 03:38:47 jsg Exp $  */

/*
 * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
 * Copyright (c) 2005, 2006
 *	Damien Bergamini <damien.bergamini@free.fr>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * CardBus front-end for the Texas Instruments ACX driver
 */

#include "bpfilter.h"

#include <sys/param.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/timeout.h>
#include <sys/device.h>

#include <machine/bus.h>
#include <machine/intr.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_radiotap.h>

#include <dev/ic/acxvar.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <dev/cardbus/cardbusvar.h>

struct acx_cardbus_softc {
	struct acx_softc	sc_acx;

	/* cardbus specific goo */
	cardbus_devfunc_t	sc_ct;
	pcitag_t		sc_tag;
	void			*sc_ih;
	bus_size_t		sc_mapsize1;
	bus_size_t		sc_mapsize2;
	pcireg_t		sc_iobar_val; /* acx100 only */
	pcireg_t		sc_bar1_val;
	pcireg_t		sc_bar2_val;
	int			sc_intrline;

	/* hack for ACX100A */
	bus_space_tag_t		sc_io_bt;
	bus_space_handle_t	sc_io_bh;
	bus_size_t		sc_iomapsize;

	int			sc_acx_attached;
	pci_chipset_tag_t	sc_pc;
};

int	acx_cardbus_match(struct device *, void *, void *);
void	acx_cardbus_attach(struct device *, struct device *, void *);
int	acx_cardbus_detach(struct device *, int);

struct cfattach acx_cardbus_ca = {
	sizeof (struct acx_cardbus_softc), acx_cardbus_match,
	acx_cardbus_attach, acx_cardbus_detach
};

static const struct pci_matchid acx_cardbus_devices[] = {
	{ PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX100A },
	{ PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX100B },
	{ PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX111 },
};

int	acx_cardbus_enable(struct acx_softc *);
void	acx_cardbus_disable(struct acx_softc *);
void	acx_cardbus_power(struct acx_softc *, int);
void	acx_cardbus_setup(struct acx_cardbus_softc *);

int
acx_cardbus_match(struct device *parent, void *match, void *aux)
{
	return (cardbus_matchbyid((struct cardbus_attach_args *)aux,
	    acx_cardbus_devices,
	    sizeof (acx_cardbus_devices) / sizeof (acx_cardbus_devices[0])));
}

void
acx_cardbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)self;
	struct acx_softc *sc = &csc->sc_acx;
	struct cardbus_attach_args *ca = aux;
	cardbus_devfunc_t ct = ca->ca_ct;
	bus_addr_t base;
	int error, b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;

	sc->sc_dmat = ca->ca_dmat;
	csc->sc_ct = ct;
	csc->sc_tag = ca->ca_tag;
	csc->sc_intrline = ca->ca_intrline;
	csc->sc_pc = ca->ca_pc;

	/* power management hooks */
	sc->sc_enable = acx_cardbus_enable;
	sc->sc_disable = acx_cardbus_disable;
	sc->sc_power = acx_cardbus_power;

	if (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_TI_ACX100A) {
		/* first map I/O space as seen in the dragonfly code */
		error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG,
		    PCI_MAPREG_TYPE_IO, 0, &csc->sc_io_bt, &csc->sc_io_bh,
		    &base, &csc->sc_iomapsize);
		if (error != 0) {
			printf(": can't map i/o space\n");
			return;
		}
		csc->sc_iobar_val = base | PCI_MAPREG_TYPE_IO;
		b1 = CARDBUS_BASE1_REG;
		b2 = CARDBUS_BASE2_REG;
	}

	/* map control/status registers */
	error = Cardbus_mapreg_map(ct, b1, PCI_MAPREG_TYPE_MEM, 0,
	    &sc->sc_mem1_bt, &sc->sc_mem1_bh, &base, &csc->sc_mapsize1);
	if (error != 0) {
		printf(": can't map mem1 space\n");
		return;
	}

	csc->sc_bar1_val = base | PCI_MAPREG_TYPE_MEM;

	/* map the other memory region */
	error = Cardbus_mapreg_map(ct, b2, PCI_MAPREG_TYPE_MEM, 0,
	    &sc->sc_mem2_bt, &sc->sc_mem2_bh, &base, &csc->sc_mapsize2);
	if (error != 0) {
		printf(": can't map mem2 space\n");
		return;
	}

	csc->sc_bar2_val = base | PCI_MAPREG_TYPE_MEM;

	/* set up the PCI configuration registers */
	acx_cardbus_setup(csc);

	printf(": irq %d\n", csc->sc_intrline);

	if (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_TI_ACX111)
		acx111_set_param(sc);
	else
		acx100_set_param(sc);

	error = acx_attach(sc);
	csc->sc_acx_attached = error == 0;

	Cardbus_function_disable(ct);
}

int
acx_cardbus_detach(struct device *self, int flags)
{
	struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)self;
	struct acx_softc *sc = &csc->sc_acx;
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;
	int error, b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;

	if (csc->sc_acx_attached) {
		error = acx_detach(sc);
		if (error != 0)
			return (error);
	}

	/* unhook the interrupt handler */
	if (csc->sc_ih != NULL) {
		cardbus_intr_disestablish(cc, cf, csc->sc_ih);
		csc->sc_ih = NULL;
	}

	/* release bus space and close window */
	if (csc->sc_iomapsize) {
		b1 = CARDBUS_BASE1_REG;
		b2 = CARDBUS_BASE2_REG;
	}
	Cardbus_mapreg_unmap(ct, b1, sc->sc_mem1_bt,
	    sc->sc_mem1_bh, csc->sc_mapsize1);
	Cardbus_mapreg_unmap(ct, b2, sc->sc_mem2_bt,
	    sc->sc_mem2_bh, csc->sc_mapsize2);
	if (csc->sc_iomapsize)
		Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, csc->sc_io_bt,
		    csc->sc_io_bh, csc->sc_iomapsize);

	return (0);
}

int
acx_cardbus_enable(struct acx_softc *sc)
{
	struct acx_cardbus_softc *csc;
	int error;

	csc = (struct acx_cardbus_softc *)sc;
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;

	/* power on the socket */
	error = Cardbus_function_enable(ct);
	if (error)
		return error;

	/* setup the PCI configuration registers */
	acx_cardbus_setup(csc);

	/* map and establish the interrupt handler */
	csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
	    acx_intr, sc, sc->sc_dev.dv_xname);
	if (csc->sc_ih == NULL) {
		printf("%s: could not establish interrupt at %d\n",
		    sc->sc_dev.dv_xname, csc->sc_intrline);
		Cardbus_function_disable(ct);
		return (1);
	}

	return (0);
}

void
acx_cardbus_disable(struct acx_softc *sc)
{
	struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)sc;
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;

	/* unhook the interrupt handler */
	cardbus_intr_disestablish(cc, cf, csc->sc_ih);
	csc->sc_ih = NULL;

	/* power down the socket */
	Cardbus_function_disable(ct);
}

void
acx_cardbus_power(struct acx_softc *sc, int why)
{
	struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)sc;

	if (why == DVACT_RESUME) {
		/* kick the PCI configuration registers */
		acx_cardbus_setup(csc);
	}
}

void
acx_cardbus_setup(struct acx_cardbus_softc *csc)
{
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	pci_chipset_tag_t pc = csc->sc_pc;
	cardbus_function_tag_t cf = ct->ct_cf;
	pcireg_t reg;
	int b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG;

	if (csc->sc_iobar_val) {
		pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE0_REG,
		    csc->sc_iobar_val);
		b1 = CARDBUS_BASE1_REG;
		b2 = CARDBUS_BASE2_REG;
		/* (*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); */
	}

	/* program the BAR */
	pci_conf_write(pc, csc->sc_tag, b1, csc->sc_bar1_val);
	pci_conf_write(pc, csc->sc_tag, b2, csc->sc_bar2_val);

	/* make sure the right access type is on the cardbus bridge */
	(*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
	(*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);

	/* enable the appropriate bits in the PCI CSR */
	reg = pci_conf_read(pc, csc->sc_tag,
	    PCI_COMMAND_STATUS_REG);
	reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
#if 0
	if (csc->sc_iobar_val)
		reg |= PCI_COMMAND_IO_ENABLE;
#endif
	pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
	    reg);
}


code:
/*      $OpenBSD: if_ath_cardbus.c,v 1.18 2014/12/22 02:28:51 tedu Exp $   */
/*	$NetBSD: if_ath_cardbus.c,v 1.4 2004/08/02 19:14:28 mycroft Exp $ */

/*
 * Copyright (c) 2003
 *	Ichiro FUKUHARA <ichiro@ichiro.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Ichiro FUKUHARA.
 * 4. The name of the company nor the name of the author may be used to
 *    endorse or promote products derived from this software without specific
 *    prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD 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.
 */

/*
 * CardBus bus front-end for the AR5001 Wireless LAN 802.11a/b/g CardBus.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/device.h>
#include <sys/gpio.h>
#include <sys/endian.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_rssadapt.h>

#include <machine/bus.h>
#include <machine/intr.h>

#include <dev/gpio/gpiovar.h>

#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>

#include <dev/cardbus/cardbusvar.h>

#include <dev/ic/athvar.h>

/*
 * PCI configuration space registers
 */
#define	ATH_PCI_MMBA		0x10	/* memory mapped base */

struct ath_cardbus_softc {
	struct ath_softc	sc_ath;

	/* CardBus-specific goo. */
	void	*sc_ih;			/* interrupt handle */
	cardbus_devfunc_t sc_ct;	/* our CardBus devfuncs */
	pcitag_t sc_tag;		/* our CardBus tag */

	pcireg_t sc_bar_val;		/* value of the BAR */

	int	sc_intrline;		/* interrupt line */
	pci_chipset_tag_t sc_pc;
};

int	ath_cardbus_match(struct device *, void *, void *);
void	ath_cardbus_attach(struct device *, struct device *, void *);
int	ath_cardbus_detach(struct device *, int);

struct cfattach ath_cardbus_ca = {
	sizeof(struct ath_cardbus_softc),
	ath_cardbus_match,
	ath_cardbus_attach,
	ath_cardbus_detach
};

void	ath_cardbus_setup(struct ath_cardbus_softc *);

int	ath_cardbus_enable(struct ath_softc *);
void	ath_cardbus_disable(struct ath_softc *);
void	ath_cardbus_power(struct ath_softc *, int);

int
ath_cardbus_match(struct device *parent, void *match, void *aux)
{
	struct cardbus_attach_args *ca = aux;
	const char* devname;

	devname = ath_hal_probe(PCI_VENDOR(ca->ca_id),
				PCI_PRODUCT(ca->ca_id));

	if (devname)
		return (1);

	return (0);
}

void
ath_cardbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct ath_cardbus_softc *csc = (void *)self;
	struct ath_softc *sc = &csc->sc_ath;
	struct cardbus_attach_args *ca = aux;
	cardbus_devfunc_t ct = ca->ca_ct;
	bus_addr_t adr;

	sc->sc_dmat = ca->ca_dmat;
	csc->sc_ct = ct;
	csc->sc_tag = ca->ca_tag;
	csc->sc_pc = ca->ca_pc;

	/*
	 * Power management hooks.
	 */
	sc->sc_enable = ath_cardbus_enable;
	sc->sc_disable = ath_cardbus_disable;
	sc->sc_power = ath_cardbus_power;

	/*
	 * Map the device.
	 */
	if (Cardbus_mapreg_map(ct, ATH_PCI_MMBA, PCI_MAPREG_TYPE_MEM, 0,
	    &sc->sc_st, &sc->sc_sh, &adr, &sc->sc_ss) == 0) {
		csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM;
	}

	else {
	        printf(": unable to map device registers\n");
		return;
	}

	/*
	 * Set up the PCI configuration registers.
	 */
	ath_cardbus_setup(csc);

	/* Remember which interrupt line. */
	csc->sc_intrline = ca->ca_intrline;

	printf(": irq %d\n", csc->sc_intrline);

	/*
	 * Finish off the attach.
	 */
	ath_attach(PCI_PRODUCT(ca->ca_id), sc);

	/*
	 * Power down the socket.
	 */
	Cardbus_function_disable(csc->sc_ct);
}

int
ath_cardbus_detach(struct device *self, int flags)
{
	struct ath_cardbus_softc *csc = (void *)self;
	struct ath_softc *sc = &csc->sc_ath;
	struct cardbus_devfunc *ct = csc->sc_ct;
	int rv;

#if defined(DIAGNOSTIC)
	if (ct == NULL)
		panic("%s: data structure lacks", sc->sc_dev.dv_xname);
#endif

	rv = ath_detach(sc, flags);
	if (rv)
		return (rv);

	/*
	 * Unhook the interrupt handler.
	 */
	if (csc->sc_ih != NULL) {
		cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih);
		csc->sc_ih = NULL;
	}

	/*
	 * Release bus space and close window.
	 */
	Cardbus_mapreg_unmap(ct, ATH_PCI_MMBA,
		    sc->sc_st, sc->sc_sh, sc->sc_ss);

	return (0);
}

int
ath_cardbus_enable(struct ath_softc *sc)
{
	struct ath_cardbus_softc *csc = (void *) sc;
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;

	/*
	 * Power on the socket.
	 */
	Cardbus_function_enable(ct);

	/*
	 * Set up the PCI configuration registers.
	 */
	ath_cardbus_setup(csc);

	/*
	 * Map and establish the interrupt.
	 */
	csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
	    ath_intr, sc, sc->sc_dev.dv_xname);
	if (csc->sc_ih == NULL) {
		printf(": unable to establish irq %d\n",
		       csc->sc_intrline);
		Cardbus_function_disable(csc->sc_ct);
		return (1);
	}
	return (0);
}

void
ath_cardbus_disable(struct ath_softc *sc)
{
	struct ath_cardbus_softc *csc = (void *) sc;
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;

	/* Unhook the interrupt handler. */
	cardbus_intr_disestablish(cc, cf, csc->sc_ih);
	csc->sc_ih = NULL;

	/* Power down the socket. */
	Cardbus_function_disable(ct);
}

void
ath_cardbus_power(struct ath_softc *sc, int why)
{
	if (why == DVACT_RESUME)
		ath_enable(sc);
}

void
ath_cardbus_setup(struct ath_cardbus_softc *csc)
{
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	pci_chipset_tag_t pc = csc->sc_pc;
	pcireg_t reg;

#ifdef notyet
	(void)cardbus_setpowerstate(sc->sc_dev.dv_xname, ct, csc->sc_tag,
	    PCI_PWR_D0);
#endif

	/* Program the BAR. */
	pci_conf_write(pc, csc->sc_tag, ATH_PCI_MMBA,
	    csc->sc_bar_val);

	/* Make sure the right access type is on the CardBus bridge. */
	(*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
	(*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);

	/* Enable the appropriate bits in the PCI CSR. */
	reg = pci_conf_read(pc, csc->sc_tag,
	    PCI_COMMAND_STATUS_REG);
	reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
	pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
	    reg);

	/*
	 * Make sure the latency timer is set to some reasonable
	 * value.
	 */
	reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG);
	if (PCI_LATTIMER(reg) < 0x20) {
		reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
		reg |= (0x20 << PCI_LATTIMER_SHIFT);
		pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg);
	}
}


code:
/*	$OpenBSD: if_athn_cardbus.c,v 1.13 2011/01/08 10:02:32 damien Exp $	*/

/*-
 * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * CardBus front-end for Atheros 802.11a/g/n chipsets.
 */

#include "bpfilter.h"

#include <sys/param.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/timeout.h>
#include <sys/device.h>

#include <machine/bus.h>
#include <machine/intr.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_radiotap.h>

#include <dev/ic/athnreg.h>
#include <dev/ic/athnvar.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <dev/cardbus/cardbusvar.h>

struct athn_cardbus_softc {
	struct athn_softc	sc_sc;

	/* CardBus specific goo. */
	cardbus_devfunc_t	sc_ct;
	pcitag_t		sc_tag;
	void			*sc_ih;
	bus_space_tag_t		sc_st;
	bus_space_handle_t	sc_sh;
	bus_size_t		sc_mapsize;
	pcireg_t		sc_bar_val;
	int			sc_intrline;
	pci_chipset_tag_t	sc_pc;
};

int		athn_cardbus_match(struct device *, void *, void *);
void		athn_cardbus_attach(struct device *, struct device *, void *);
int		athn_cardbus_detach(struct device *, int);
int		athn_cardbus_enable(struct athn_softc *);
void		athn_cardbus_disable(struct athn_softc *);
void		athn_cardbus_power(struct athn_softc *, int);
void		athn_cardbus_setup(struct athn_cardbus_softc *);
uint32_t	athn_cardbus_read(struct athn_softc *, uint32_t);
void		athn_cardbus_write(struct athn_softc *, uint32_t, uint32_t);
void		athn_cardbus_write_barrier(struct athn_softc *);

struct cfattach athn_cardbus_ca = {
	sizeof (struct athn_cardbus_softc),
	athn_cardbus_match,
	athn_cardbus_attach,
	athn_cardbus_detach
};

static const struct pci_matchid athn_cardbus_devices[] = {
	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5416 },
	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5418 },
	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9160 },
	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9280 },
	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9281 },
	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9285 },
	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR2427 },
	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9227 },
	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9287 },
	{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9300 }
};

int
athn_cardbus_match(struct device *parent, void *match, void *aux)
{
	return (cardbus_matchbyid(aux, athn_cardbus_devices,
	    nitems(athn_cardbus_devices)));
}

void
athn_cardbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)self;
	struct athn_softc *sc = &csc->sc_sc;
	struct cardbus_attach_args *ca = aux;
	cardbus_devfunc_t ct = ca->ca_ct;
	bus_addr_t base;
	int error;

	sc->sc_dmat = ca->ca_dmat;
	csc->sc_ct = ct;
	csc->sc_tag = ca->ca_tag;
	csc->sc_intrline = ca->ca_intrline;
	csc->sc_pc = ca->ca_pc;

	/* Power management hooks. */
	sc->sc_enable = athn_cardbus_enable;
	sc->sc_disable = athn_cardbus_disable;
	sc->sc_power = athn_cardbus_power;

	sc->ops.read = athn_cardbus_read;
	sc->ops.write = athn_cardbus_write;
	sc->ops.write_barrier = athn_cardbus_write_barrier;

	/* Map control/status registers. */
	error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG,
	    PCI_MAPREG_TYPE_MEM, 0, &csc->sc_st, &csc->sc_sh, &base,
	    &csc->sc_mapsize);
	if (error != 0) {
		printf(": can't map mem space\n");
		return;
	}
	csc->sc_bar_val = base | PCI_MAPREG_TYPE_MEM;

	/* Set up the PCI configuration registers. */
	athn_cardbus_setup(csc);

	printf(": irq %d\n", csc->sc_intrline);

	athn_attach(sc);
	Cardbus_function_disable(ct);
}

int
athn_cardbus_detach(struct device *self, int flags)
{
	struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)self;
	struct athn_softc *sc = &csc->sc_sc;
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;

	athn_detach(sc);

	/* Unhook the interrupt handler. */
	if (csc->sc_ih != NULL)
		cardbus_intr_disestablish(cc, cf, csc->sc_ih);

	/* Release bus space and close window. */
	Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, csc->sc_st, csc->sc_sh,
	    csc->sc_mapsize);

	return (0);
}

int
athn_cardbus_enable(struct athn_softc *sc)
{
	struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;

	/* Power on the socket. */
	Cardbus_function_enable(ct);

	/* Setup the PCI configuration registers. */
	athn_cardbus_setup(csc);

	/* Map and establish the interrupt handler. */
	csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
	    athn_intr, sc, sc->sc_dev.dv_xname);
	if (csc->sc_ih == NULL) {
		printf("%s: could not establish interrupt at %d\n",
		    sc->sc_dev.dv_xname, csc->sc_intrline);
		Cardbus_function_disable(ct);
		return (1);
	}
	return (0);
}

void
athn_cardbus_disable(struct athn_softc *sc)
{
	struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;

	/* Unhook the interrupt handler. */
	cardbus_intr_disestablish(cc, cf, csc->sc_ih);
	csc->sc_ih = NULL;

	/* Power down the socket. */
	Cardbus_function_disable(ct);
}

void
athn_cardbus_power(struct athn_softc *sc, int why)
{
	struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;

	if (why == DVACT_RESUME) {
		/* Restore the PCI configuration registers. */
		athn_cardbus_setup(csc);
	}
}

void
athn_cardbus_setup(struct athn_cardbus_softc *csc)
{
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	pci_chipset_tag_t pc = csc->sc_pc;
	cardbus_function_tag_t cf = ct->ct_cf;
	pcireg_t reg;

	/* Program the BAR. */
	pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE0_REG,
	    csc->sc_bar_val);

	/* Make sure the right access type is on the cardbus bridge. */
	(*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
	(*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);

	/* Enable the appropriate bits in the PCI CSR. */
	reg = pci_conf_read(pc, csc->sc_tag,
	    PCI_COMMAND_STATUS_REG);
	reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
	pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
	    reg);

	/*
	 * Noone knows why this shit is necessary but there are claims that
	 * not doing this may cause very frequent PCI FATAL interrupts from
	 * the card: http://bugzilla.kernel.org/show_bug.cgi?id=13483
	 */
	reg = pci_conf_read(pc, csc->sc_tag, 0x40);
	if (reg & 0xff00)
		pci_conf_write(pc, csc->sc_tag, 0x40, reg & ~0xff00);

	/* Change latency timer; default value yields poor results. */
	reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG);
	reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
	reg |= 168 << PCI_LATTIMER_SHIFT;
	pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg);
}

uint32_t
athn_cardbus_read(struct athn_softc *sc, uint32_t addr)
{
	struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;

	return (bus_space_read_4(csc->sc_st, csc->sc_sh, addr));
}

void
athn_cardbus_write(struct athn_softc *sc, uint32_t addr, uint32_t val)
{
	struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;

	bus_space_write_4(csc->sc_st, csc->sc_sh, addr, val);
}

void
athn_cardbus_write_barrier(struct athn_softc *sc)
{
	struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;

	bus_space_barrier(csc->sc_st, csc->sc_sh, 0, csc->sc_mapsize,
	    BUS_SPACE_BARRIER_WRITE);
}


code:
/*	$OpenBSD: if_atw_cardbus.c,v 1.23 2015/03/14 03:38:47 jsg Exp $	*/
/*	$NetBSD: if_atw_cardbus.c,v 1.9 2004/07/23 07:07:55 dyoung Exp $	*/

/*-
 * Copyright (c) 1999, 2000, 2003 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
 * NASA Ames Research Center.  This code was adapted for the ADMtek ADM8211
 * by David Young.
 *
 * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
 */

/*
 * CardBus bus front-end for the ADMtek ADM8211 802.11 MAC/BBP driver.
 */

#include "bpfilter.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/device.h>
#include <sys/endian.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_var.h>

#if NBPFILTER > 0
#include <net/bpf.h>
#endif

#include <machine/bus.h>
#include <machine/intr.h>

#include <dev/ic/atwreg.h>
#include <dev/ic/si4136reg.h>
#include <dev/ic/atwvar.h>

#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>

#include <dev/cardbus/cardbusvar.h>

/*
 * PCI configuration space registers used by the ADM8211.
 */
#define	ATW_PCI_IOBA		0x10	/* i/o mapped base */
#define	ATW_PCI_MMBA		0x14	/* memory mapped base */

struct atw_cardbus_softc {
	struct atw_softc sc_atw;	/* real ADM8211 softc */

	/* CardBus-specific goo. */
	void	*sc_ih;			/* interrupt handle */
	cardbus_devfunc_t sc_ct;	/* our CardBus devfuncs */
	pcitag_t sc_tag;		/* our CardBus tag */
	int	sc_csr;			/* CSR bits */
	bus_size_t sc_mapsize;		/* the size of mapped bus space
					   region */

	int	sc_cben;		/* CardBus enables */
	int	sc_bar_reg;		/* which BAR to use */
	pcireg_t sc_bar_val;		/* value of the BAR */

	int	sc_intrline;		/* interrupt line */
	pci_chipset_tag_t sc_pc;
};

int	atw_cardbus_match(struct device *, void *, void *);
void	atw_cardbus_attach(struct device *, struct device *, void *);
int	atw_cardbus_detach(struct device *, int);

struct cfattach atw_cardbus_ca = {
	sizeof(struct atw_cardbus_softc), atw_cardbus_match, atw_cardbus_attach,
	    atw_cardbus_detach
};

void	atw_cardbus_setup(struct atw_cardbus_softc *);

int	atw_cardbus_enable(struct atw_softc *);
void	atw_cardbus_disable(struct atw_softc *);
void	atw_cardbus_power(struct atw_softc *, int);

const struct pci_matchid atw_cardbus_devices[] = {
	{ PCI_VENDOR_ADMTEK, PCI_PRODUCT_ADMTEK_ADM8211 },
	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CRSHPW796 },
};

int
atw_cardbus_match(struct device *parent, void *match, void *aux)
{
	return (cardbus_matchbyid((struct cardbus_attach_args *)aux,
	    atw_cardbus_devices, nitems(atw_cardbus_devices)));
}

void
atw_cardbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct atw_cardbus_softc *csc = (void *)self;
	struct atw_softc *sc = &csc->sc_atw;
	struct cardbus_attach_args *ca = aux;
	cardbus_devfunc_t ct = ca->ca_ct;
	bus_addr_t adr;

	sc->sc_dmat = ca->ca_dmat;
	csc->sc_ct = ct;
	csc->sc_tag = ca->ca_tag;
	csc->sc_pc = ca->ca_pc;

	/*
	 * Power management hooks.
	 */
	sc->sc_enable = atw_cardbus_enable;
	sc->sc_disable = atw_cardbus_disable;
	sc->sc_power = atw_cardbus_power;

	/* Get revision info. */
	sc->sc_rev = PCI_REVISION(ca->ca_class);

#if 0
	printf(": signature %08x\n%s",
	    pci_conf_read(ca->ca_pc, csc->sc_tag, 0x80),
	    sc->sc_dev.dv_xname);
#endif

	/*
	 * Map the device.
	 */
	csc->sc_csr = PCI_COMMAND_MASTER_ENABLE;
	if (Cardbus_mapreg_map(ct, ATW_PCI_MMBA,
	    PCI_MAPREG_TYPE_MEM, 0, &sc->sc_st, &sc->sc_sh, &adr,
	    &csc->sc_mapsize) == 0) {
#if 0
		printf(": atw_cardbus_attach mapped %d bytes mem space\n%s",
		    csc->sc_mapsize, sc->sc_dev.dv_xname);
#endif
		csc->sc_cben = CARDBUS_MEM_ENABLE;
		csc->sc_csr |= PCI_COMMAND_MEM_ENABLE;
		csc->sc_bar_reg = ATW_PCI_MMBA;
		csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM;
	} else if (Cardbus_mapreg_map(ct, ATW_PCI_IOBA,
	    PCI_MAPREG_TYPE_IO, 0, &sc->sc_st, &sc->sc_sh, &adr,
	    &csc->sc_mapsize) == 0) {
#if 0
		printf(": atw_cardbus_attach mapped %d bytes I/O space\n%s",
		    csc->sc_mapsize, sc->sc_dev.dv_xname);
#endif
		csc->sc_cben = CARDBUS_IO_ENABLE;
		csc->sc_csr |= PCI_COMMAND_IO_ENABLE;
		csc->sc_bar_reg = ATW_PCI_IOBA;
		csc->sc_bar_val = adr | PCI_MAPREG_TYPE_IO;
	} else {
		printf(": unable to map device registers\n");
		return;
	}

	/*
	 * Bring the chip out of powersave mode and initialize the
	 * configuration registers.
	 */
	atw_cardbus_setup(csc);

	/* Remember which interrupt line. */
	csc->sc_intrline = ca->ca_intrline;

	printf(": revision %d.%d: irq %d\n",
	    (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf, csc->sc_intrline);
#if 0
	/*
	 * The CardBus cards will make it to store-and-forward mode as
	 * soon as you put them under any kind of load, so just start
	 * out there.
	 */
	sc->sc_txthresh = 3; /* TBD name constant */
#endif

	/*
	 * Finish off the attach.
	 */
	atw_attach(sc);

	ATW_WRITE(sc, ATW_FER, ATW_FER_INTR);

	/*
	 * Power down the socket.
	 */
	Cardbus_function_disable(csc->sc_ct);
}

int
atw_cardbus_detach(struct device *self, int flags)
{
	struct atw_cardbus_softc *csc = (void *)self;
	struct atw_softc *sc = &csc->sc_atw;
	struct cardbus_devfunc *ct = csc->sc_ct;
	int rv;

#if defined(DIAGNOSTIC)
	if (ct == NULL)
		panic("%s: data structure lacks", sc->sc_dev.dv_xname);
#endif

	rv = atw_detach(sc);
	if (rv)
		return (rv);

	/*
	 * Unhook the interrupt handler.
	 */
	if (csc->sc_ih != NULL)
		cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih);

	/*
	 * Release bus space and close window.
	 */
	if (csc->sc_bar_reg != 0)
		Cardbus_mapreg_unmap(ct, csc->sc_bar_reg,
		    sc->sc_st, sc->sc_sh, csc->sc_mapsize);

	return (0);
}

int
atw_cardbus_enable(struct atw_softc *sc)
{
	struct atw_cardbus_softc *csc = (void *) sc;
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;

	/*
	 * Power on the socket.
	 */
	Cardbus_function_enable(ct);

	/*
	 * Set up the PCI configuration registers.
	 */
	atw_cardbus_setup(csc);

	/*
	 * Map and establish the interrupt.
	 */
	csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
	    atw_intr, sc, sc->sc_dev.dv_xname);
	if (csc->sc_ih == NULL) {
		printf("%s: unable to establish interrupt at %d\n",
		    sc->sc_dev.dv_xname, csc->sc_intrline);
		Cardbus_function_disable(csc->sc_ct);
		return (1);
	}

	return (0);
}

void
atw_cardbus_disable(struct atw_softc *sc)
{
	struct atw_cardbus_softc *csc = (void *) sc;
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;

	/* Unhook the interrupt handler. */
	cardbus_intr_disestablish(cc, cf, csc->sc_ih);
	csc->sc_ih = NULL;

	/* Power down the socket. */
	Cardbus_function_disable(ct);
}

void
atw_cardbus_power(struct atw_softc *sc, int why)
{
	if (why == DVACT_RESUME)
		atw_enable(sc);
}

void
atw_cardbus_setup(struct atw_cardbus_softc *csc)
{
#ifdef notyet
	struct atw_softc *sc = &csc->sc_atw;
#endif
	cardbus_devfunc_t ct = csc->sc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	pci_chipset_tag_t pc = csc->sc_pc;
	pcireg_t reg;

#ifdef notyet
	(void)cardbus_setpowerstate(sc->sc_dev.dv_xname, ct, csc->sc_tag,
	    PCI_PWR_D0);
#endif

	/* Program the BAR. */
	pci_conf_write(pc, csc->sc_tag, csc->sc_bar_reg,
	    csc->sc_bar_val);

	/* Make sure the right access type is on the CardBus bridge. */
	(*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben);
	(*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);

	/* Enable the appropriate bits in the PCI CSR. */
	reg = pci_conf_read(pc, csc->sc_tag,
	    PCI_COMMAND_STATUS_REG);
	reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE);
	reg |= csc->sc_csr;
	pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
	    reg);

	/*
	 * Make sure the latency timer is set to some reasonable
	 * value.
	 */
	reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG);
	if (PCI_LATTIMER(reg) < 0x20) {
		reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
		reg |= (0x20 << PCI_LATTIMER_SHIFT);
		pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg);
	}
}


code:
/*	$OpenBSD: if_bwi_cardbus.c,v 1.15 2013/12/06 21:03:02 deraadt Exp $ */

/*
 * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org>
 * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Cardbus front-end for the Broadcom AirForce
 */

#include "bpfilter.h"

#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/systm.h>
#include <sys/timeout.h>

#include <net/if.h>
#include <net/if_media.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_radiotap.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <dev/cardbus/cardbusvar.h>

#include <dev/ic/bwivar.h>

struct bwi_cardbus_softc {
	struct bwi_softc	 csc_bwi;

	/* cardbus specific goo */
	cardbus_devfunc_t	 csc_ct;
	pcitag_t		 csc_tag;
	void			*csc_ih;

	bus_size_t		 csc_mapsize;
	pcireg_t		 csc_bar_val;
	int			 csc_intrline;
	pci_chipset_tag_t	 csc_pc;
};

int		bwi_cardbus_match(struct device *, void *, void*);
void		bwi_cardbus_attach(struct device *, struct device *, void *);
int		bwi_cardbus_detach(struct device *, int);
void		bwi_cardbus_setup(struct bwi_cardbus_softc *);
int		bwi_cardbus_enable(struct bwi_softc *);
void		bwi_cardbus_disable(struct bwi_softc *);
void		bwi_cardbus_conf_write(void *, uint32_t, uint32_t);
uint32_t	bwi_cardbus_conf_read(void *, uint32_t);

struct cfattach bwi_cardbus_ca = {
	sizeof (struct bwi_cardbus_softc), bwi_cardbus_match,
	bwi_cardbus_attach, bwi_cardbus_detach
};

static const struct pci_matchid bwi_cardbus_devices[] = {
	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4303 },
	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306 },
	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306_2 },
	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4307 },
	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4309 },
	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4318 },
	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4319 },
	{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43XG }
};

int
bwi_cardbus_match(struct device *parent, void *match, void *aux)
{
	return (cardbus_matchbyid(aux, bwi_cardbus_devices,
	    sizeof (bwi_cardbus_devices) / sizeof (bwi_cardbus_devices[0])));
}

void
bwi_cardbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self;
	struct cardbus_attach_args *ca = aux;
	struct bwi_softc *sc = &csc->csc_bwi;
	cardbus_devfunc_t ct = ca->ca_ct;
	pcireg_t reg;
	bus_addr_t base;
	int error;

	sc->sc_dmat = ca->ca_dmat;
	csc->csc_ct = ct;
	csc->csc_tag = ca->ca_tag;
	csc->csc_intrline = ca->ca_intrline;
	csc->csc_pc = ca->ca_pc;

	/* power management hooks */
	sc->sc_enable = bwi_cardbus_enable;
	sc->sc_disable = bwi_cardbus_disable;
	//sc->sc_power = bwi_cardbus_power;

	/* map control/status registers */
	error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG,
	    PCI_MAPREG_TYPE_MEM, 0, &sc->sc_mem_bt,
	    &sc->sc_mem_bh, &base, &csc->csc_mapsize);
	if (error != 0) {
		printf(": can't map mem space\n");
		return;
	}
	csc->csc_bar_val = base | PCI_MAPREG_TYPE_MEM;

	/* set up the PCI configuration registers */
	bwi_cardbus_setup(csc);

	printf(": irq %d", csc->csc_intrline);

	/* we need to access Cardbus config space from the driver */
	sc->sc_conf_read = bwi_cardbus_conf_read;
	sc->sc_conf_write = bwi_cardbus_conf_write;

	reg = (sc->sc_conf_read)(sc, PCI_SUBSYS_ID_REG);

	sc->sc_pci_revid = PCI_REVISION(ca->ca_class);
	sc->sc_pci_did = PCI_PRODUCT(ca->ca_id);
	sc->sc_pci_subvid = PCI_VENDOR(reg);
	sc->sc_pci_subdid = PCI_PRODUCT(reg);

	error = bwi_attach(sc);
	if (error != 0)
		bwi_cardbus_detach(&sc->sc_dev, 0);

	Cardbus_function_disable(ct);
}

int
bwi_cardbus_detach(struct device *self, int flags)
{
	struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self;
	struct bwi_softc *sc = &csc->csc_bwi;
	cardbus_devfunc_t ct = csc->csc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;
	int error;

	error = bwi_detach(sc);
	if (error != 0)
		return (error);

	/* unhook the interrupt handler */
	if (csc->csc_ih != NULL) {
		cardbus_intr_disestablish(cc, cf, csc->csc_ih);
		csc->csc_ih = NULL;
	}

	/* release bus space and close window */
	Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, sc->sc_mem_bt,
	    sc->sc_mem_bh, csc->csc_mapsize);

	return (0);
}

void
bwi_cardbus_setup(struct bwi_cardbus_softc *csc)
{
	cardbus_devfunc_t ct = csc->csc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	pci_chipset_tag_t pc = csc->csc_pc;
	cardbus_function_tag_t cf = ct->ct_cf;
	pcireg_t reg;

	/* program the BAR */
	pci_conf_write(pc, csc->csc_tag, CARDBUS_BASE0_REG,
	    csc->csc_bar_val);

	/* make sure the right access type is on the cardbus bridge */
	(*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
	(*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);

	/* enable the appropriate bits in the PCI CSR */
	reg = pci_conf_read(pc, csc->csc_tag,
	    PCI_COMMAND_STATUS_REG);
	reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
	pci_conf_write(pc, csc->csc_tag, PCI_COMMAND_STATUS_REG,
	    reg);
}

int
bwi_cardbus_enable(struct bwi_softc *sc)
{
	struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)sc;
	cardbus_devfunc_t ct = csc->csc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;

	/* power on the socket */
	Cardbus_function_enable(ct);

	/* setup the PCI configuration registers */
	bwi_cardbus_setup(csc);

	/* map and establish the interrupt handler */
	csc->csc_ih = cardbus_intr_establish(cc, cf, csc->csc_intrline, IPL_NET,
	    bwi_intr, sc, sc->sc_dev.dv_xname);
	if (csc->csc_ih == NULL) {
		printf("%s: could not establish interrupt at %d\n",
		    sc->sc_dev.dv_xname, csc->csc_intrline);
		Cardbus_function_disable(ct);
		return (1);
	}

	return (0);
}

void
bwi_cardbus_disable(struct bwi_softc *sc)
{
	struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)sc;
	cardbus_devfunc_t ct = csc->csc_ct;
	cardbus_chipset_tag_t cc = ct->ct_cc;
	cardbus_function_tag_t cf = ct->ct_cf;

	/* unhook the interrupt handler */
	cardbus_intr_disestablish(cc, cf, csc->csc_ih);
	csc->csc_ih = NULL;

	/* power down the socket */
	Cardbus_function_disable(ct);
}

void
bwi_cardbus_conf_write(void *self, uint32_t reg, uint32_t val)
{
	struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self;
	pci_chipset_tag_t pc = csc->csc_pc;

	pci_conf_write(pc, csc->csc_tag, reg, val);
}

uint32_t
bwi_cardbus_conf_read(void *self, uint32_t reg)
{
	struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self;
	pci_chipset_tag_t pc = csc->csc_pc;

	return (pci_conf_read(pc, csc->csc_tag, reg));
}