1139749Simp/*-
2124137Simp * Copyright (c) 2002-2004 M. Warner Losh.
3124137Simp * Copyright (c) 2000-2001 Jonathan Chen.
467276Sjon * All rights reserved.
567276Sjon *
667276Sjon * Redistribution and use in source and binary forms, with or without
767276Sjon * modification, are permitted provided that the following conditions
867276Sjon * are met:
967276Sjon * 1. Redistributions of source code must retain the above copyright
10140197Simp *    notice, this list of conditions and the following disclaimer.
1167276Sjon * 2. Redistributions in binary form must reproduce the above copyright
12140197Simp *    notice, this list of conditions and the following disclaimer in the
13140197Simp *    documentation and/or other materials provided with the distribution.
1467276Sjon *
1567276Sjon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1667276Sjon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1767276Sjon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18140197Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19140197Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2067276Sjon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2167276Sjon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2267276Sjon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2367276Sjon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2467276Sjon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2567276Sjon * SUCH DAMAGE.
26140197Simp *
2767276Sjon */
2867276Sjon
29140036Simp/*-
3094570Simp * Copyright (c) 1998, 1999 and 2000
3194570Simp *      HAYAKAWA Koichi.  All rights reserved.
3294570Simp *
3394570Simp * Redistribution and use in source and binary forms, with or without
3494570Simp * modification, are permitted provided that the following conditions
3594570Simp * are met:
3694570Simp * 1. Redistributions of source code must retain the above copyright
3794570Simp *    notice, this list of conditions and the following disclaimer.
3894570Simp * 2. Redistributions in binary form must reproduce the above copyright
3994570Simp *    notice, this list of conditions and the following disclaimer in the
4094570Simp *    documentation and/or other materials provided with the distribution.
4194570Simp * 3. All advertising materials mentioning features or use of this software
4294570Simp *    must display the following acknowledgement:
4394570Simp *	This product includes software developed by HAYAKAWA Koichi.
4494570Simp * 4. The name of the author may not be used to endorse or promote products
4594570Simp *    derived from this software without specific prior written permission.
4694570Simp *
4794570Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4894570Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4994570Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5094570Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
5194570Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
5294570Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5394570Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5494570Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5594570Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
5694570Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5794570Simp */
5894570Simp
5994570Simp/*
60104830Simp * Driver for PCI to CardBus Bridge chips
61133553Simp * and PCI to PCMCIA Bridge chips
62133553Simp * and ISA to PCMCIA host adapters
63133553Simp * and C Bus to PCMCIA host adapters
6467276Sjon *
6567276Sjon * References:
6667276Sjon *  TI Datasheets:
6767276Sjon *   http://www-s.ti.com/cgi-bin/sc/generic2.cgi?family=PCI+CARDBUS+CONTROLLERS
6867276Sjon *
6967276Sjon * Written by Jonathan Chen <jon@freebsd.org>
7067276Sjon * The author would like to acknowledge:
7167276Sjon *  * HAYAKAWA Koichi: Author of the NetBSD code for the same thing
7267276Sjon *  * Warner Losh: Newbus/newcard guru and author of the pccard side of things
7367276Sjon *  * YAMAMOTO Shigeru: Author of another FreeBSD cardbus driver
7467276Sjon *  * David Cross: Author of the initial ugly hack for a specific cardbus card
7567276Sjon */
7667276Sjon
77122534Simp#include <sys/cdefs.h>
78122534Simp__FBSDID("$FreeBSD$");
79122534Simp
8067276Sjon#include <sys/param.h>
81133553Simp#include <sys/bus.h>
8298156Simp#include <sys/condvar.h>
8367276Sjon#include <sys/errno.h>
8467276Sjon#include <sys/kernel.h>
85129876Sphk#include <sys/module.h>
86133553Simp#include <sys/kthread.h>
87170163Spiso#include <sys/interrupt.h>
8875021Sjesper#include <sys/lock.h>
8967276Sjon#include <sys/malloc.h>
9069288Sjon#include <sys/mutex.h>
91133553Simp#include <sys/proc.h>
92133553Simp#include <sys/rman.h>
9386908Simp#include <sys/sysctl.h>
94133553Simp#include <sys/systm.h>
9567276Sjon#include <machine/bus.h>
9667276Sjon#include <machine/resource.h>
9767276Sjon
98119285Simp#include <dev/pci/pcireg.h>
99119285Simp#include <dev/pci/pcivar.h>
10067276Sjon
10167276Sjon#include <dev/pccard/pccardreg.h>
10267276Sjon#include <dev/pccard/pccardvar.h>
10367276Sjon
10489949Simp#include <dev/exca/excareg.h>
10589949Simp#include <dev/exca/excavar.h>
10689949Simp
10767276Sjon#include <dev/pccbb/pccbbreg.h>
10867276Sjon#include <dev/pccbb/pccbbvar.h>
10967276Sjon
11067276Sjon#include "power_if.h"
11167276Sjon#include "card_if.h"
11267276Sjon#include "pcib_if.h"
11367276Sjon
11490751Simp#define	DPRINTF(x) do { if (cbb_debug) printf x; } while (0)
11590751Simp#define	DEVPRINTF(x) do { if (cbb_debug) device_printf x; } while (0)
11667276Sjon
11782378Sjon#define	PCI_MASK_CONFIG(DEV,REG,MASK,SIZE)				\
11867276Sjon	pci_write_config(DEV, REG, pci_read_config(DEV, REG, SIZE) MASK, SIZE)
11967276Sjon#define	PCI_MASK2_CONFIG(DEV,REG,MASK1,MASK2,SIZE)			\
12067276Sjon	pci_write_config(DEV, REG, (					\
12167276Sjon		pci_read_config(DEV, REG, SIZE) MASK1) MASK2, SIZE)
12267276Sjon
123119165Simp#define CBB_CARD_PRESENT(s) ((s & CBB_STATE_CD) == 0)
124119165Simp
125101904Simp#define CBB_START_MEM	0x88000000
126101904Simp#define CBB_START_32_IO 0x1000
127101904Simp#define CBB_START_16_IO 0x100
12886899Simp
129133553Simpdevclass_t cbb_devclass;
13067276Sjon
13186908Simp/* sysctl vars */
132227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, cbb, CTLFLAG_RD, 0, "CBB parameters");
13386908Simp
13486908Simp/* There's no way to say TUNEABLE_LONG to get the right types */
135101904Simpu_long cbb_start_mem = CBB_START_MEM;
136155316SimpTUNABLE_ULONG("hw.cbb.start_memory", &cbb_start_mem);
13795709SimpSYSCTL_ULONG(_hw_cbb, OID_AUTO, start_memory, CTLFLAG_RW,
138101904Simp    &cbb_start_mem, CBB_START_MEM,
13986908Simp    "Starting address for memory allocations");
14086908Simp
141101904Simpu_long cbb_start_16_io = CBB_START_16_IO;
142155316SimpTUNABLE_ULONG("hw.cbb.start_16_io", &cbb_start_16_io);
14395708SimpSYSCTL_ULONG(_hw_cbb, OID_AUTO, start_16_io, CTLFLAG_RW,
144101904Simp    &cbb_start_16_io, CBB_START_16_IO,
14590751Simp    "Starting ioport for 16-bit cards");
14690751Simp
147101904Simpu_long cbb_start_32_io = CBB_START_32_IO;
148155316SimpTUNABLE_ULONG("hw.cbb.start_32_io", &cbb_start_32_io);
14995708SimpSYSCTL_ULONG(_hw_cbb, OID_AUTO, start_32_io, CTLFLAG_RW,
150101904Simp    &cbb_start_32_io, CBB_START_32_IO,
15190751Simp    "Starting ioport for 32-bit cards");
15290751Simp
15390751Simpint cbb_debug = 0;
15490751SimpTUNABLE_INT("hw.cbb.debug", &cbb_debug);
155217323SmdfSYSCTL_INT(_hw_cbb, OID_AUTO, debug, CTLFLAG_RW, &cbb_debug, 0,
15690751Simp    "Verbose cardbus bridge debugging");
15790751Simp
158101904Simpstatic void	cbb_insert(struct cbb_softc *sc);
159101904Simpstatic void	cbb_removal(struct cbb_softc *sc);
160148013Simpstatic uint32_t	cbb_detect_voltage(device_t brdev);
161189723Simpstatic void	cbb_cardbus_reset_power(device_t brdev, device_t child, int on);
162101904Simpstatic int	cbb_cardbus_io_open(device_t brdev, int win, uint32_t start,
16389326Simp		    uint32_t end);
164101904Simpstatic int	cbb_cardbus_mem_open(device_t brdev, int win,
16589326Simp		    uint32_t start, uint32_t end);
166101904Simpstatic void	cbb_cardbus_auto_open(struct cbb_softc *sc, int type);
167101904Simpstatic int	cbb_cardbus_activate_resource(device_t brdev, device_t child,
16882378Sjon		    int type, int rid, struct resource *res);
169101904Simpstatic int	cbb_cardbus_deactivate_resource(device_t brdev,
17082378Sjon		    device_t child, int type, int rid, struct resource *res);
171101904Simpstatic struct resource	*cbb_cardbus_alloc_resource(device_t brdev,
17282375Sjon		    device_t child, int type, int *rid, u_long start,
173118607Sjhb		    u_long end, u_long count, u_int flags);
174101904Simpstatic int	cbb_cardbus_release_resource(device_t brdev, device_t child,
17582378Sjon		    int type, int rid, struct resource *res);
176133553Simpstatic int	cbb_cardbus_power_enable_socket(device_t brdev,
177133553Simp		    device_t child);
178188129Simpstatic int	cbb_cardbus_power_disable_socket(device_t brdev,
179133553Simp		    device_t child);
180170163Spisostatic int	cbb_func_filt(void *arg);
181133553Simpstatic void	cbb_func_intr(void *arg);
18267276Sjon
18389949Simpstatic void
184101904Simpcbb_remove_res(struct cbb_softc *sc, struct resource *res)
18589949Simp{
186101904Simp	struct cbb_reslist *rle;
18789949Simp
18889949Simp	SLIST_FOREACH(rle, &sc->rl, link) {
18989949Simp		if (rle->res == res) {
190101904Simp			SLIST_REMOVE(&sc->rl, rle, cbb_reslist, link);
19189949Simp			free(rle, M_DEVBUF);
19289949Simp			return;
19389949Simp		}
19489949Simp	}
19589949Simp}
19689949Simp
19789949Simpstatic struct resource *
198101904Simpcbb_find_res(struct cbb_softc *sc, int type, int rid)
19989949Simp{
200101904Simp	struct cbb_reslist *rle;
20189949Simp
20289949Simp	SLIST_FOREACH(rle, &sc->rl, link)
20389949Simp		if (SYS_RES_MEMORY == rle->type && rid == rle->rid)
20489949Simp			return (rle->res);
20589949Simp	return (NULL);
20689949Simp}
20789949Simp
20889949Simpstatic void
209101904Simpcbb_insert_res(struct cbb_softc *sc, struct resource *res, int type,
21089949Simp    int rid)
21189949Simp{
212101904Simp	struct cbb_reslist *rle;
21389949Simp
21489949Simp	/*
21589949Simp	 * Need to record allocated resource so we can iterate through
21689949Simp	 * it later.
21789949Simp	 */
218101904Simp	rle = malloc(sizeof(struct cbb_reslist), M_DEVBUF, M_NOWAIT);
219122534Simp	if (rle == NULL)
220101904Simp		panic("cbb_cardbus_alloc_resource: can't record entry!");
22189949Simp	rle->res = res;
22289949Simp	rle->type = type;
22389949Simp	rle->rid = rid;
22489949Simp	SLIST_INSERT_HEAD(&sc->rl, rle, link);
22589949Simp}
22689949Simp
22789949Simpstatic void
228101904Simpcbb_destroy_res(struct cbb_softc *sc)
22989949Simp{
230101904Simp	struct cbb_reslist *rle;
23189949Simp
23289949Simp	while ((rle = SLIST_FIRST(&sc->rl)) != NULL) {
23390751Simp		device_printf(sc->dev, "Danger Will Robinson: Resource "
23489949Simp		    "left allocated!  This is a bug... "
23589949Simp		    "(rid=%x, type=%d, addr=%lx)\n", rle->rid, rle->type,
23689949Simp		    rman_get_start(rle->res));
23789949Simp		SLIST_REMOVE_HEAD(&sc->rl, link);
23889949Simp		free(rle, M_DEVBUF);
23989949Simp	}
24089949Simp}
24189949Simp
242118713Simp/*
243118713Simp * Disable function interrupts by telling the bridge to generate IRQ1
244118713Simp * interrupts.  These interrupts aren't really generated by the chip, since
245118713Simp * IRQ1 is reserved.  Some chipsets assert INTA# inappropriately during
246118713Simp * initialization, so this helps to work around the problem.
247122263Simp *
248122263Simp * XXX We can't do this workaround for all chipsets, because this
249122263Simp * XXX causes interference with the keyboard because somechipsets will
250122263Simp * XXX actually signal IRQ1 over their serial interrupt connections to
251122263Simp * XXX the south bridge.  Disable it it for now.
252118713Simp */
253133553Simpvoid
254118713Simpcbb_disable_func_intr(struct cbb_softc *sc)
255118713Simp{
256122291Simp#if 0
257118713Simp	uint8_t reg;
258118713Simp
259133553Simp	reg = (exca_getb(&sc->exca[0], EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) |
260118713Simp	    EXCA_INTR_IRQ_RESERVED1;
261133553Simp	exca_putb(&sc->exca[0], EXCA_INTR, reg);
262122263Simp#endif
263118713Simp}
264118713Simp
265118713Simp/*
266118713Simp * Enable function interrupts.  We turn on function interrupts when the card
267118713Simp * requests an interrupt.  The PCMCIA standard says that we should set
268118713Simp * the lower 4 bits to 0 to route via PCI.  Note: we call this for both
269118713Simp * CardBus and R2 (PC Card) cases, but it should have no effect on CardBus
270118713Simp * cards.
271118713Simp */
272118713Simpstatic void
273118713Simpcbb_enable_func_intr(struct cbb_softc *sc)
274118713Simp{
275118713Simp	uint8_t reg;
276118713Simp
277133553Simp	reg = (exca_getb(&sc->exca[0], EXCA_INTR) & ~EXCA_INTR_IRQ_MASK) |
278118713Simp	    EXCA_INTR_IRQ_NONE;
279133553Simp	exca_putb(&sc->exca[0], EXCA_INTR, reg);
280118713Simp}
281118713Simp
282133553Simpint
283101904Simpcbb_detach(device_t brdev)
28469288Sjon{
285101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
28669288Sjon	device_t *devlist;
287166741Simp	int tmp, tries, error, numdevs;
28869288Sjon
289155434Simp	/*
290155434Simp	 * Before we delete the children (which we have to do because
291155434Simp	 * attach doesn't check for children busses correctly), we have
292155434Simp	 * to detach the children.  Even if we didn't need to delete the
293155434Simp	 * children, we have to detach them.
294155434Simp	 */
295155434Simp	error = bus_generic_detach(brdev);
296155434Simp	if (error != 0)
297155434Simp		return (error);
298155434Simp
299155434Simp	/*
300155434Simp	 * Since the attach routine doesn't search for children before it
301155434Simp	 * attaches them to this device, we must delete them here in order
302155434Simp	 * for the kldload/unload case to work.  If we failed to do that, then
303155434Simp	 * we'd get duplicate devices when cbb.ko was reloaded.
304155434Simp	 */
305166741Simp	tries = 10;
306166741Simp	do {
307166741Simp		error = device_get_children(brdev, &devlist, &numdevs);
308166741Simp		if (error == 0)
309166741Simp			break;
310166741Simp		/*
311166741Simp		 * Try hard to cope with low memory.
312166741Simp		 */
313166741Simp		if (error == ENOMEM) {
314167087Sjhb			pause("cbbnomem", 1);
315166741Simp			continue;
316166741Simp		}
317166741Simp	} while (tries-- > 0);
318155434Simp	for (tmp = 0; tmp < numdevs; tmp++)
319155434Simp		device_delete_child(brdev, devlist[tmp]);
32072189Simp	free(devlist, M_TEMP);
32169288Sjon
322151837Simp	/* Turn off the interrupts */
323151837Simp	cbb_set(sc, CBB_SOCKET_MASK, 0);
324151837Simp
325151837Simp	/* reset 16-bit pcmcia bus */
326151837Simp	exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET);
327151837Simp
328151837Simp	/* turn off power */
329151837Simp	cbb_power(brdev, CARD_OFF);
330151837Simp
331151837Simp	/* Ack the interrupt */
332151837Simp	cbb_set(sc, CBB_SOCKET_EVENT, 0xffffffff);
333151837Simp
334151078Simp	/*
335172836Sjulian	 * Wait for the thread to die.  kproc_exit will do a wakeup
336151078Simp	 * on the event thread's struct thread * so that we know it is
337169618Simp	 * safe to proceed.  IF the thread is running, set the please
338151078Simp	 * die flag and wait for it to comply.  Since the wakeup on
339172836Sjulian	 * the event thread happens only in kproc_exit, we don't
340151078Simp	 * need to loop here.
341151078Simp	 */
342169618Simp	bus_teardown_intr(brdev, sc->irq_res, sc->intrhand);
343151837Simp	mtx_lock(&sc->mtx);
344101904Simp	sc->flags |= CBB_KTHREAD_DONE;
345158891Simp	while (sc->flags & CBB_KTHREAD_RUNNING) {
346158891Simp		DEVPRINTF((sc->dev, "Waiting for thread to die\n"));
347185625Simp		wakeup(&sc->intrhand);
348104651Simp		msleep(sc->event_thread, &sc->mtx, PWAIT, "cbbun", 0);
34986904Simp	}
350104651Simp	mtx_unlock(&sc->mtx);
35169288Sjon
35290751Simp	bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res);
353129531Simp	bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE,
354129531Simp	    sc->base_res);
35590751Simp	mtx_destroy(&sc->mtx);
35686904Simp	return (0);
35769288Sjon}
35869288Sjon
359133553Simpint
360101904Simpcbb_setup_intr(device_t dev, device_t child, struct resource *irq,
361166901Spiso  int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
362166901Spiso   void **cookiep)
36390444Simp{
364104642Simp	struct cbb_intrhand *ih;
365104642Simp	struct cbb_softc *sc = device_get_softc(dev);
366133553Simp	int err;
36790444Simp
368170163Spiso	if (filt == NULL && intr == NULL)
369170163Spiso		return (EINVAL);
370104642Simp	ih = malloc(sizeof(struct cbb_intrhand), M_DEVBUF, M_NOWAIT);
371104642Simp	if (ih == NULL)
372104642Simp		return (ENOMEM);
373104642Simp	*cookiep = ih;
374170163Spiso	ih->filt = filt;
375104642Simp	ih->intr = intr;
376104642Simp	ih->arg = arg;
377133553Simp	ih->sc = sc;
37890444Simp	/*
37990444Simp	 * XXX need to turn on ISA interrupts, if we ever support them, but
38090444Simp	 * XXX for now that's all we need to do.
38190444Simp	 */
382133553Simp	err = BUS_SETUP_INTR(device_get_parent(dev), child, irq, flags,
383170270Simp	    filt ? cbb_func_filt : NULL, intr ? cbb_func_intr : NULL, ih,
384170270Simp	    &ih->cookie);
385133553Simp	if (err != 0) {
386133553Simp		free(ih, M_DEVBUF);
387133553Simp		return (err);
388133553Simp	}
389133553Simp	cbb_enable_func_intr(sc);
390170272Simp	sc->cardok = 1;
391133553Simp	return 0;
39290444Simp}
39390444Simp
394133553Simpint
395101904Simpcbb_teardown_intr(device_t dev, device_t child, struct resource *irq,
39690444Simp    void *cookie)
39790444Simp{
398104642Simp	struct cbb_intrhand *ih;
399133553Simp	int err;
400104642Simp
40190444Simp	/* XXX Need to do different things for ISA interrupts. */
402104642Simp	ih = (struct cbb_intrhand *) cookie;
403133553Simp	err = BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq,
404133553Simp	    ih->cookie);
405133553Simp	if (err != 0)
406133553Simp		return (err);
407104642Simp	free(ih, M_DEVBUF);
408104642Simp	return (0);
40990444Simp}
41090444Simp
41190444Simp
412133553Simpvoid
413101904Simpcbb_driver_added(device_t brdev, driver_t *driver)
41469288Sjon{
415101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
41669288Sjon	device_t *devlist;
417113239Simp	device_t dev;
41869288Sjon	int tmp;
41969288Sjon	int numdevs;
420113239Simp	int wake = 0;
42170715Sjon
42282375Sjon	DEVICE_IDENTIFY(driver, brdev);
423166741Simp	tmp = device_get_children(brdev, &devlist, &numdevs);
424166741Simp	if (tmp != 0) {
425166741Simp		device_printf(brdev, "Cannot get children list, no reprobe\n");
426166741Simp		return;
427166741Simp	}
42869288Sjon	for (tmp = 0; tmp < numdevs; tmp++) {
429113239Simp		dev = devlist[tmp];
430113239Simp		if (device_get_state(dev) == DS_NOTPRESENT &&
431166742Simp		    device_probe_and_attach(dev) == 0)
432113239Simp			wake++;
43369288Sjon	}
43472189Simp	free(devlist, M_TEMP);
43582378Sjon
436185625Simp	if (wake > 0)
437185625Simp		wakeup(&sc->intrhand);
43869288Sjon}
43969288Sjon
440133553Simpvoid
441101904Simpcbb_child_detached(device_t brdev, device_t child)
44269288Sjon{
443101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
44486904Simp
445166742Simp	/* I'm not sure we even need this */
446166742Simp	if (child != sc->cbdev && child != sc->exca[0].pccarddev)
447113239Simp		device_printf(brdev, "Unknown child detached: %s\n",
448113239Simp		    device_get_nameunit(child));
44969288Sjon}
45069288Sjon
45167276Sjon/************************************************************************/
45267276Sjon/* Kthreads								*/
45367276Sjon/************************************************************************/
45467276Sjon
455133553Simpvoid
456101904Simpcbb_event_thread(void *arg)
45767276Sjon{
458101904Simp	struct cbb_softc *sc = arg;
45989326Simp	uint32_t status;
46090751Simp	int err;
461118706Simp	int not_a_card = 0;
46267276Sjon
463230626Simp	/*
464230626Simp	 * We need to act as a power sequencer on startup.  Delay 2s/channel
465230626Simp	 * to ensure the other channels have had a chance to come up.  We likely
466230626Simp	 * should add a lock that's shared on a per-slot basis so that only
467230626Simp	 * one power event can happen per slot at a time.
468230626Simp	 */
469230626Simp	pause("cbbstart", hz * device_get_unit(sc->dev) * 2);
470158891Simp	mtx_lock(&sc->mtx);
471101904Simp	sc->flags |= CBB_KTHREAD_RUNNING;
472116232Simp	while ((sc->flags & CBB_KTHREAD_DONE) == 0) {
473169618Simp		mtx_unlock(&sc->mtx);
474196403Sjhb		/*
475196403Sjhb		 * We take out Giant here because we need it deep,
476196403Sjhb		 * down in the bowels of the vm system for mapping the
477196403Sjhb		 * memory we need to read the CIS.  In addition, since
478196403Sjhb		 * we are adding/deleting devices from the dev tree,
479196403Sjhb		 * and that code isn't MP safe, we have to hold Giant.
480196403Sjhb		 */
481196403Sjhb		mtx_lock(&Giant);
482101904Simp		status = cbb_get(sc, CBB_SOCKET_STATE);
483153945Simp		DPRINTF(("Status is 0x%x\n", status));
484119165Simp		if (!CBB_CARD_PRESENT(status)) {
485118713Simp			not_a_card = 0;		/* We know card type */
486118713Simp			cbb_removal(sc);
487118713Simp		} else if (status & CBB_STATE_NOT_A_CARD) {
488118706Simp			/*
489167208Simp			 * Up to 10 times, try to rescan the card when we see
490167208Simp			 * NOT_A_CARD.  10 is somehwat arbitrary.  When this
491167208Simp			 * pathology hits, there's a ~40% chance each try will
492167208Simp			 * fail.  10 tries takes about 5s and results in a
493167208Simp			 * 99.99% certainty of the results.
494118706Simp			 */
495167208Simp			if (not_a_card++ < 10) {
496118706Simp				DEVPRINTF((sc->dev,
497118706Simp				    "Not a card bit set, rescanning\n"));
498118706Simp				cbb_setb(sc, CBB_SOCKET_FORCE, CBB_FORCE_CV_TEST);
499118706Simp			} else {
500118706Simp				device_printf(sc->dev,
501118706Simp				    "Can't determine card type\n");
502118706Simp			}
503118706Simp		} else {
504118706Simp			not_a_card = 0;		/* We know card type */
505118713Simp			cbb_insert(sc);
506118706Simp		}
507196403Sjhb		mtx_unlock(&Giant);
508104651Simp
50990981Simp		/*
510188701Simp		 * First time through we need to tell mountroot that we're
511188701Simp		 * done.
512188701Simp		 */
513188701Simp		if (sc->sc_root_token) {
514188701Simp			root_mount_rel(sc->sc_root_token);
515188701Simp			sc->sc_root_token = NULL;
516188701Simp		}
517188701Simp
518188701Simp		/*
519167208Simp		 * Wait until it has been 250ms since the last time we
52090981Simp		 * get an interrupt.  We handle the rest of the interrupt
521116232Simp		 * at the top of the loop.  Although we clear the bit in the
522116232Simp		 * ISR, we signal sc->cv from the detach path after we've
523116232Simp		 * set the CBB_KTHREAD_DONE bit, so we can't do a simple
524167208Simp		 * 250ms sleep here.
525119061Simp		 *
526119061Simp		 * In our ISR, we turn off the card changed interrupt.  Turn
527119061Simp		 * them back on here before we wait for them to happen.  We
528119061Simp		 * turn them on/off so that we can tolerate a large latency
529119061Simp		 * between the time we signal cbb_event_thread and it gets
530119061Simp		 * a chance to run.
53190981Simp		 */
53298156Simp		mtx_lock(&sc->mtx);
533185625Simp		cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD | CBB_SOCKET_MASK_CSTS);
534185741Simp		msleep(&sc->intrhand, &sc->mtx, 0, "-", 0);
535104642Simp		err = 0;
536116232Simp		while (err != EWOULDBLOCK &&
537104642Simp		    (sc->flags & CBB_KTHREAD_DONE) == 0)
538185741Simp			err = msleep(&sc->intrhand, &sc->mtx, 0, "-", hz / 5);
53967276Sjon	}
540158891Simp	DEVPRINTF((sc->dev, "Thread terminating\n"));
541101904Simp	sc->flags &= ~CBB_KTHREAD_RUNNING;
542158891Simp	mtx_unlock(&sc->mtx);
543172836Sjulian	kproc_exit(0);
54467276Sjon}
54567276Sjon
54667276Sjon/************************************************************************/
54767276Sjon/* Insert/removal							*/
54867276Sjon/************************************************************************/
54967276Sjon
55067276Sjonstatic void
551101904Simpcbb_insert(struct cbb_softc *sc)
55267276Sjon{
55389326Simp	uint32_t sockevent, sockstate;
55467276Sjon
555104642Simp	sockevent = cbb_get(sc, CBB_SOCKET_EVENT);
556104642Simp	sockstate = cbb_get(sc, CBB_SOCKET_STATE);
55767276Sjon
55890751Simp	DEVPRINTF((sc->dev, "card inserted: event=0x%08x, state=%08x\n",
55982375Sjon	    sockevent, sockstate));
56067276Sjon
561118705Simp	if (sockstate & CBB_STATE_R2_CARD) {
562166742Simp		if (device_is_attached(sc->exca[0].pccarddev)) {
563133553Simp			sc->flags |= CBB_16BIT_CARD;
564133553Simp			exca_insert(&sc->exca[0]);
565148090Simp		} else {
566148090Simp			device_printf(sc->dev,
567148090Simp			    "16-bit card inserted, but no pccard bus.\n");
568133553Simp		}
569118705Simp	} else if (sockstate & CBB_STATE_CB_CARD) {
570166742Simp		if (device_is_attached(sc->cbdev)) {
571101904Simp			sc->flags &= ~CBB_16BIT_CARD;
572140037Simp			CARD_ATTACH_CARD(sc->cbdev);
57390751Simp		} else {
57490751Simp			device_printf(sc->dev,
575104830Simp			    "CardBus card inserted, but no cardbus bus.\n");
57690751Simp		}
57767276Sjon	} else {
57890751Simp		/*
57990751Simp		 * We should power the card down, and try again a couple of
58090751Simp		 * times if this happens. XXX
58190751Simp		 */
582110842Simp		device_printf(sc->dev, "Unsupported card type detected\n");
58367276Sjon	}
58467276Sjon}
58567276Sjon
58667276Sjonstatic void
587101904Simpcbb_removal(struct cbb_softc *sc)
58867276Sjon{
589170272Simp	sc->cardok = 0;
590106899Simp	if (sc->flags & CBB_16BIT_CARD) {
591133553Simp		exca_removal(&sc->exca[0]);
592106899Simp	} else {
593166742Simp		if (device_is_attached(sc->cbdev))
594106899Simp			CARD_DETACH_CARD(sc->cbdev);
595106899Simp	}
596101904Simp	cbb_destroy_res(sc);
59767276Sjon}
59867276Sjon
59967276Sjon/************************************************************************/
60067276Sjon/* Interrupt Handler							*/
60167276Sjon/************************************************************************/
60267276Sjon
603170163Spisostatic int
604170163Spisocbb_func_filt(void *arg)
605133553Simp{
606133553Simp	struct cbb_intrhand *ih = (struct cbb_intrhand *)arg;
607133553Simp	struct cbb_softc *sc = ih->sc;
608133553Simp
609133553Simp	/*
610133553Simp	 * Make sure that the card is really there.
611133553Simp	 */
612170272Simp	if (!sc->cardok)
613170163Spiso		return (FILTER_STRAY);
614133553Simp	if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) {
615170272Simp		sc->cardok = 0;
616170232Simp		return (FILTER_HANDLED);
617133553Simp	}
618133553Simp
619133553Simp	/*
620170232Simp	 * nb: don't have to check for giant or not, since that's done in the
621170232Simp	 * ISR dispatch and one can't hold Giant in a filter anyway...
622133553Simp	 */
623170270Simp	return ((*ih->filt)(ih->arg));
624133553Simp}
625133553Simp
626170163Spisostatic void
627170163Spisocbb_func_intr(void *arg)
628170163Spiso{
629170163Spiso	struct cbb_intrhand *ih = (struct cbb_intrhand *)arg;
630170232Simp	struct cbb_softc *sc = ih->sc;
631170163Spiso
632170232Simp	/*
633170232Simp	 * While this check may seem redundant, it helps close a race
634170232Simp	 * condition.  If the card is ejected after the filter runs, but
635170232Simp	 * before this ISR can be scheduled, then we need to do the same
636170232Simp	 * filtering to prevent the card's ISR from being called.  One could
637170232Simp	 * argue that the card's ISR should be able to cope, but experience
638170232Simp	 * has shown they can't always.  This mitigates the problem by making
639170232Simp	 * the race quite a bit smaller.  Properly written client ISRs should
640170232Simp	 * cope with the card going away in the middle of the ISR.  We assume
641170232Simp	 * that drivers that are sophisticated enough to use filters don't
642170232Simp	 * need our protection.  This also allows us to ensure they *ARE*
643170232Simp	 * called if their filter said they needed to be called.
644170232Simp	 */
645170232Simp	if (ih->filt == NULL) {
646170272Simp		if (!sc->cardok)
647170232Simp			return;
648170232Simp		if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) {
649170272Simp			sc->cardok = 0;
650170232Simp			return;
651170232Simp		}
652170232Simp	}
653170232Simp
654170232Simp	/*
655170232Simp	 * Call the registered ithread interrupt handler.  This entire routine
656170232Simp	 * will be called with Giant if this isn't an MP safe driver, or not
657170232Simp	 * if it is.  Either way, we don't have to worry.
658170232Simp	 */
659170163Spiso	ih->intr(ih->arg);
660170163Spiso}
661170163Spiso
66267276Sjon/************************************************************************/
66369288Sjon/* Generic Power functions						*/
66467276Sjon/************************************************************************/
66567276Sjon
666148013Simpstatic uint32_t
667101904Simpcbb_detect_voltage(device_t brdev)
66867276Sjon{
669101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
67089326Simp	uint32_t psr;
671148013Simp	uint32_t vol = CARD_UKN_CARD;
67267276Sjon
673101904Simp	psr = cbb_get(sc, CBB_SOCKET_STATE);
67467276Sjon
675157092Simp	if (psr & CBB_STATE_5VCARD && psr & CBB_STATE_5VSOCK)
67667276Sjon		vol |= CARD_5V_CARD;
677157092Simp	if (psr & CBB_STATE_3VCARD && psr & CBB_STATE_3VSOCK)
67867276Sjon		vol |= CARD_3V_CARD;
679157092Simp	if (psr & CBB_STATE_XVCARD && psr & CBB_STATE_XVSOCK)
68067276Sjon		vol |= CARD_XV_CARD;
681157092Simp	if (psr & CBB_STATE_YVCARD && psr & CBB_STATE_YVSOCK)
68267276Sjon		vol |= CARD_YV_CARD;
68367276Sjon
68486904Simp	return (vol);
68567276Sjon}
68667276Sjon
687115887Simpstatic uint8_t
688115887Simpcbb_o2micro_power_hack(struct cbb_softc *sc)
689115887Simp{
690115887Simp	uint8_t reg;
691115887Simp
692115887Simp	/*
693115887Simp	 * Issue #2: INT# not qualified with IRQ Routing Bit.  An
694150460Simp	 * unexpected PCI INT# may be generated during PC Card
695115887Simp	 * initialization even with the IRQ Routing Bit Set with some
696150460Simp	 * PC Cards.
697115887Simp	 *
698115887Simp	 * This is a two part issue.  The first part is that some of
699115887Simp	 * our older controllers have an issue in which the slot's PCI
700115887Simp	 * INT# is NOT qualified by the IRQ routing bit (PCI reg. 3Eh
701115887Simp	 * bit 7).  Regardless of the IRQ routing bit, if NO ISA IRQ
702115887Simp	 * is selected (ExCA register 03h bits 3:0, of the slot, are
703115887Simp	 * cleared) we will generate INT# if IREQ# is asserted.  The
704150460Simp	 * second part is because some PC Cards prematurally assert
705115887Simp	 * IREQ# before the ExCA registers are fully programmed.  This
706115887Simp	 * in turn asserts INT# because ExCA register 03h bits 3:0
707115887Simp	 * (ISA IRQ Select) are not yet programmed.
708115887Simp	 *
709115887Simp	 * The fix for this issue, which will work for any controller
710115887Simp	 * (old or new), is to set ExCA register 03h bits 3:0 = 0001b
711115887Simp	 * (select IRQ1), of the slot, before turning on slot power.
712115887Simp	 * Selecting IRQ1 will result in INT# NOT being asserted
713115887Simp	 * (because IRQ1 is selected), and IRQ1 won't be asserted
714115887Simp	 * because our controllers don't generate IRQ1.
715148090Simp	 *
716148090Simp	 * Other, non O2Micro controllers will generate irq 1 in some
717148105Simp	 * situations, so we can't do this hack for everybody.  Reports of
718148105Simp	 * keyboard controller's interrupts being suppressed occurred when
719148105Simp	 * we did this.
720115887Simp	 */
721133553Simp	reg = exca_getb(&sc->exca[0], EXCA_INTR);
722133553Simp	exca_putb(&sc->exca[0], EXCA_INTR, (reg & 0xf0) | 1);
723115887Simp	return (reg);
724115887Simp}
725115887Simp
726115887Simp/*
727115887Simp * Restore the damage that cbb_o2micro_power_hack does to EXCA_INTR so
728115887Simp * we don't have an interrupt storm on power on.  This has the efect of
729115887Simp * disabling card status change interrupts for the duration of poweron.
730115887Simp */
731115887Simpstatic void
732115887Simpcbb_o2micro_power_hack2(struct cbb_softc *sc, uint8_t reg)
733115887Simp{
734133553Simp	exca_putb(&sc->exca[0], EXCA_INTR, reg);
735115887Simp}
736115887Simp
737133553Simpint
738101904Simpcbb_power(device_t brdev, int volts)
73967276Sjon{
740161241Simp	uint32_t status, sock_ctrl, reg_ctrl, mask;
741101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
742148090Simp	int cnt, sane;
743115887Simp	int retval = 0;
744148013Simp	int on = 0;
745115887Simp	uint8_t reg = 0;
74667276Sjon
747101904Simp	sock_ctrl = cbb_get(sc, CBB_SOCKET_CONTROL);
74867276Sjon
749115986Simp	sock_ctrl &= ~CBB_SOCKET_CTRL_VCCMASK;
75067276Sjon	switch (volts & CARD_VCCMASK) {
751115986Simp	case 5:
752115986Simp		sock_ctrl |= CBB_SOCKET_CTRL_VCC_5V;
753148013Simp		on++;
75467276Sjon		break;
755115986Simp	case 3:
756115986Simp		sock_ctrl |= CBB_SOCKET_CTRL_VCC_3V;
757148013Simp		on++;
75867276Sjon		break;
759115986Simp	case XV:
760115986Simp		sock_ctrl |= CBB_SOCKET_CTRL_VCC_XV;
761148013Simp		on++;
76267276Sjon		break;
763115986Simp	case YV:
764115986Simp		sock_ctrl |= CBB_SOCKET_CTRL_VCC_YV;
765148013Simp		on++;
76667276Sjon		break;
767115986Simp	case 0:
768115986Simp		break;
76967276Sjon	default:
77086904Simp		return (0);			/* power NEVER changed */
77167276Sjon	}
77267276Sjon
773115986Simp	/* VPP == VCC */
774115986Simp	sock_ctrl &= ~CBB_SOCKET_CTRL_VPPMASK;
775115986Simp	sock_ctrl |= ((sock_ctrl >> 4) & 0x07);
77667276Sjon
777101904Simp	if (cbb_get(sc, CBB_SOCKET_CONTROL) == sock_ctrl)
77886904Simp		return (1); /* no change necessary */
779115986Simp	DEVPRINTF((sc->dev, "cbb_power: %dV\n", volts));
780115887Simp	if (volts != 0 && sc->chipset == CB_O2MICRO)
781115887Simp		reg = cbb_o2micro_power_hack(sc);
78270715Sjon
783148090Simp	/*
784185749Simp	 * We have to mask the card change detect interrupt while we're
785185749Simp	 * messing with the power.  It is allowed to bounce while we're
786185749Simp	 * messing with power as things settle down.  In addition, we mask off
787185749Simp	 * the card's function interrupt by routing it via the ISA bus.  This
788185749Simp	 * bit generally only affects 16-bit cards.  Some bridges allow one to
789185749Simp	 * set another bit to have it also affect 32-bit cards.  Since 32-bit
790185749Simp	 * cards are required to be better behaved, we don't bother to get
791185749Simp	 * into those bridge specific features.
792185749Simp	 *
793185749Simp	 * XXX I wonder if we need to enable the READY bit interrupt in the
794185749Simp	 * EXCA CSC register for 16-bit cards, and disable the CD bit?
795148090Simp	 */
796148090Simp	mask = cbb_get(sc, CBB_SOCKET_MASK);
797148090Simp	mask |= CBB_SOCKET_MASK_POWER;
798148090Simp	mask &= ~CBB_SOCKET_MASK_CD;
799148090Simp	cbb_set(sc, CBB_SOCKET_MASK, mask);
800148105Simp	PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL,
801148105Simp	    |CBBM_BRIDGECTRL_INTR_IREQ_ISA_EN, 2);
802101904Simp	cbb_set(sc, CBB_SOCKET_CONTROL, sock_ctrl);
803148013Simp	if (on) {
804148013Simp		mtx_lock(&sc->mtx);
805148013Simp		cnt = sc->powerintr;
806161241Simp		/*
807185749Simp		 * We have a shortish timeout of 500ms here.  Some bridges do
808185749Simp		 * not generate a POWER_CYCLE event for 16-bit cards.  In
809185749Simp		 * those cases, we have to cope the best we can, and having
810223218Simp		 * only a short delay is better than the alternatives.  Others
811223218Simp		 * raise the power cycle a smidge before it is really ready.
812223218Simp		 * We deal with those below.
813161241Simp		 */
814161241Simp		sane = 10;
815148090Simp		while (!(cbb_get(sc, CBB_SOCKET_STATE) & CBB_STATE_POWER_CYCLE) &&
816148090Simp		    cnt == sc->powerintr && sane-- > 0)
817185741Simp			msleep(&sc->powerintr, &sc->mtx, 0, "-", hz / 20);
818148013Simp		mtx_unlock(&sc->mtx);
819223218Simp
820161241Simp		/*
821223219Simp		 * Relax for 100ms.  Some bridges appear to assert this signal
822223218Simp		 * right away, but before the card has stabilized.  Other
823223218Simp		 * cards need need more time to cope up reliabily.
824223218Simp		 * Experiments with troublesome setups show this to be a
825223218Simp		 * "cheap" way to enhance reliabilty.  We need not do this for
826223218Simp		 * "off" since we don't touch the card after we turn it off.
827223218Simp		 */
828223219Simp		pause("cbbPwr", min(hz / 10, 1));
829223218Simp
830223218Simp		/*
831185749Simp		 * The TOPIC95B requires a little bit extra time to get its
832185749Simp		 * act together, so delay for an additional 100ms.  Also as
833185749Simp		 * documented below, it doesn't seem to set the POWER_CYCLE
834161241Simp		 * bit, so don't whine if it never came on.
835161241Simp		 */
836223218Simp		if (sc->chipset == CB_TOPIC95)
837167087Sjhb			pause("cbb95B", hz / 10);
838223218Simp		else if (sane <= 0)
839148090Simp			device_printf(sc->dev, "power timeout, doom?\n");
840148013Simp	}
841148090Simp
842148090Simp	/*
843148105Simp	 * After the power is good, we can turn off the power interrupt.
844148105Simp	 * However, the PC Card standard says that we must delay turning the
845148105Simp	 * CD bit back on for a bit to allow for bouncyness on power down
846148105Simp	 * (recall that we don't wait above for a power down, since we don't
847148105Simp	 * get an interrupt for that).  We're called either from the suspend
848148105Simp	 * code in which case we don't want to turn card change on again, or
849148105Simp	 * we're called from the card insertion code, in which case the cbb
850148105Simp	 * thread will turn it on for us before it waits to be woken by a
851148105Simp	 * change event.
852161241Simp	 *
853161241Simp	 * NB: Topic95B doesn't set the power cycle bit.  we assume that
854161241Simp	 * both it and the TOPIC95 behave the same.
855148090Simp	 */
856148013Simp	cbb_clrb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_POWER);
857101904Simp	status = cbb_get(sc, CBB_SOCKET_STATE);
858161241Simp	if (on && sc->chipset != CB_TOPIC95) {
859148013Simp		if ((status & CBB_STATE_POWER_CYCLE) == 0)
860148013Simp			device_printf(sc->dev, "Power not on?\n");
86167276Sjon	}
862118705Simp	if (status & CBB_STATE_BAD_VCC_REQ) {
863148013Simp		device_printf(sc->dev, "Bad Vcc requested\n");
864185622Simp		/*
865185622Simp		 * Turn off the power, and try again.  Retrigger other
866185622Simp		 * active interrupts via force register.  From NetBSD
867185622Simp		 * PR 36652, coded by me to description there.
868185622Simp		 */
869185622Simp		sock_ctrl &= ~CBB_SOCKET_CTRL_VCCMASK;
870185622Simp		sock_ctrl &= ~CBB_SOCKET_CTRL_VPPMASK;
871185622Simp		cbb_set(sc, CBB_SOCKET_CONTROL, sock_ctrl);
872185622Simp		status &= ~CBB_STATE_BAD_VCC_REQ;
873185622Simp		status &= ~CBB_STATE_DATA_LOST;
874185622Simp		status |= CBB_FORCE_CV_TEST;
875185622Simp		cbb_set(sc, CBB_SOCKET_FORCE, status);
876115887Simp		goto done;
87767276Sjon	}
878161241Simp	if (sc->chipset == CB_TOPIC97) {
879161241Simp		reg_ctrl = pci_read_config(sc->dev, TOPIC_REG_CTRL, 4);
880161241Simp		reg_ctrl &= ~TOPIC97_REG_CTRL_TESTMODE;
881161241Simp		if (on)
882161241Simp			reg_ctrl |= TOPIC97_REG_CTRL_CLKRUN_ENA;
883161241Simp		else
884161241Simp			reg_ctrl &= ~TOPIC97_REG_CTRL_CLKRUN_ENA;
885161241Simp		pci_write_config(sc->dev, TOPIC_REG_CTRL, reg_ctrl, 4);
886161241Simp	}
887148105Simp	PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL,
888148105Simp	    & ~CBBM_BRIDGECTRL_INTR_IREQ_ISA_EN, 2);
889115887Simp	retval = 1;
890115887Simpdone:;
891115887Simp	if (volts != 0 && sc->chipset == CB_O2MICRO)
892115887Simp		cbb_o2micro_power_hack2(sc, reg);
893115887Simp	return (retval);
89467276Sjon}
89567276Sjon
896148013Simpstatic int
897148013Simpcbb_current_voltage(device_t brdev)
898148013Simp{
899148013Simp	struct cbb_softc *sc = device_get_softc(brdev);
900148013Simp	uint32_t ctrl;
901148013Simp
902148013Simp	ctrl = cbb_get(sc, CBB_SOCKET_CONTROL);
903148013Simp	switch (ctrl & CBB_SOCKET_CTRL_VCCMASK) {
904148013Simp	case CBB_SOCKET_CTRL_VCC_5V:
905148013Simp		return CARD_5V_CARD;
906148013Simp	case CBB_SOCKET_CTRL_VCC_3V:
907148013Simp		return CARD_3V_CARD;
908148013Simp	case CBB_SOCKET_CTRL_VCC_XV:
909148013Simp		return CARD_XV_CARD;
910148013Simp	case CBB_SOCKET_CTRL_VCC_YV:
911148013Simp		return CARD_YV_CARD;
912148013Simp	}
913148013Simp	return 0;
914148013Simp}
915148013Simp
91690751Simp/*
91790751Simp * detect the voltage for the card, and set it.  Since the power
91890751Simp * used is the square of the voltage, lower voltages is a big win
91990751Simp * and what Windows does (and what Microsoft prefers).  The MS paper
920148013Simp * also talks about preferring the CIS entry as well, but that has
921148013Simp * to be done elsewhere.  We also optimize power sequencing here
922148013Simp * and don't change things if we're already powered up at a supported
923148013Simp * voltage.
924148013Simp *
925148013Simp * In addition, we power up with OE disabled.  We'll set it later
926148013Simp * in the power up sequence.
92790751Simp */
92890751Simpstatic int
929101904Simpcbb_do_power(device_t brdev)
93090751Simp{
931127965Simp	struct cbb_softc *sc = device_get_softc(brdev);
932148013Simp	uint32_t voltage, curpwr;
933148013Simp	uint32_t status;
93490751Simp
935148013Simp	/* Don't enable OE (output enable) until power stable */
936133553Simp	exca_clrb(&sc->exca[0], EXCA_PWRCTL, EXCA_PWRCTL_OE);
937127960Simp
938148013Simp	voltage = cbb_detect_voltage(brdev);
939148013Simp	curpwr = cbb_current_voltage(brdev);
940148013Simp	status = cbb_get(sc, CBB_SOCKET_STATE);
941148013Simp	if ((status & CBB_STATE_POWER_CYCLE) && (voltage & curpwr))
942148013Simp		return 0;
94390751Simp	/* Prefer lowest voltage supported */
944115986Simp	cbb_power(brdev, CARD_OFF);
94590751Simp	if (voltage & CARD_YV_CARD)
946115986Simp		cbb_power(brdev, CARD_VCC(YV));
94790751Simp	else if (voltage & CARD_XV_CARD)
948115986Simp		cbb_power(brdev, CARD_VCC(XV));
94990751Simp	else if (voltage & CARD_3V_CARD)
950115986Simp		cbb_power(brdev, CARD_VCC(3));
95190751Simp	else if (voltage & CARD_5V_CARD)
952115986Simp		cbb_power(brdev, CARD_VCC(5));
95390751Simp	else {
95490751Simp		device_printf(brdev, "Unknown card voltage\n");
95590751Simp		return (ENXIO);
95690751Simp	}
95790751Simp	return (0);
95890751Simp}
95990751Simp
96067276Sjon/************************************************************************/
961104830Simp/* CardBus power functions						*/
96267276Sjon/************************************************************************/
96367276Sjon
96469288Sjonstatic void
965189723Simpcbb_cardbus_reset_power(device_t brdev, device_t child, int on)
96667276Sjon{
967101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
968181453Simp	uint32_t b;
969181453Simp	int delay, count;
97067276Sjon
971148025Simp	/*
972181458Simp	 * Asserting reset for 20ms is necessary for most bridges.  For some
973185623Simp	 * reason, the Ricoh RF5C47x bridges need it asserted for 400ms.  The
974185623Simp	 * root cause of this is unknown, and NetBSD does the same thing.
975148025Simp	 */
976181453Simp	delay = sc->chipset == CB_RF5C47X ? 400 : 20;
97790751Simp	PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL, |CBBM_BRIDGECTRL_RESET, 2);
978167087Sjhb	pause("cbbP3", hz * delay / 1000);
97967276Sjon
980181458Simp	/*
981185623Simp	 * If a card exists and we're turning it on, take it out of reset.
982185623Simp	 * After clearing reset, wait up to 1.1s for the first configuration
983185623Simp	 * register (vendor/product) configuration register of device 0.0 to
984185623Simp	 * become != 0xffffffff.  The PCMCIA PC Card Host System Specification
985185623Simp	 * says that when powering up the card, the PCI Spec v2.1 must be
986185623Simp	 * followed.  In PCI spec v2.2 Table 4-6, Trhfa (Reset High to first
987185623Simp	 * Config Access) is at most 2^25 clocks, or just over 1s.  Section
988185623Simp	 * 2.2.1 states any card not ready to participate in bus transactions
989185623Simp	 * must tristate its outputs.  Therefore, any access to its
990185623Simp	 * configuration registers must be ignored.  In that state, the config
991185623Simp	 * reg will read 0xffffffff.  Section 6.2.1 states a vendor id of
992185623Simp	 * 0xffff is invalid, so this can never match a real card.  Print a
993185623Simp	 * warning if it never returns a real id.  The PCMCIA PC Card
994185623Simp	 * Electrical Spec Section 5.2.7.1 implies only device 0 is present on
995185623Simp	 * a cardbus bus, so that's the only register we check here.
996181458Simp	 */
997181453Simp	if (on && CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) {
998181458Simp		/*
999181458Simp		 */
100090751Simp		PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL,
100190751Simp		    &~CBBM_BRIDGECTRL_RESET, 2);
1002181523Simp		b = pcib_get_bus(child);
1003181458Simp		count = 1100 / 20;
1004181453Simp		do {
1005181453Simp			pause("cbbP4", hz * 2 / 100);
1006181470Simp		} while (PCIB_READ_CONFIG(brdev, b, 0, 0, PCIR_DEVVENDOR, 4) ==
1007181470Simp		    0xfffffffful && --count >= 0);
1008181453Simp		if (count < 0)
1009181458Simp			device_printf(brdev, "Warning: Bus reset timeout\n");
101067276Sjon	}
101167276Sjon}
101267276Sjon
101369288Sjonstatic int
1014101904Simpcbb_cardbus_power_enable_socket(device_t brdev, device_t child)
101569288Sjon{
1016101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
101790751Simp	int err;
101870715Sjon
1019119191Simp	if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE)))
102086904Simp		return (ENODEV);
102170715Sjon
1022101904Simp	err = cbb_do_power(brdev);
102390751Simp	if (err)
102490751Simp		return (err);
1025189723Simp	cbb_cardbus_reset_power(brdev, child, 1);
102686904Simp	return (0);
102769288Sjon}
102869288Sjon
1029188129Simpstatic int
1030101904Simpcbb_cardbus_power_disable_socket(device_t brdev, device_t child)
103169288Sjon{
1032115986Simp	cbb_power(brdev, CARD_OFF);
1033189723Simp	cbb_cardbus_reset_power(brdev, child, 0);
1034188129Simp	return (0);
103569288Sjon}
103669288Sjon
103767276Sjon/************************************************************************/
1038104830Simp/* CardBus Resource							*/
103967276Sjon/************************************************************************/
104067276Sjon
104167276Sjonstatic int
1042101904Simpcbb_cardbus_io_open(device_t brdev, int win, uint32_t start, uint32_t end)
104367276Sjon{
104467276Sjon	int basereg;
104567276Sjon	int limitreg;
104667276Sjon
104767276Sjon	if ((win < 0) || (win > 1)) {
104882375Sjon		DEVPRINTF((brdev,
1049101904Simp		    "cbb_cardbus_io_open: window out of range %d\n", win));
105086904Simp		return (EINVAL);
105167276Sjon	}
105267276Sjon
105390751Simp	basereg = win * 8 + CBBR_IOBASE0;
105490751Simp	limitreg = win * 8 + CBBR_IOLIMIT0;
105567276Sjon
105682375Sjon	pci_write_config(brdev, basereg, start, 4);
105782375Sjon	pci_write_config(brdev, limitreg, end, 4);
105886904Simp	return (0);
105967276Sjon}
106067276Sjon
106167276Sjonstatic int
1062101904Simpcbb_cardbus_mem_open(device_t brdev, int win, uint32_t start, uint32_t end)
106367276Sjon{
106467276Sjon	int basereg;
106567276Sjon	int limitreg;
106667276Sjon
106767276Sjon	if ((win < 0) || (win > 1)) {
106882375Sjon		DEVPRINTF((brdev,
1069101904Simp		    "cbb_cardbus_mem_open: window out of range %d\n", win));
107086904Simp		return (EINVAL);
107167276Sjon	}
107267276Sjon
1073185624Simp	basereg = win * 8 + CBBR_MEMBASE0;
1074185624Simp	limitreg = win * 8 + CBBR_MEMLIMIT0;
107567276Sjon
107682375Sjon	pci_write_config(brdev, basereg, start, 4);
107782375Sjon	pci_write_config(brdev, limitreg, end, 4);
107886904Simp	return (0);
107967276Sjon}
108067276Sjon
1081153860Simp#define START_NONE 0xffffffff
1082153860Simp#define END_NONE 0
1083153860Simp
108467276Sjonstatic void
1085101904Simpcbb_cardbus_auto_open(struct cbb_softc *sc, int type)
108667276Sjon{
108789326Simp	uint32_t starts[2];
108889326Simp	uint32_t ends[2];
1089101904Simp	struct cbb_reslist *rle;
1090153860Simp	int align, i;
109189326Simp	uint32_t reg;
109267276Sjon
1093153860Simp	starts[0] = starts[1] = START_NONE;
1094153860Simp	ends[0] = ends[1] = END_NONE;
109567276Sjon
109682378Sjon	if (type == SYS_RES_MEMORY)
109790751Simp		align = CBB_MEMALIGN;
109882378Sjon	else if (type == SYS_RES_IOPORT)
109990751Simp		align = CBB_IOALIGN;
110082378Sjon	else
110182378Sjon		align = 1;
110282378Sjon
110382378Sjon	SLIST_FOREACH(rle, &sc->rl, link) {
110467276Sjon		if (rle->type != type)
1105153860Simp			continue;
1106153860Simp		if (rle->res == NULL)
1107153860Simp			continue;
1108153860Simp		if (!(rman_get_flags(rle->res) & RF_ACTIVE))
1109153860Simp			continue;
1110153860Simp		if (rman_get_flags(rle->res) & RF_PREFETCHABLE)
1111153860Simp			i = 1;
1112153860Simp		else
1113153860Simp			i = 0;
1114153860Simp		if (rman_get_start(rle->res) < starts[i])
1115153860Simp			starts[i] = rman_get_start(rle->res);
1116153860Simp		if (rman_get_end(rle->res) > ends[i])
1117153860Simp			ends[i] = rman_get_end(rle->res);
1118153860Simp	}
1119153860Simp	for (i = 0; i < 2; i++) {
1120153860Simp		if (starts[i] == START_NONE)
1121153860Simp			continue;
1122153860Simp		starts[i] &= ~(align - 1);
1123153860Simp		ends[i] = ((ends[i] + align - 1) & ~(align - 1)) - 1;
1124153860Simp	}
1125153860Simp	if (starts[0] != START_NONE && starts[1] != START_NONE) {
1126153860Simp		if (starts[0] < starts[1]) {
1127153860Simp			if (ends[0] > starts[1]) {
1128153860Simp				device_printf(sc->dev, "Overlapping ranges"
1129153860Simp				    " for prefetch and non-prefetch memory\n");
1130153860Simp				return;
1131153860Simp			}
113267276Sjon		} else {
1133153860Simp			if (ends[1] > starts[0]) {
1134153860Simp				device_printf(sc->dev, "Overlapping ranges"
1135153860Simp				    " for prefetch and non-prefetch memory\n");
1136153860Simp				return;
1137153860Simp			}
113867276Sjon		}
113967276Sjon	}
114067276Sjon
114182378Sjon	if (type == SYS_RES_MEMORY) {
1142101904Simp		cbb_cardbus_mem_open(sc->dev, 0, starts[0], ends[0]);
1143101904Simp		cbb_cardbus_mem_open(sc->dev, 1, starts[1], ends[1]);
114490751Simp		reg = pci_read_config(sc->dev, CBBR_BRIDGECTRL, 2);
1145153860Simp		reg &= ~(CBBM_BRIDGECTRL_PREFETCH_0 |
114690751Simp		    CBBM_BRIDGECTRL_PREFETCH_1);
1147153860Simp		if (starts[1] != START_NONE)
1148153860Simp			reg |= CBBM_BRIDGECTRL_PREFETCH_1;
114990751Simp		pci_write_config(sc->dev, CBBR_BRIDGECTRL, reg, 2);
1150153860Simp		if (bootverbose) {
1151153860Simp			device_printf(sc->dev, "Opening memory:\n");
1152153860Simp			if (starts[0] != START_NONE)
1153153860Simp				device_printf(sc->dev, "Normal: %#x-%#x\n",
1154153860Simp				    starts[0], ends[0]);
1155153860Simp			if (starts[1] != START_NONE)
1156153860Simp				device_printf(sc->dev, "Prefetch: %#x-%#x\n",
1157153860Simp				    starts[1], ends[1]);
1158153757Simp		}
115967276Sjon	} else if (type == SYS_RES_IOPORT) {
1160101904Simp		cbb_cardbus_io_open(sc->dev, 0, starts[0], ends[0]);
1161101904Simp		cbb_cardbus_io_open(sc->dev, 1, starts[1], ends[1]);
1162153860Simp		if (bootverbose && starts[0] != START_NONE)
1163153860Simp			device_printf(sc->dev, "Opening I/O: %#x-%#x\n",
1164153860Simp			    starts[0], ends[0]);
116567276Sjon	}
116667276Sjon}
116767276Sjon
116867276Sjonstatic int
1169101904Simpcbb_cardbus_activate_resource(device_t brdev, device_t child, int type,
117082378Sjon    int rid, struct resource *res)
117167276Sjon{
117282378Sjon	int ret;
117367276Sjon
117482378Sjon	ret = BUS_ACTIVATE_RESOURCE(device_get_parent(brdev), child,
117582378Sjon	    type, rid, res);
117686904Simp	if (ret != 0)
117786904Simp		return (ret);
1178101904Simp	cbb_cardbus_auto_open(device_get_softc(brdev), type);
117986904Simp	return (0);
118067276Sjon}
118167276Sjon
118267276Sjonstatic int
1183101904Simpcbb_cardbus_deactivate_resource(device_t brdev, device_t child, int type,
118482378Sjon    int rid, struct resource *res)
118567276Sjon{
118682378Sjon	int ret;
118767276Sjon
118882378Sjon	ret = BUS_DEACTIVATE_RESOURCE(device_get_parent(brdev), child,
118982378Sjon	    type, rid, res);
119086904Simp	if (ret != 0)
119186904Simp		return (ret);
1192101904Simp	cbb_cardbus_auto_open(device_get_softc(brdev), type);
119386904Simp	return (0);
119467276Sjon}
119567276Sjon
119682375Sjonstatic struct resource *
1197101904Simpcbb_cardbus_alloc_resource(device_t brdev, device_t child, int type,
1198118607Sjhb    int *rid, u_long start, u_long end, u_long count, u_int flags)
119967276Sjon{
1200101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
120182378Sjon	int tmp;
120282378Sjon	struct resource *res;
1203127965Simp	u_long align;
120482378Sjon
120582378Sjon	switch (type) {
120682378Sjon	case SYS_RES_IRQ:
120790751Simp		tmp = rman_get_start(sc->irq_res);
120882378Sjon		if (start > tmp || end < tmp || count != 1) {
120982378Sjon			device_printf(child, "requested interrupt %ld-%ld,"
1210101904Simp			    "count = %ld not supported by cbb\n",
121182378Sjon			    start, end, count);
121286904Simp			return (NULL);
121367276Sjon		}
121482378Sjon		start = end = tmp;
1215114169Simp		flags |= RF_SHAREABLE;
121682378Sjon		break;
121782378Sjon	case SYS_RES_IOPORT:
1218101904Simp		if (start <= cbb_start_32_io)
1219101904Simp			start = cbb_start_32_io;
122082378Sjon		if (end < start)
122182378Sjon			end = start;
1222153757Simp		if (count > (1 << RF_ALIGNMENT(flags)))
1223153757Simp			flags = (flags & ~RF_ALIGNMENT_MASK) |
1224153757Simp			    rman_make_alignment_flags(count);
122582378Sjon		break;
122682378Sjon	case SYS_RES_MEMORY:
1227101904Simp		if (start <= cbb_start_mem)
1228101904Simp			start = cbb_start_mem;
122982378Sjon		if (end < start)
123082378Sjon			end = start;
1231127966Simp		if (count < CBB_MEMALIGN)
1232127966Simp			align = CBB_MEMALIGN;
1233127966Simp		else
1234127966Simp			align = count;
1235127966Simp		if (align > (1 << RF_ALIGNMENT(flags)))
1236127966Simp			flags = (flags & ~RF_ALIGNMENT_MASK) |
1237127965Simp			    rman_make_alignment_flags(align);
123882378Sjon		break;
123982378Sjon	}
124082378Sjon	res = BUS_ALLOC_RESOURCE(device_get_parent(brdev), child, type, rid,
124182378Sjon	    start, end, count, flags & ~RF_ACTIVE);
124282378Sjon	if (res == NULL) {
1243169617Simp		printf("cbb alloc res fail type %d rid %x\n", type, *rid);
124486904Simp		return (NULL);
124582378Sjon	}
1246101904Simp	cbb_insert_res(sc, res, type, *rid);
124782378Sjon	if (flags & RF_ACTIVE)
124882378Sjon		if (bus_activate_resource(child, type, *rid, res) != 0) {
124982378Sjon			bus_release_resource(child, type, *rid, res);
125086904Simp			return (NULL);
125167276Sjon		}
125282378Sjon
125386904Simp	return (res);
125467276Sjon}
125567276Sjon
125667276Sjonstatic int
1257101904Simpcbb_cardbus_release_resource(device_t brdev, device_t child, int type,
125882378Sjon    int rid, struct resource *res)
125967276Sjon{
1260101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
126186904Simp	int error;
126282378Sjon
126382378Sjon	if (rman_get_flags(res) & RF_ACTIVE) {
126482378Sjon		error = bus_deactivate_resource(child, type, rid, res);
126582378Sjon		if (error != 0)
126686904Simp			return (error);
126782378Sjon	}
1268101904Simp	cbb_remove_res(sc, res);
126986904Simp	return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child,
127086904Simp	    type, rid, res));
127167276Sjon}
127267276Sjon
127367276Sjon/************************************************************************/
127469288Sjon/* PC Card Power Functions						*/
127567276Sjon/************************************************************************/
127667276Sjon
127769288Sjonstatic int
1278101904Simpcbb_pcic_power_enable_socket(device_t brdev, device_t child)
127969288Sjon{
1280101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
128190751Simp	int err;
128269288Sjon
1283101904Simp	DPRINTF(("cbb_pcic_socket_enable:\n"));
128469288Sjon
128569288Sjon	/* power down/up the socket to reset */
1286101904Simp	err = cbb_do_power(brdev);
128790751Simp	if (err)
128890751Simp		return (err);
1289133553Simp	exca_reset(&sc->exca[0], child);
129069288Sjon
129186904Simp	return (0);
129269288Sjon}
129369288Sjon
1294188129Simpstatic int
1295101904Simpcbb_pcic_power_disable_socket(device_t brdev, device_t child)
129669288Sjon{
1297101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
129869288Sjon
1299101904Simp	DPRINTF(("cbb_pcic_socket_disable\n"));
130069288Sjon
1301167217Simp	/* Turn off the card's interrupt and leave it in reset, wait 10ms */
1302151080Simp	exca_putb(&sc->exca[0], EXCA_INTR, 0);
1303167087Sjhb	pause("cbbP1", hz / 100);
130469288Sjon
130569288Sjon	/* power down the socket */
1306115986Simp	cbb_power(brdev, CARD_OFF);
1307151080Simp	exca_putb(&sc->exca[0], EXCA_PWRCTL, 0);
130869288Sjon
130969288Sjon	/* wait 300ms until power fails (Tpf). */
1310167217Simp	pause("cbbP2", hz * 300 / 1000);
1311166786Simp
1312166786Simp	/* enable CSC interrupts */
1313166786Simp	exca_putb(&sc->exca[0], EXCA_INTR, EXCA_INTR_ENABLE);
1314188129Simp	return (0);
131569288Sjon}
131669288Sjon
131769288Sjon/************************************************************************/
131889949Simp/* POWER methods							*/
131969288Sjon/************************************************************************/
132069288Sjon
1321133553Simpint
1322101904Simpcbb_power_enable_socket(device_t brdev, device_t child)
132367276Sjon{
1324101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
132567276Sjon
1326101904Simp	if (sc->flags & CBB_16BIT_CARD)
1327101904Simp		return (cbb_pcic_power_enable_socket(brdev, child));
1328188129Simp	return (cbb_cardbus_power_enable_socket(brdev, child));
132967276Sjon}
133067276Sjon
1331188129Simpint
1332101904Simpcbb_power_disable_socket(device_t brdev, device_t child)
133367276Sjon{
1334101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
1335101904Simp	if (sc->flags & CBB_16BIT_CARD)
1336188129Simp		return (cbb_pcic_power_disable_socket(brdev, child));
1337188129Simp	return (cbb_cardbus_power_disable_socket(brdev, child));
133867276Sjon}
1339115989Simp
134082378Sjonstatic int
1341101904Simpcbb_pcic_activate_resource(device_t brdev, device_t child, int type, int rid,
134282378Sjon    struct resource *res)
134367276Sjon{
1344101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
1345133553Simp	return (exca_activate_resource(&sc->exca[0], child, type, rid, res));
134667276Sjon}
134767276Sjon
134867276Sjonstatic int
1349101904Simpcbb_pcic_deactivate_resource(device_t brdev, device_t child, int type,
135082378Sjon    int rid, struct resource *res)
135167276Sjon{
1352101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
1353133553Simp	return (exca_deactivate_resource(&sc->exca[0], child, type, rid, res));
135467276Sjon}
135567276Sjon
135682375Sjonstatic struct resource *
1357101904Simpcbb_pcic_alloc_resource(device_t brdev, device_t child, int type, int *rid,
1358118607Sjhb    u_long start, u_long end, u_long count, u_int flags)
135967276Sjon{
136082378Sjon	struct resource *res = NULL;
1361101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
1362128170Simp	int align;
136382378Sjon	int tmp;
136467276Sjon
136567423Simp	switch (type) {
136667423Simp	case SYS_RES_MEMORY:
1367101904Simp		if (start < cbb_start_mem)
1368101904Simp			start = cbb_start_mem;
136982378Sjon		if (end < start)
137082378Sjon			end = start;
1371128170Simp		if (count < CBB_MEMALIGN)
1372128170Simp			align = CBB_MEMALIGN;
1373128170Simp		else
1374128170Simp			align = count;
1375128170Simp		if (align > (1 << RF_ALIGNMENT(flags)))
1376128170Simp			flags = (flags & ~RF_ALIGNMENT_MASK) |
1377128170Simp			    rman_make_alignment_flags(align);
137867423Simp		break;
137967423Simp	case SYS_RES_IOPORT:
1380101904Simp		if (start < cbb_start_16_io)
1381101904Simp			start = cbb_start_16_io;
138267423Simp		if (end < start)
138367423Simp			end = start;
138467423Simp		break;
138567423Simp	case SYS_RES_IRQ:
138690751Simp		tmp = rman_get_start(sc->irq_res);
138782378Sjon		if (start > tmp || end < tmp || count != 1) {
138882378Sjon			device_printf(child, "requested interrupt %ld-%ld,"
1389101904Simp			    "count = %ld not supported by cbb\n",
139082378Sjon			    start, end, count);
139186904Simp			return (NULL);
139282378Sjon		}
139367423Simp		flags |= RF_SHAREABLE;
139490751Simp		start = end = rman_get_start(sc->irq_res);
139567423Simp		break;
139667423Simp	}
139782378Sjon	res = BUS_ALLOC_RESOURCE(device_get_parent(brdev), child, type, rid,
139882378Sjon	    start, end, count, flags & ~RF_ACTIVE);
139982378Sjon	if (res == NULL)
140086904Simp		return (NULL);
1401101904Simp	cbb_insert_res(sc, res, type, *rid);
140267276Sjon	if (flags & RF_ACTIVE) {
140382378Sjon		if (bus_activate_resource(child, type, *rid, res) != 0) {
140482378Sjon			bus_release_resource(child, type, *rid, res);
140586904Simp			return (NULL);
140667276Sjon		}
140767276Sjon	}
140867276Sjon
140986904Simp	return (res);
141067276Sjon}
141167276Sjon
141267276Sjonstatic int
1413101904Simpcbb_pcic_release_resource(device_t brdev, device_t child, int type,
141482375Sjon    int rid, struct resource *res)
141567276Sjon{
1416101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
141786904Simp	int error;
141867276Sjon
141970715Sjon	if (rman_get_flags(res) & RF_ACTIVE) {
142070715Sjon		error = bus_deactivate_resource(child, type, rid, res);
142170715Sjon		if (error != 0)
142286904Simp			return (error);
142370715Sjon	}
1424101904Simp	cbb_remove_res(sc, res);
142586904Simp	return (BUS_RELEASE_RESOURCE(device_get_parent(brdev), child,
142686904Simp	    type, rid, res));
142767276Sjon}
142867276Sjon
142967276Sjon/************************************************************************/
143067276Sjon/* PC Card methods							*/
143167276Sjon/************************************************************************/
143267276Sjon
1433133553Simpint
1434101904Simpcbb_pcic_set_res_flags(device_t brdev, device_t child, int type, int rid,
1435188129Simp    u_long flags)
143667276Sjon{
1437101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
143882378Sjon	struct resource *res;
143967276Sjon
144067276Sjon	if (type != SYS_RES_MEMORY)
144167276Sjon		return (EINVAL);
1442101904Simp	res = cbb_find_res(sc, type, rid);
144382378Sjon	if (res == NULL) {
144482378Sjon		device_printf(brdev,
144582378Sjon		    "set_res_flags: specified rid not found\n");
144686904Simp		return (ENOENT);
144782378Sjon	}
1448133553Simp	return (exca_mem_set_flags(&sc->exca[0], res, flags));
144967276Sjon}
145067276Sjon
1451133553Simpint
1452101904Simpcbb_pcic_set_memory_offset(device_t brdev, device_t child, int rid,
145389326Simp    uint32_t cardaddr, uint32_t *deltap)
145467276Sjon{
1455101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
145682378Sjon	struct resource *res;
145767276Sjon
1458101904Simp	res = cbb_find_res(sc, SYS_RES_MEMORY, rid);
145982378Sjon	if (res == NULL) {
146082378Sjon		device_printf(brdev,
146182378Sjon		    "set_memory_offset: specified rid not found\n");
146286904Simp		return (ENOENT);
146370715Sjon	}
1464133553Simp	return (exca_mem_set_offset(&sc->exca[0], res, cardaddr, deltap));
146567276Sjon}
146667276Sjon
146769288Sjon/************************************************************************/
146869288Sjon/* BUS Methods								*/
146967276Sjon/************************************************************************/
147067276Sjon
147167276Sjon
1472133553Simpint
1473101904Simpcbb_activate_resource(device_t brdev, device_t child, int type, int rid,
147482375Sjon    struct resource *r)
147567276Sjon{
1476101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
147767276Sjon
1478101904Simp	if (sc->flags & CBB_16BIT_CARD)
1479101904Simp		return (cbb_pcic_activate_resource(brdev, child, type, rid, r));
148067276Sjon	else
1481101904Simp		return (cbb_cardbus_activate_resource(brdev, child, type, rid,
148286904Simp		    r));
148367276Sjon}
148467276Sjon
1485133553Simpint
1486101904Simpcbb_deactivate_resource(device_t brdev, device_t child, int type,
148782375Sjon    int rid, struct resource *r)
148867276Sjon{
1489101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
149067276Sjon
1491101904Simp	if (sc->flags & CBB_16BIT_CARD)
1492101904Simp		return (cbb_pcic_deactivate_resource(brdev, child, type,
149386904Simp		    rid, r));
149467276Sjon	else
1495101904Simp		return (cbb_cardbus_deactivate_resource(brdev, child, type,
149686904Simp		    rid, r));
149767276Sjon}
149867276Sjon
1499133553Simpstruct resource *
1500101904Simpcbb_alloc_resource(device_t brdev, device_t child, int type, int *rid,
1501118607Sjhb    u_long start, u_long end, u_long count, u_int flags)
150267276Sjon{
1503101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
150467276Sjon
1505101904Simp	if (sc->flags & CBB_16BIT_CARD)
1506101904Simp		return (cbb_pcic_alloc_resource(brdev, child, type, rid,
150786904Simp		    start, end, count, flags));
150867276Sjon	else
1509101904Simp		return (cbb_cardbus_alloc_resource(brdev, child, type, rid,
151086904Simp		    start, end, count, flags));
151167276Sjon}
151267276Sjon
1513133553Simpint
1514101904Simpcbb_release_resource(device_t brdev, device_t child, int type, int rid,
151582375Sjon    struct resource *r)
151667276Sjon{
1517101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
151867276Sjon
1519101904Simp	if (sc->flags & CBB_16BIT_CARD)
1520101904Simp		return (cbb_pcic_release_resource(brdev, child, type,
152186904Simp		    rid, r));
152267276Sjon	else
1523101904Simp		return (cbb_cardbus_release_resource(brdev, child, type,
152486904Simp		    rid, r));
152567276Sjon}
152667276Sjon
1527133553Simpint
1528101904Simpcbb_read_ivar(device_t brdev, device_t child, int which, uintptr_t *result)
152969954Smsmith{
1530101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
153170715Sjon
153269954Smsmith	switch (which) {
1533172394Smarius	case PCIB_IVAR_DOMAIN:
1534172394Smarius		*result = sc->domain;
1535172394Smarius		return (0);
153669954Smsmith	case PCIB_IVAR_BUS:
153790751Simp		*result = sc->secbus;
153886904Simp		return (0);
153969954Smsmith	}
154086904Simp	return (ENOENT);
154169954Smsmith}
154269954Smsmith
1543133553Simpint
1544101904Simpcbb_write_ivar(device_t brdev, device_t child, int which, uintptr_t value)
154569954Smsmith{
1546101904Simp	struct cbb_softc *sc = device_get_softc(brdev);
154769954Smsmith
154869954Smsmith	switch (which) {
1549172394Smarius	case PCIB_IVAR_DOMAIN:
1550172394Smarius		return (EINVAL);
155169954Smsmith	case PCIB_IVAR_BUS:
155290751Simp		sc->secbus = value;
1553159194Simp		return (0);
155469954Smsmith	}
155586904Simp	return (ENOENT);
155669954Smsmith}
155769954Smsmith
1558133553Simpint
1559101904Simpcbb_suspend(device_t self)
156087975Simp{
156187975Simp	int			error = 0;
1562104642Simp	struct cbb_softc	*sc = device_get_softc(self);
156387975Simp
1564158892Simp	error = bus_generic_suspend(self);
1565158892Simp	if (error != 0)
1566158892Simp		return (error);
1567116232Simp	cbb_set(sc, CBB_SOCKET_MASK, 0);	/* Quiet hardware */
1568170272Simp	sc->cardok = 0;				/* Card is bogus now */
1569158892Simp	return (0);
157087975Simp}
157187975Simp
1572133553Simpint
1573101904Simpcbb_resume(device_t self)
157487975Simp{
157587975Simp	int	error = 0;
1576101904Simp	struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(self);
157789326Simp	uint32_t tmp;
157887975Simp
1579104642Simp	/*
1580104642Simp	 * Some BIOSes will not save the BARs for the pci chips, so we
1581104642Simp	 * must do it ourselves.  If the BAR is reset to 0 for an I/O
1582104642Simp	 * device, it will read back as 0x1, so no explicit test for
1583104642Simp	 * memory devices are needed.
1584104642Simp	 *
1585104642Simp	 * Note: The PCI bus code should do this automatically for us on
1586104642Simp	 * suspend/resume, but until it does, we have to cope.
1587104642Simp	 */
158890751Simp	pci_write_config(self, CBBR_SOCKBASE, rman_get_start(sc->base_res), 4);
158987975Simp	DEVPRINTF((self, "PCI Memory allocated: %08lx\n",
159090751Simp	    rman_get_start(sc->base_res)));
159187975Simp
1592133553Simp	sc->chipinit(sc);
159387975Simp
1594104642Simp	/* reset interrupt -- Do we really need to do this? */
1595104642Simp	tmp = cbb_get(sc, CBB_SOCKET_EVENT);
1596104642Simp	cbb_set(sc, CBB_SOCKET_EVENT, tmp);
1597104642Simp
159887975Simp	/* CSC Interrupt: Card detect interrupt on */
1599101904Simp	cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
160087975Simp
1601106362Simp	/* Signal the thread to wakeup. */
1602185625Simp	wakeup(&sc->intrhand);
160387975Simp
160490444Simp	error = bus_generic_resume(self);
160590444Simp
160687975Simp	return (error);
160787975Simp}
160887975Simp
1609133553Simpint
1610188129Simpcbb_child_present(device_t parent, device_t child)
1611106900Simp{
1612188129Simp	struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(parent);
1613106900Simp	uint32_t sockstate;
1614106900Simp
1615106900Simp	sockstate = cbb_get(sc, CBB_SOCKET_STATE);
1616170272Simp	return (CBB_CARD_PRESENT(sockstate) && sc->cardok);
1617106900Simp}
1618