pccard.c revision 104610
166200Simp/*	$NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $	*/
252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard.c 104610 2002-10-07 07:18:32Z imp $ */
352506Simp
452506Simp/*
552506Simp * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
652506Simp *
752506Simp * Redistribution and use in source and binary forms, with or without
852506Simp * modification, are permitted provided that the following conditions
952506Simp * are met:
1052506Simp * 1. Redistributions of source code must retain the above copyright
1152506Simp *    notice, this list of conditions and the following disclaimer.
1252506Simp * 2. Redistributions in binary form must reproduce the above copyright
1352506Simp *    notice, this list of conditions and the following disclaimer in the
1452506Simp *    documentation and/or other materials provided with the distribution.
1552506Simp * 3. All advertising materials mentioning features or use of this software
1652506Simp *    must display the following acknowledgement:
1752506Simp *	This product includes software developed by Marc Horowitz.
1852506Simp * 4. The name of the author may not be used to endorse or promote products
1952506Simp *    derived from this software without specific prior written permission.
2052506Simp *
2152506Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2252506Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2352506Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2452506Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2552506Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2652506Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2752506Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2852506Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2952506Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3052506Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3152506Simp */
3252506Simp
3352506Simp#include <sys/param.h>
3452506Simp#include <sys/systm.h>
3552506Simp#include <sys/malloc.h>
3652506Simp#include <sys/module.h>
3752506Simp#include <sys/kernel.h>
3852506Simp#include <sys/queue.h>
3991786Simp#include <sys/sysctl.h>
4052506Simp#include <sys/types.h>
4152506Simp
4252506Simp#include <sys/bus.h>
4352506Simp#include <machine/bus.h>
4452506Simp#include <sys/rman.h>
4552506Simp#include <machine/resource.h>
4652506Simp
4782781Sshiba#include <net/ethernet.h>
4882781Sshiba
4952506Simp#include <dev/pccard/pccardreg.h>
5052506Simp#include <dev/pccard/pccardvar.h>
5152506Simp
5255500Simp#include "power_if.h"
5359193Simp#include "card_if.h"
5455500Simp
5555500Simp#define PCCARDDEBUG
5655500Simp
5791786Simp/* sysctl vars */
5891786SimpSYSCTL_NODE(_hw, OID_AUTO, pccard, CTLFLAG_RD, 0, "PCCARD parameters");
5991786Simp
6091786Simpint	pccard_debug = 0;
6191786SimpTUNABLE_INT("hw.pccard.debug", &pccard_debug);
6291786SimpSYSCTL_INT(_hw_pccard, OID_AUTO, debug, CTLFLAG_RW,
6391786Simp    &pccard_debug, 0,
6491786Simp  "pccard debug");
6591786Simp
6691786Simpint	pccard_cis_debug = 0;
6791786SimpTUNABLE_INT("hw.pccard.cis_debug", &pccard_cis_debug);
6891786SimpSYSCTL_INT(_hw_pccard, OID_AUTO, cis_debug, CTLFLAG_RW,
6991786Simp    &pccard_cis_debug, 0, "pccard CIS debug");
7091786Simp
7152506Simp#ifdef PCCARDDEBUG
7252506Simp#define	DPRINTF(arg) if (pccard_debug) printf arg
7355500Simp#define	DEVPRINTF(arg) if (pccard_debug) device_printf arg
7467333Simp#define PRVERBOSE(arg) printf arg
7567333Simp#define DEVPRVERBOSE(arg) device_printf arg
7652506Simp#else
7752506Simp#define	DPRINTF(arg)
7855500Simp#define	DEVPRINTF(arg)
7967333Simp#define PRVERBOSE(arg) if (bootverbose) printf arg
8067333Simp#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg
8152506Simp#endif
8252506Simp
8382378Sjonstatic int	pccard_ccr_read(struct pccard_function *pf, int ccr);
8482378Sjonstatic void	pccard_ccr_write(struct pccard_function *pf, int ccr, int val);
8582378Sjonstatic int	pccard_attach_card(device_t dev);
8682378Sjonstatic int	pccard_detach_card(device_t dev, int flags);
8782378Sjonstatic int	pccard_card_gettype(device_t dev, int *type);
8882378Sjonstatic void	pccard_function_init(struct pccard_function *pf);
8982378Sjonstatic void	pccard_function_free(struct pccard_function *pf);
9082378Sjonstatic int	pccard_function_enable(struct pccard_function *pf);
9182378Sjonstatic void	pccard_function_disable(struct pccard_function *pf);
9282378Sjonstatic int	pccard_compat_do_probe(device_t bus, device_t dev);
9382378Sjonstatic int	pccard_compat_do_attach(device_t bus, device_t dev);
9482378Sjonstatic int	pccard_add_children(device_t dev, int busno);
9582378Sjonstatic int	pccard_probe(device_t dev);
9682378Sjonstatic int	pccard_attach(device_t dev);
9782378Sjonstatic int	pccard_detach(device_t dev);
9882378Sjonstatic void	pccard_print_resources(struct resource_list *rl,
9982378Sjon		    const char *name, int type, int count, const char *format);
10082378Sjonstatic int	pccard_print_child(device_t dev, device_t child);
10182378Sjonstatic int	pccard_set_resource(device_t dev, device_t child, int type,
10282378Sjon		    int rid, u_long start, u_long count);
10382378Sjonstatic int	pccard_get_resource(device_t dev, device_t child, int type,
10482378Sjon		    int rid, u_long *startp, u_long *countp);
10582378Sjonstatic void	pccard_delete_resource(device_t dev, device_t child, int type,
10682378Sjon		    int rid);
10782378Sjonstatic int	pccard_set_res_flags(device_t dev, device_t child, int type,
10882378Sjon		    int rid, u_int32_t flags);
10982378Sjonstatic int	pccard_set_memory_offset(device_t dev, device_t child, int rid,
11082378Sjon		    u_int32_t offset, u_int32_t *deltap);
11182378Sjonstatic int	pccard_read_ivar(device_t bus, device_t child, int which,
11282378Sjon		    u_char *result);
11382378Sjonstatic void	pccard_driver_added(device_t dev, driver_t *driver);
11482378Sjonstatic struct resource *pccard_alloc_resource(device_t dev,
11582378Sjon		    device_t child, int type, int *rid, u_long start,
11682378Sjon		    u_long end, u_long count, u_int flags);
11782378Sjonstatic int	pccard_release_resource(device_t dev, device_t child, int type,
11882378Sjon		    int rid, struct resource *r);
11982378Sjonstatic void	pccard_child_detached(device_t parent, device_t dev);
12082378Sjonstatic void	pccard_intr(void *arg);
12182378Sjonstatic int	pccard_setup_intr(device_t dev, device_t child,
12282378Sjon		    struct resource *irq, int flags, driver_intr_t *intr,
12382378Sjon		    void *arg, void **cookiep);
12482378Sjonstatic int	pccard_teardown_intr(device_t dev, device_t child,
12582378Sjon		    struct resource *r, void *cookie);
12652506Simp
12797613Stakawatastatic const struct pccard_product *
12897613Stakawatapccard_do_product_lookup(device_t bus, device_t dev,
12997613Stakawata			 const struct pccard_product *tab, size_t ent_size,
13097613Stakawata			 pccard_product_match_fn matchfn);
13197613Stakawata
13297613Stakawata
13382378Sjonstatic int
13474632Simppccard_ccr_read(struct pccard_function *pf, int ccr)
13552506Simp{
13652506Simp	return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
13752506Simp	    pf->pf_ccr_offset + ccr));
13852506Simp}
13952506Simp
14082378Sjonstatic void
14174632Simppccard_ccr_write(struct pccard_function *pf, int ccr, int val)
14252506Simp{
14352506Simp	if ((pf->ccr_mask) & (1 << (ccr / 2))) {
14452506Simp		bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
14552506Simp		    pf->pf_ccr_offset + ccr, val);
14652506Simp	}
14752506Simp}
14852506Simp
14959193Simpstatic int
15059193Simppccard_attach_card(device_t dev)
15152506Simp{
15264850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
15352506Simp	struct pccard_function *pf;
15465917Simp	struct pccard_ivar *ivar;
15561788Simp	device_t child;
156102713Simp	int i;
15752506Simp
15852506Simp	/*
15952506Simp	 * this is here so that when socket_enable calls gettype, trt happens
16052506Simp	 */
16152506Simp	STAILQ_INIT(&sc->card.pf_head);
16252506Simp
16355500Simp	DEVPRINTF((dev, "chip_socket_enable\n"));
16455500Simp	POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
16552506Simp
16655500Simp	DEVPRINTF((dev, "read_cis\n"));
16752506Simp	pccard_read_cis(sc);
16852506Simp
16955500Simp	DEVPRINTF((dev, "check_cis_quirks\n"));
17052506Simp	pccard_check_cis_quirks(dev);
17152506Simp
17252506Simp	/*
17352506Simp	 * bail now if the card has no functions, or if there was an error in
17452506Simp	 * the cis.
17552506Simp	 */
17652506Simp
17770715Sjon	if (sc->card.error) {
178102713Simp		device_printf(dev, "CARD ERROR!\n");
17952506Simp		return (1);
18070715Sjon	}
18170715Sjon	if (STAILQ_EMPTY(&sc->card.pf_head)) {
182102713Simp		device_printf(dev, "Card has no functions!\n");
18352506Simp		return (1);
18470715Sjon	}
18552506Simp
18690436Simp	if (bootverbose || pccard_debug)
18752506Simp		pccard_print_cis(dev);
18852506Simp
18955500Simp	DEVPRINTF((dev, "functions scanning\n"));
190102713Simp	i = -1;
19152506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
192102713Simp		i++;
193102713Simp		if (STAILQ_EMPTY(&pf->cfe_head)) {
194102713Simp			device_printf(dev,
195102713Simp			    "Function %d has no config entries.!\n", i);
19652506Simp			continue;
197102713Simp		}
19852506Simp		pf->sc = sc;
19952506Simp		pf->cfe = NULL;
20064927Simp		pf->dev = NULL;
20152506Simp	}
202102713Simp	DEVPRINTF((dev, "Card has %d functions. pccard_mfc is %d\n", i,
203102713Simp	    pccard_mfc(sc)));
20482378Sjon
20552506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
20652506Simp		if (STAILQ_EMPTY(&pf->cfe_head))
20752506Simp			continue;
20861788Simp		/*
20961788Simp		 * In NetBSD, the drivers are responsible for activating
21061788Simp		 * each function of a card.  I think that in FreeBSD we
21161788Simp		 * want to activate them enough for the usual bus_*_resource
21261788Simp		 * routines will do the right thing.  This many mean a
21361788Simp		 * departure from the current NetBSD model.
21461788Simp		 *
21561788Simp		 * This could get really ugly for multifunction cards.  But
21661788Simp		 * it might also just fall out of the FreeBSD resource model.
21761788Simp		 *
21861788Simp		 */
21967897Sdwmalone		ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF,
22067897Sdwmalone		    M_WAITOK | M_ZERO);
22161788Simp		child = device_add_child(dev, NULL, -1);
22265917Simp		device_set_ivars(child, ivar);
22366847Simp		ivar->fcn = pf;
22467187Simp		pf->dev = child;
22567167Simp		/*
22667167Simp		 * XXX We might want to move the next two lines into
22767167Simp		 * XXX the pccard interface layer.  For the moment, this
22867167Simp		 * XXX is OK, but some drivers want to pick the config
22967167Simp		 * XXX entry to use as well as some address tweaks (mostly
23067167Simp		 * XXX due to bugs in decode logic that makes some
23167167Simp		 * XXX addresses illegal or broken).
23267167Simp		 */
23365917Simp		pccard_function_init(pf);
23482378Sjon		if (sc->sc_enabled_count == 0)
23582378Sjon			POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
23667333Simp		if (pccard_function_enable(pf) == 0 &&
23767333Simp		    device_probe_and_attach(child) == 0) {
23855500Simp			DEVPRINTF((sc->dev, "function %d CCR at %d "
23967167Simp			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
24067167Simp			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
24167167Simp			    pccard_ccr_read(pf, 0x00),
24252506Simp			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
24352506Simp			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
24452506Simp			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
24552506Simp			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
24667167Simp		} else {
24786907Simp			if (pf->cfe != NULL)
24886907Simp				pccard_function_disable(pf);
24952506Simp		}
25052506Simp	}
25174632Simp	return (0);
25252506Simp}
25352506Simp
25459193Simpstatic int
25559193Simppccard_detach_card(device_t dev, int flags)
25652506Simp{
25764850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
25852506Simp	struct pccard_function *pf;
25982378Sjon	struct pccard_config_entry *cfe;
26052506Simp
26152506Simp	/*
26252506Simp	 * We are running on either the PCCARD socket's event thread
26352506Simp	 * or in user context detaching a device by user request.
26452506Simp	 */
26552506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
26682378Sjon		int state = device_get_state(pf->dev);
26761788Simp
26882378Sjon		if (state == DS_ATTACHED || state == DS_BUSY)
26982378Sjon			device_detach(pf->dev);
27086907Simp		if (pf->cfe != NULL)
27186907Simp			pccard_function_disable(pf);
27282378Sjon		pccard_function_free(pf);
27376424Simp		if (pf->dev != NULL)
27464927Simp			device_delete_child(dev, pf->dev);
27552506Simp	}
27682378Sjon	if (sc->sc_enabled_count == 0)
27782378Sjon		POWER_DISABLE_SOCKET(device_get_parent(dev), dev);
27882378Sjon
27982378Sjon	while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) {
28082378Sjon		while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) {
28182378Sjon			STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list);
28282378Sjon			free(cfe, M_DEVBUF);
28382378Sjon		}
28482378Sjon		STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list);
28582378Sjon		free(pf, M_DEVBUF);
28682378Sjon	}
28774632Simp	return (0);
28852506Simp}
28952506Simp
29097613Stakawatastatic const struct pccard_product *
29197613Stakawatapccard_do_product_lookup(device_t bus, device_t dev,
29297613Stakawata			 const struct pccard_product *tab, size_t ent_size,
29397613Stakawata			 pccard_product_match_fn matchfn)
29466200Simp{
29566200Simp	const struct pccard_product *ent;
29666200Simp	int matches;
29766200Simp	u_int32_t fcn;
29866200Simp	u_int32_t vendor;
29966200Simp	u_int32_t prod;
30066200Simp	char *vendorstr;
30166200Simp	char *prodstr;
30266200Simp
30366200Simp#ifdef DIAGNOSTIC
30466200Simp	if (sizeof *ent > ent_size)
30570715Sjon		panic("pccard_product_lookup: bogus ent_size %ld",
30666200Simp		    (long) ent_size);
30766200Simp#endif
30866200Simp	if (pccard_get_vendor(dev, &vendor))
30966200Simp		return (NULL);
31066200Simp	if (pccard_get_product(dev, &prod))
31166200Simp		return (NULL);
31266200Simp	if (pccard_get_function_number(dev, &fcn))
31366200Simp		return (NULL);
31466200Simp	if (pccard_get_vendor_str(dev, &vendorstr))
31566200Simp		return (NULL);
31666200Simp	if (pccard_get_product_str(dev, &prodstr))
31766200Simp		return (NULL);
31882378Sjon	for (ent = tab; ent->pp_name != NULL; ent =
31982378Sjon	    (const struct pccard_product *) ((const char *) ent + ent_size)) {
32066200Simp		matches = 1;
32186642Simp		if (ent->pp_vendor == PCCARD_VENDOR_ANY &&
32286642Simp		    ent->pp_product == PCCARD_VENDOR_ANY &&
32386642Simp		    ent->pp_cis[0] == NULL &&
32486642Simp		    ent->pp_cis[1] == NULL) {
32586642Simp			device_printf(dev,
32686642Simp			    "Total wildcard entry ignored for %s\n",
32786642Simp			    ent->pp_name);
32886642Simp			continue;
32986642Simp		}
33066200Simp		if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY &&
33166200Simp		    vendor != ent->pp_vendor)
33266200Simp			matches = 0;
33366200Simp		if (matches && ent->pp_product != PCCARD_PRODUCT_ANY &&
33466200Simp		    prod != ent->pp_product)
33566200Simp			matches = 0;
33666200Simp		if (matches && fcn != ent->pp_expfunc)
33766200Simp			matches = 0;
33871322Simp		if (matches && ent->pp_cis[0] &&
33971322Simp		    strcmp(ent->pp_cis[0], vendorstr) != 0)
34066200Simp			matches = 0;
34171322Simp		if (matches && ent->pp_cis[1] &&
34271322Simp		    strcmp(ent->pp_cis[1], prodstr) != 0)
34366200Simp			matches = 0;
34471322Simp		/* XXX need to match cis[2] and cis[3] also XXX */
34566200Simp		if (matchfn != NULL)
34666200Simp			matches = (*matchfn)(dev, ent, matches);
34766200Simp		if (matches)
34866200Simp			return (ent);
34966200Simp	}
35066200Simp	return (NULL);
35166200Simp}
35266200Simp
35370715Sjonstatic int
35459193Simppccard_card_gettype(device_t dev, int *type)
35552506Simp{
35664850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
35752506Simp	struct pccard_function *pf;
35852506Simp
35952506Simp	/*
36052506Simp	 * set the iftype to memory if this card has no functions (not yet
36152506Simp	 * probed), or only one function, and that is not initialized yet or
36252506Simp	 * that is memory.
36352506Simp	 */
36452506Simp	pf = STAILQ_FIRST(&sc->card.pf_head);
36552506Simp	if (pf == NULL ||
36652506Simp	    (STAILQ_NEXT(pf, pf_list) == NULL &&
36752506Simp	    (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY)))
36859193Simp		*type = PCCARD_IFTYPE_MEMORY;
36952506Simp	else
37059193Simp		*type = PCCARD_IFTYPE_IO;
37174632Simp	return (0);
37252506Simp}
37352506Simp
37452506Simp/*
37552506Simp * Initialize a PCCARD function.  May be called as long as the function is
37652506Simp * disabled.
37782382Simp *
37882382Simp * Note: pccard_function_init should not keep resources allocated.  It should
37982382Simp * only set them up ala isa pnp, set the values in the rl lists, and return.
38082382Simp * Any resource held after pccard_function_init is called is a bug.  However,
38182382Simp * the bus routines to get the resources also assume that pccard_function_init
38282382Simp * does this, so they need to be fixed too.
38352506Simp */
38482378Sjonstatic void
38570715Sjonpccard_function_init(struct pccard_function *pf)
38652506Simp{
38765917Simp	struct pccard_config_entry *cfe;
38867187Simp	int i;
38967242Simp	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
39067242Simp	struct resource_list *rl = &devi->resources;
39170762Simp	struct resource_list_entry *rle;
39267242Simp	struct resource *r = 0;
39367242Simp	device_t bus;
39467424Simp	int start;
39567424Simp	int end;
39690897Simp	int spaces;
39765917Simp
39870715Sjon	if (pf->pf_flags & PFF_ENABLED) {
39970715Sjon		printf("pccard_function_init: function is enabled");
40070715Sjon		return;
40170715Sjon	}
40267242Simp	bus = device_get_parent(pf->dev);
40352506Simp	/* Remember which configuration entry we are using. */
40472012Sphk	STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
40567187Simp		for (i = 0; i < cfe->num_iospace; i++)
40667187Simp			cfe->iores[i] = NULL;
40767187Simp		cfe->irqres = NULL;
40890897Simp		spaces = 0;
40967187Simp		for (i = 0; i < cfe->num_iospace; i++) {
41067424Simp			start = cfe->iospace[i].start;
41167424Simp			if (start)
41267424Simp				end = start + cfe->iospace[i].length - 1;
41367424Simp			else
41467424Simp				end = ~0;
41567187Simp			cfe->iorid[i] = i;
41690897Simp			DEVPRINTF((bus, "I/O rid %d start %x end %x\n",
41790897Simp			    i, start, end));
41867242Simp			r = cfe->iores[i] = bus_alloc_resource(bus,
41967424Simp			    SYS_RES_IOPORT, &cfe->iorid[i], start, end,
42070715Sjon			    cfe->iospace[i].length,
42167424Simp			    rman_make_alignment_flags(cfe->iospace[i].length));
42276424Simp			if (cfe->iores[i] == NULL)
42367187Simp				goto not_this_one;
42467242Simp			resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i],
42567242Simp			    rman_get_start(r), rman_get_end(r),
42667242Simp			    cfe->iospace[i].length);
42776424Simp			rle = resource_list_find(rl, SYS_RES_IOPORT,
42876424Simp			    cfe->iorid[i]);
42976424Simp			rle->res = r;
43090897Simp			spaces++;
43167187Simp		}
43267187Simp		if (cfe->num_memspace > 0) {
43382781Sshiba			/*
43482781Sshiba			 * Not implement yet, Fix me.
43582781Sshiba			 */
43690897Simp			DEVPRINTF((bus, "Memory space not yet implemented.\n"));
43767187Simp		}
43890897Simp		if (spaces == 0) {
43990897Simp			DEVPRINTF((bus, "Neither memory nor I/O mampped\n"));
44090897Simp			goto not_this_one;
44190897Simp		}
44267187Simp		if (cfe->irqmask) {
44367187Simp			cfe->irqrid = 0;
44467399Simp			r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ,
44567424Simp			    &cfe->irqrid, 0, ~0, 1, 0);
44676424Simp			if (cfe->irqres == NULL)
44767187Simp				goto not_this_one;
44867242Simp			resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid,
44967242Simp			    rman_get_start(r), rman_get_end(r), 1);
45076424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
45176424Simp			    cfe->irqrid);
45276424Simp			rle->res = r;
45367187Simp		}
45467187Simp		/* If we get to here, we've allocated all we need */
45567167Simp		pf->cfe = cfe;
45667187Simp		break;
45767187Simp	    not_this_one:;
45867424Simp		DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n",
45967424Simp		    cfe->number));
46067333Simp		/*
46167333Simp		 * Release resources that we partially allocated
46267333Simp		 * from this config entry.
46367333Simp		 */
46467187Simp		for (i = 0; i < cfe->num_iospace; i++) {
46576424Simp			if (cfe->iores[i] != NULL) {
46670715Sjon				bus_release_resource(bus, SYS_RES_IOPORT,
46767187Simp				    cfe->iorid[i], cfe->iores[i]);
46882378Sjon				rle = resource_list_find(rl, SYS_RES_IOPORT,
46976424Simp				    cfe->iorid[i]);
47076424Simp				rle->res = NULL;
47176424Simp				resource_list_delete(rl, SYS_RES_IOPORT,
47276424Simp				    cfe->iorid[i]);
47375756Simp			}
47467187Simp			cfe->iores[i] = NULL;
47567187Simp		}
47676424Simp		if (cfe->irqmask && cfe->irqres != NULL) {
47767242Simp			bus_release_resource(bus, SYS_RES_IRQ,
47867187Simp			    cfe->irqrid, cfe->irqres);
47976424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
48076424Simp			    cfe->irqrid);
48176424Simp			rle->res = NULL;
48276424Simp			resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid);
48367187Simp			cfe->irqres = NULL;
48467187Simp		}
48567167Simp	}
48652506Simp}
48752506Simp
48882378Sjon/*
48982378Sjon * Free resources allocated by pccard_function_init(), May be called as long
49082378Sjon * as the function is disabled.
49182382Simp *
49282382Simp * NOTE: This function should be unnecessary.  pccard_function_init should
49382382Simp * never keep resources initialized.
49482378Sjon */
49582378Sjonstatic void
49682378Sjonpccard_function_free(struct pccard_function *pf)
49782378Sjon{
49882378Sjon	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
49982378Sjon	struct resource_list_entry *rle;
50082378Sjon
50182378Sjon	if (pf->pf_flags & PFF_ENABLED) {
50282378Sjon		printf("pccard_function_init: function is enabled");
50382378Sjon		return;
50482378Sjon	}
50582378Sjon
50682378Sjon	SLIST_FOREACH(rle, &devi->resources, link) {
50782378Sjon		if (rle->res) {
50882378Sjon			if (rle->res->r_dev != pf->sc->dev)
50982378Sjon				device_printf(pf->sc->dev,
51082378Sjon				    "function_free: Resource still owned by "
51182378Sjon				    "child, oops. "
51282378Sjon				    "(type=%d, rid=%d, addr=%lx)\n",
51382378Sjon				    rle->type, rle->rid,
51482378Sjon				    rman_get_start(rle->res));
51582378Sjon			BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
51682378Sjon			    rle->res->r_dev, rle->type, rle->rid, rle->res);
51782378Sjon			rle->res = NULL;
51882378Sjon		}
51982378Sjon	}
52082378Sjon	resource_list_free(&devi->resources);
52182378Sjon}
52282378Sjon
52352506Simp/* Enable a PCCARD function */
52482378Sjonstatic int
52555720Simppccard_function_enable(struct pccard_function *pf)
52652506Simp{
52752506Simp	struct pccard_function *tmp;
52852506Simp	int reg;
52955720Simp	device_t dev = pf->sc->dev;
53070746Simp
53167333Simp	if (pf->cfe == NULL) {
53267333Simp		DEVPRVERBOSE((dev, "No config entry could be allocated.\n"));
53374632Simp		return (ENOMEM);
53467333Simp	}
53552506Simp
53652506Simp	/*
53752506Simp	 * Increase the reference count on the socket, enabling power, if
53852506Simp	 * necessary.
53952506Simp	 */
54082378Sjon	pf->sc->sc_enabled_count++;
54152506Simp
54252506Simp	if (pf->pf_flags & PFF_ENABLED) {
54352506Simp		/*
54452506Simp		 * Don't do anything if we're already enabled.
54552506Simp		 */
54652506Simp		return (0);
54752506Simp	}
54852506Simp
54952506Simp	/*
55052506Simp	 * it's possible for different functions' CCRs to be in the same
55152506Simp	 * underlying page.  Check for that.
55252506Simp	 */
55352506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
55452506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
55552506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
55652506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
55782378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
55882378Sjon		    tmp->pf_ccr_realsize))) {
55952506Simp			pf->pf_ccrt = tmp->pf_ccrt;
56052506Simp			pf->pf_ccrh = tmp->pf_ccrh;
56152506Simp			pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
56252506Simp
56352506Simp			/*
56452506Simp			 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
56552506Simp			 * tmp->ccr_base) + pf->ccr_base;
56652506Simp			 */
56770715Sjon			/* pf->pf_ccr_offset =
56852506Simp			    (tmp->pf_ccr_offset + pf->ccr_base) -
56970715Sjon			    tmp->ccr_base; */
57052506Simp			pf->pf_ccr_window = tmp->pf_ccr_window;
57152506Simp			break;
57252506Simp		}
57352506Simp	}
57452506Simp	if (tmp == NULL) {
57555720Simp		pf->ccr_rid = 0;
57655720Simp		pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
57770715Sjon		    &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE);
57870715Sjon		if (!pf->ccr_res)
57952506Simp			goto bad;
58070746Simp		DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%lx\n",
58170746Simp		    rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res),
58270746Simp		    pf->ccr_base));
58361788Simp		CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
58461788Simp		    pf->ccr_rid, PCCARD_A_MEM_ATTR);
58570715Sjon		CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev,
58670748Simp		    pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset);
58755720Simp		pf->pf_ccrt = rman_get_bustag(pf->ccr_res);
58855720Simp		pf->pf_ccrh = rman_get_bushandle(pf->ccr_res);
58955720Simp		pf->pf_ccr_realsize = 1;
59052506Simp	}
59152506Simp
59252506Simp	reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX);
59352506Simp	reg |= PCCARD_CCR_OPTION_LEVIREQ;
59452506Simp	if (pccard_mfc(pf->sc)) {
59552506Simp		reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE |
59652506Simp			PCCARD_CCR_OPTION_ADDR_DECODE);
59782383Simp		/* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */
59852506Simp	}
59952506Simp	pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
60052506Simp
60152506Simp	reg = 0;
60252506Simp	if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0)
60352506Simp		reg |= PCCARD_CCR_STATUS_IOIS8;
60452506Simp	if (pf->cfe->flags & PCCARD_CFE_AUDIO)
60552506Simp		reg |= PCCARD_CCR_STATUS_AUDIO;
60652506Simp	pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg);
60752506Simp
60852506Simp	pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0);
60952506Simp
61052506Simp	if (pccard_mfc(pf->sc)) {
61152506Simp		long tmp, iosize;
61252506Simp
61352506Simp		tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
61452506Simp		/* round up to nearest (2^n)-1 */
61552506Simp		for (iosize = 1; iosize < tmp; iosize <<= 1)
61652506Simp			;
61752506Simp		iosize--;
61852506Simp
61952506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
62052506Simp				 pf->pf_mfc_iobase & 0xff);
62152506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
62252506Simp				 (pf->pf_mfc_iobase >> 8) & 0xff);
62352506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
62452506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
62552506Simp
62652506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
62752506Simp	}
62852506Simp
62952506Simp#ifdef PCCARDDEBUG
63052506Simp	if (pccard_debug) {
63152506Simp		STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
63270715Sjon			device_printf(tmp->sc->dev,
63355500Simp			    "function %d CCR at %d offset %x: "
63455500Simp			    "%x %x %x %x, %x %x %x %x, %x\n",
63570715Sjon			    tmp->number, tmp->pf_ccr_window,
63655500Simp			    tmp->pf_ccr_offset,
63755500Simp			    pccard_ccr_read(tmp, 0x00),
63855500Simp			    pccard_ccr_read(tmp, 0x02),
63955500Simp			    pccard_ccr_read(tmp, 0x04),
64055500Simp			    pccard_ccr_read(tmp, 0x06),
64155500Simp			    pccard_ccr_read(tmp, 0x0A),
64270715Sjon			    pccard_ccr_read(tmp, 0x0C),
64355500Simp			    pccard_ccr_read(tmp, 0x0E),
64455500Simp			    pccard_ccr_read(tmp, 0x10),
64555500Simp			    pccard_ccr_read(tmp, 0x12));
64652506Simp		}
64752506Simp	}
64852506Simp#endif
64952506Simp	pf->pf_flags |= PFF_ENABLED;
65052506Simp	return (0);
65152506Simp
65252506Simp bad:
65352506Simp	/*
65452506Simp	 * Decrement the reference count, and power down the socket, if
65552506Simp	 * necessary.
65652506Simp	 */
65782378Sjon	pf->sc->sc_enabled_count--;
65865098Simp	DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count));
65952506Simp
66052506Simp	return (1);
66152506Simp}
66252506Simp
66352506Simp/* Disable PCCARD function. */
66482378Sjonstatic void
66555720Simppccard_function_disable(struct pccard_function *pf)
66652506Simp{
66752506Simp	struct pccard_function *tmp;
66855720Simp	device_t dev = pf->sc->dev;
66952506Simp
67052506Simp	if (pf->cfe == NULL)
67161788Simp		panic("pccard_function_disable: function not initialized");
67252506Simp
67352506Simp	if ((pf->pf_flags & PFF_ENABLED) == 0) {
67452506Simp		/*
67552506Simp		 * Don't do anything if we're already disabled.
67652506Simp		 */
67752506Simp		return;
67852506Simp	}
67952506Simp
68070715Sjon	if (pf->intr_handler != NULL) {
68182378Sjon		struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
68282378Sjon		struct resource_list_entry *rle =
68382378Sjon		    resource_list_find(&devi->resources, SYS_RES_IRQ, 0);
68482378Sjon		BUS_TEARDOWN_INTR(dev, pf->dev, rle->res,
68582378Sjon		    pf->intr_handler_cookie);
68670715Sjon	}
68770715Sjon
68852506Simp	/*
68952506Simp	 * it's possible for different functions' CCRs to be in the same
69052506Simp	 * underlying page.  Check for that.  Note we mark us as disabled
69152506Simp	 * first to avoid matching ourself.
69252506Simp	 */
69352506Simp
69452506Simp	pf->pf_flags &= ~PFF_ENABLED;
69552506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
69652506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
69752506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
69852506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
69982378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
70082378Sjon		    tmp->pf_ccr_realsize)))
70152506Simp			break;
70252506Simp	}
70352506Simp
70452506Simp	/* Not used by anyone else; unmap the CCR. */
70552506Simp	if (tmp == NULL) {
70670715Sjon		bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid,
70755720Simp		    pf->ccr_res);
70855720Simp		pf->ccr_res = NULL;
70952506Simp	}
71052506Simp
71152506Simp	/*
71252506Simp	 * Decrement the reference count, and power down the socket, if
71352506Simp	 * necessary.
71452506Simp	 */
71582378Sjon	pf->sc->sc_enabled_count--;
71652506Simp}
71752506Simp
71866058Simp/*
71966058Simp * simulate the old "probe" routine.  In the new world order, the driver
72066058Simp * needs to grab devices while in the old they were assigned to the device by
72166058Simp * the pccardd process.  These symbols are exported to the upper layers.
72266058Simp */
72374636Simpstatic int
72474636Simppccard_compat_do_probe(device_t bus, device_t dev)
72566058Simp{
72666058Simp	return (CARD_COMPAT_MATCH(dev));
72766058Simp}
72866058Simp
72974636Simpstatic int
73074636Simppccard_compat_do_attach(device_t bus, device_t dev)
73166058Simp{
73266058Simp	int err;
73366058Simp
73466058Simp	err = CARD_COMPAT_PROBE(dev);
73566058Simp	if (err == 0)
73666058Simp		err = CARD_COMPAT_ATTACH(dev);
73766058Simp	return (err);
73866058Simp}
73966058Simp
74053873Simp#define PCCARD_NPORT	2
74153873Simp#define PCCARD_NMEM	5
74253873Simp#define PCCARD_NIRQ	1
74353873Simp#define PCCARD_NDRQ	0
74453873Simp
74552506Simpstatic int
74652506Simppccard_add_children(device_t dev, int busno)
74752506Simp{
74859193Simp	/* Call parent to scan for any current children */
74974632Simp	return (0);
75052506Simp}
75152506Simp
75252506Simpstatic int
75352506Simppccard_probe(device_t dev)
75452506Simp{
75567333Simp	device_set_desc(dev, "16-bit PCCard bus");
75674632Simp	return (pccard_add_children(dev, device_get_unit(dev)));
75752506Simp}
75852506Simp
75959193Simpstatic int
76059193Simppccard_attach(device_t dev)
76159193Simp{
76264850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
76361788Simp
76459193Simp	sc->dev = dev;
76561788Simp	sc->sc_enabled_count = 0;
76674632Simp	return (bus_generic_attach(dev));
76759193Simp}
76859193Simp
76982378Sjonstatic int
77082378Sjonpccard_detach(device_t dev)
77182378Sjon{
77282378Sjon	pccard_detach_card(dev, 0);
77382378Sjon	return 0;
77482378Sjon}
77582378Sjon
77687975Simpstatic int
77787975Simppccard_suspend(device_t self)
77887975Simp{
77987975Simp	pccard_detach_card(self, 0);
78087975Simp	return (0);
78187975Simp}
78287975Simp
78387975Simpstatic
78487975Simpint
78587975Simppccard_resume(device_t self)
78687975Simp{
78787975Simp	return (0);
78887975Simp}
78987975Simp
79053873Simpstatic void
79153873Simppccard_print_resources(struct resource_list *rl, const char *name, int type,
79253873Simp    int count, const char *format)
79353873Simp{
79453873Simp	struct resource_list_entry *rle;
79553873Simp	int printed;
79653873Simp	int i;
79753873Simp
79853873Simp	printed = 0;
79953873Simp	for (i = 0; i < count; i++) {
80053873Simp		rle = resource_list_find(rl, type, i);
80176424Simp		if (rle != NULL) {
80253873Simp			if (printed == 0)
80353873Simp				printf(" %s ", name);
80453873Simp			else if (printed > 0)
80553873Simp				printf(",");
80653873Simp			printed++;
80753873Simp			printf(format, rle->start);
80853873Simp			if (rle->count > 1) {
80953873Simp				printf("-");
81053873Simp				printf(format, rle->start + rle->count - 1);
81153873Simp			}
81253873Simp		} else if (i > 3) {
81353873Simp			/* check the first few regardless */
81453873Simp			break;
81553873Simp		}
81653873Simp	}
81753873Simp}
81853873Simp
81953873Simpstatic int
82053873Simppccard_print_child(device_t dev, device_t child)
82153873Simp{
82266847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
82353873Simp	struct resource_list *rl = &devi->resources;
82453873Simp	int retval = 0;
82553873Simp
82653873Simp	retval += bus_print_child_header(dev, child);
82753873Simp	retval += printf(" at");
82853873Simp
82976424Simp	if (devi != NULL) {
83053873Simp		pccard_print_resources(rl, "port", SYS_RES_IOPORT,
83153873Simp		    PCCARD_NPORT, "%#lx");
83253873Simp		pccard_print_resources(rl, "iomem", SYS_RES_MEMORY,
83353873Simp		    PCCARD_NMEM, "%#lx");
83453873Simp		pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ,
83553873Simp		    "%ld");
83670715Sjon		pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ,
83753873Simp		    "%ld");
83867269Simp		retval += printf(" function %d config %d", devi->fcn->number,
83967269Simp		    devi->fcn->cfe->number);
84053873Simp	}
84153873Simp
84253873Simp	retval += bus_print_child_footer(dev, child);
84353873Simp
84453873Simp	return (retval);
84553873Simp}
84653873Simp
84753873Simpstatic int
84853873Simppccard_set_resource(device_t dev, device_t child, int type, int rid,
84953873Simp		 u_long start, u_long count)
85053873Simp{
85166847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
85253873Simp	struct resource_list *rl = &devi->resources;
85353873Simp
85453873Simp	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
85553873Simp	    && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
85674632Simp		return (EINVAL);
85753873Simp	if (rid < 0)
85874632Simp		return (EINVAL);
85953873Simp	if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT)
86074632Simp		return (EINVAL);
86153873Simp	if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM)
86274632Simp		return (EINVAL);
86353873Simp	if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ)
86474632Simp		return (EINVAL);
86553873Simp	if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ)
86674632Simp		return (EINVAL);
86753873Simp
86853873Simp	resource_list_add(rl, type, rid, start, start + count - 1, count);
86982378Sjon	if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev,
87082378Sjon	    type, &rid, start, start + count - 1, count, 0))
87182378Sjon		return 0;
87282378Sjon	else
87382378Sjon		return ENOMEM;
87453873Simp}
87553873Simp
87653873Simpstatic int
87753873Simppccard_get_resource(device_t dev, device_t child, int type, int rid,
87853873Simp    u_long *startp, u_long *countp)
87953873Simp{
88066847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
88153873Simp	struct resource_list *rl = &devi->resources;
88253873Simp	struct resource_list_entry *rle;
88353873Simp
88453873Simp	rle = resource_list_find(rl, type, rid);
88576424Simp	if (rle == NULL)
88674632Simp		return (ENOENT);
88770715Sjon
88876424Simp	if (startp != NULL)
88953873Simp		*startp = rle->start;
89076424Simp	if (countp != NULL)
89153873Simp		*countp = rle->count;
89253873Simp
89374632Simp	return (0);
89453873Simp}
89553873Simp
89653873Simpstatic void
89753873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid)
89853873Simp{
89966847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
90053873Simp	struct resource_list *rl = &devi->resources;
90153873Simp	resource_list_delete(rl, type, rid);
90253873Simp}
90353873Simp
90459193Simpstatic int
90559193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid,
90659193Simp    u_int32_t flags)
90759193Simp{
90874632Simp	return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type,
90974632Simp	    rid, flags));
91059193Simp}
91159193Simp
91259193Simpstatic int
91359193Simppccard_set_memory_offset(device_t dev, device_t child, int rid,
91482378Sjon    u_int32_t offset, u_int32_t *deltap)
91570715Sjon
91659193Simp{
91774632Simp	return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid,
91874632Simp	    offset, deltap));
91959193Simp}
92059193Simp
92166058Simpstatic int
92266058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result)
92366058Simp{
92466847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
92566779Simp	struct pccard_function *func = devi->fcn;
92666779Simp	struct pccard_softc *sc = PCCARD_SOFTC(bus);
92766779Simp
92866779Simp	switch (which) {
92966779Simp	default:
93066779Simp	case PCCARD_IVAR_ETHADDR:
93182781Sshiba		bcopy(func->pf_funce_lan_nid, result, ETHER_ADDR_LEN);
93266779Simp		break;
93366779Simp	case PCCARD_IVAR_VENDOR:
93466779Simp		*(u_int32_t *) result = sc->card.manufacturer;
93566779Simp		break;
93666779Simp	case PCCARD_IVAR_PRODUCT:
93766779Simp		*(u_int32_t *) result = sc->card.product;
93866779Simp		break;
93990964Sshiba	case PCCARD_IVAR_PRODEXT:
94090964Sshiba		*(u_int16_t *) result = sc->card.prodext;
94190964Sshiba		break;
94275761Simp	case PCCARD_IVAR_FUNCTION:
94375761Simp		*(u_int32_t *) result = func->function;
94475761Simp		break;
94566779Simp	case PCCARD_IVAR_FUNCTION_NUMBER:
94666847Simp		if (!func) {
94766847Simp			device_printf(bus, "No function number, bug!\n");
94866847Simp			return (ENOENT);
94966847Simp		}
95066847Simp		*(u_int32_t *) result = func->number;
95166779Simp		break;
95266779Simp	case PCCARD_IVAR_VENDOR_STR:
95366779Simp		*(char **) result = sc->card.cis1_info[0];
95466779Simp		break;
95566779Simp	case PCCARD_IVAR_PRODUCT_STR:
95666779Simp		*(char **) result = sc->card.cis1_info[1];
95766779Simp		break;
95866779Simp	case PCCARD_IVAR_CIS3_STR:
95966779Simp		*(char **) result = sc->card.cis1_info[2];
96066779Simp		break;
96167167Simp	case PCCARD_IVAR_CIS4_STR:
962104610Simp		*(char **) result = sc->card.cis1_info[3];
96367167Simp		break;
96466779Simp	}
96566779Simp	return (0);
96666058Simp}
96766058Simp
96866779Simpstatic void
96966779Simppccard_driver_added(device_t dev, driver_t *driver)
97066779Simp{
97182378Sjon	struct pccard_softc *sc = PCCARD_SOFTC(dev);
97282378Sjon	struct pccard_function *pf;
97382378Sjon	device_t child;
97482378Sjon
97582378Sjon	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
97682378Sjon		if (STAILQ_EMPTY(&pf->cfe_head))
97782378Sjon			continue;
97882378Sjon		child = pf->dev;
97982378Sjon		if (device_get_state(child) != DS_NOTPRESENT)
98082378Sjon			continue;
98182378Sjon		if (pccard_function_enable(pf) == 0 &&
98282378Sjon		    device_probe_and_attach(child) == 0) {
98382378Sjon			DEVPRINTF((sc->dev, "function %d CCR at %d "
98482378Sjon			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
98582378Sjon			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
98682378Sjon			    pccard_ccr_read(pf, 0x00),
98782378Sjon			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
98882378Sjon			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
98982378Sjon			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
99082378Sjon			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
99182378Sjon		} else {
99286907Simp			if (pf->cfe != NULL)
99386907Simp				pccard_function_disable(pf);
99482378Sjon		}
99582378Sjon	}
99682378Sjon	return;
99766779Simp}
99866058Simp
99967242Simpstatic struct resource *
100067242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid,
100167242Simp    u_long start, u_long end, u_long count, u_int flags)
100267242Simp{
100382378Sjon	struct pccard_ivar *dinfo;
100482378Sjon	struct resource_list_entry *rle = 0;
100582378Sjon	int passthrough = (device_get_parent(child) != dev);
100667242Simp
100782378Sjon	if (passthrough) {
100882378Sjon		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
100982378Sjon		    type, rid, start, end, count, flags));
101082378Sjon	}
101170715Sjon
101282378Sjon	dinfo = device_get_ivars(child);
101382378Sjon	rle = resource_list_find(&dinfo->resources, type, *rid);
101470715Sjon
101582378Sjon	if (!rle)
101682378Sjon		return NULL;		/* no resource of that type/rid */
101770715Sjon
101882378Sjon	if (!rle->res) {
101982378Sjon		device_printf(dev, "WARNING: Resource not reserved by pccard bus\n");
102082378Sjon		return NULL;
102182378Sjon	} else {
102290897Simp		if (rle->res->r_dev != dev)
102390897Simp			return (NULL);
102482378Sjon		bus_release_resource(dev, type, *rid, rle->res);
102582378Sjon		rle->res = NULL;
102682378Sjon		switch(type) {
102782378Sjon		case SYS_RES_IOPORT:
102882378Sjon		case SYS_RES_MEMORY:
102982378Sjon			if (!(flags & RF_ALIGNMENT_MASK))
103082378Sjon				flags |= rman_make_alignment_flags(rle->count);
103182378Sjon			break;
103282378Sjon		case SYS_RES_IRQ:
103382378Sjon			flags |= RF_SHAREABLE;
103482378Sjon			break;
103582378Sjon		}
103690897Simp		rle->res = resource_list_alloc(&dinfo->resources, dev, child,
103790897Simp		    type, rid, rle->start, rle->end, rle->count, flags);
103890897Simp		return (rle->res);
103967269Simp	}
104067242Simp}
104167242Simp
104267242Simpstatic int
104367242Simppccard_release_resource(device_t dev, device_t child, int type, int rid,
104467242Simp    struct resource *r)
104567242Simp{
104682378Sjon	struct pccard_ivar *dinfo;
104782378Sjon	int passthrough = (device_get_parent(child) != dev);
104882378Sjon	struct resource_list_entry *rle = 0;
104982378Sjon	int ret;
105082378Sjon	int flags;
105170715Sjon
105282378Sjon	if (passthrough)
105382378Sjon		return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
105482378Sjon		    type, rid, r);
105570715Sjon
105682378Sjon	dinfo = device_get_ivars(child);
105770715Sjon
105882378Sjon	rle = resource_list_find(&dinfo->resources, type, rid);
105970715Sjon
106082378Sjon	if (!rle) {
106182378Sjon		device_printf(dev, "Allocated resource not found, "
106282378Sjon		    "%d %x %lx %lx\n",
106382378Sjon		    type, rid, rman_get_start(r), rman_get_size(r));
106482378Sjon		return ENOENT;
106570715Sjon	}
106682378Sjon	if (!rle->res) {
106782378Sjon		device_printf(dev, "Allocated resource not recorded\n");
106882378Sjon		return ENOENT;
106970715Sjon	}
107070715Sjon
107182378Sjon	ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
107282378Sjon	    type, rid, r);
107382378Sjon	switch(type) {
107482378Sjon	case SYS_RES_IOPORT:
107582378Sjon	case SYS_RES_MEMORY:
107682378Sjon		flags = rman_make_alignment_flags(rle->count);
107782378Sjon		break;
107882378Sjon	case SYS_RES_IRQ:
107982378Sjon		flags = RF_SHAREABLE;
108082378Sjon		break;
108182378Sjon	default:
108282378Sjon		flags = 0;
108370715Sjon	}
108482378Sjon	rle->res = bus_alloc_resource(dev, type, &rid,
108582378Sjon	    rle->start, rle->end, rle->count, flags);
108682378Sjon	if (rle->res == NULL)
108782378Sjon		device_printf(dev, "release_resource: "
108882378Sjon		    "unable to reaquire resource\n");
108982378Sjon	return ret;
109067242Simp}
109167242Simp
109267333Simpstatic void
109367333Simppccard_child_detached(device_t parent, device_t dev)
109467333Simp{
109567333Simp	struct pccard_ivar *ivar = PCCARD_IVAR(dev);
109682378Sjon	struct pccard_function *pf = ivar->fcn;
109767333Simp
109882378Sjon	pccard_function_disable(pf);
109967333Simp}
110067333Simp
110170715Sjonstatic void
110270762Simppccard_intr(void *arg)
110370762Simp{
110482378Sjon	struct pccard_function *pf = (struct pccard_function*) arg;
110582378Sjon	int reg;
1106102923Simp	int doisr = 1;
110782378Sjon
110882383Simp	/*
1109102923Simp	 * MFC cards know if they interrupted, so we have to ack the
1110102923Simp	 * interrupt and call the ISR.  Non-MFC cards don't have these
1111102923Simp	 * bits, so they always get called.  Many non-MFC cards have
1112102923Simp	 * this bit set always upon read, but some do not.
1113102923Simp	 *
1114102923Simp	 * We always ack the interrupt, even if there's no ISR
1115102923Simp	 * for the card.  This is done on the theory that acking
1116102923Simp	 * the interrupt will pacify the card enough to keep an
1117102923Simp	 * interrupt storm from happening.  Of course this won't
1118102923Simp	 * help in the non-MFC case.
111982383Simp	 */
1120102923Simp	if (pccard_mfc(pf->sc)) {
1121102923Simp		reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
1122102923Simp		if (reg & PCCARD_CCR_STATUS_INTR)
1123102923Simp			pccard_ccr_write(pf, PCCARD_CCR_STATUS,
1124102923Simp			    reg & ~PCCARD_CCR_STATUS_INTR);
1125102923Simp		else
1126102923Simp			doisr = 0;
1127102923Simp	}
1128102923Simp	if (pf->intr_handler != NULL && doisr)
112982378Sjon		pf->intr_handler(pf->intr_handler_arg);
113070715Sjon}
113170715Sjon
113270715Sjonstatic int
113370762Simppccard_setup_intr(device_t dev, device_t child, struct resource *irq,
113470762Simp    int flags, driver_intr_t *intr, void *arg, void **cookiep)
113570715Sjon{
1136102713Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
113770715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
113870715Sjon	struct pccard_function *func = ivar->fcn;
113990445Simp	int err;
114070715Sjon
114170715Sjon	if (func->intr_handler != NULL)
1142101762Simp		panic("Only one interrupt handler per function allowed");
114390445Simp	err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr,
114490445Simp	    func, cookiep);
114590445Simp	if (err != 0)
114690445Simp		return (err);
114770715Sjon	func->intr_handler = intr;
114870715Sjon	func->intr_handler_arg = arg;
114982378Sjon	func->intr_handler_cookie = *cookiep;
1150102713Simp	if (pccard_mfc(sc)) {
1151102713Simp		pccard_ccr_write(func, PCCARD_CCR_OPTION,
1152102713Simp		    pccard_ccr_read(func, PCCARD_CCR_OPTION) |
1153102713Simp		    PCCARD_CCR_OPTION_IREQ_ENABLE);
1154102713Simp	}
115574632Simp	return (0);
115670715Sjon}
115770715Sjon
115870715Sjonstatic int
115970762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r,
116070762Simp    void *cookie)
116170715Sjon{
1162102713Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
116370715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
116470715Sjon	struct pccard_function *func = ivar->fcn;
116582378Sjon	int ret;
116670715Sjon
1167102713Simp	if (pccard_mfc(sc)) {
1168102713Simp		pccard_ccr_write(func, PCCARD_CCR_OPTION,
1169102713Simp		    pccard_ccr_read(func, PCCARD_CCR_OPTION) &
1170102713Simp		    ~PCCARD_CCR_OPTION_IREQ_ENABLE);
1171102713Simp	}
117290445Simp	ret = bus_generic_teardown_intr(dev, child, r, cookie);
117382378Sjon	if (ret == 0) {
117482378Sjon		func->intr_handler = NULL;
117582378Sjon		func->intr_handler_arg = NULL;
117682378Sjon		func->intr_handler_cookie = NULL;
117782378Sjon	}
117870715Sjon
117982378Sjon	return (ret);
118070715Sjon}
118170715Sjon
118252506Simpstatic device_method_t pccard_methods[] = {
118352506Simp	/* Device interface */
118452506Simp	DEVMETHOD(device_probe,		pccard_probe),
118559193Simp	DEVMETHOD(device_attach,	pccard_attach),
118682378Sjon	DEVMETHOD(device_detach,	pccard_detach),
118752506Simp	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
118887975Simp	DEVMETHOD(device_suspend,	pccard_suspend),
118987975Simp	DEVMETHOD(device_resume,	pccard_resume),
119052506Simp
119152506Simp	/* Bus interface */
119252506Simp	DEVMETHOD(bus_print_child,	pccard_print_child),
119366779Simp	DEVMETHOD(bus_driver_added,	pccard_driver_added),
119467333Simp	DEVMETHOD(bus_child_detached,	pccard_child_detached),
119567242Simp	DEVMETHOD(bus_alloc_resource,	pccard_alloc_resource),
119667242Simp	DEVMETHOD(bus_release_resource,	pccard_release_resource),
119782378Sjon	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
119882378Sjon	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
119970715Sjon	DEVMETHOD(bus_setup_intr,	pccard_setup_intr),
120070715Sjon	DEVMETHOD(bus_teardown_intr,	pccard_teardown_intr),
120152506Simp	DEVMETHOD(bus_set_resource,	pccard_set_resource),
120252506Simp	DEVMETHOD(bus_get_resource,	pccard_get_resource),
120352506Simp	DEVMETHOD(bus_delete_resource,	pccard_delete_resource),
120466058Simp	DEVMETHOD(bus_read_ivar,	pccard_read_ivar),
120552506Simp
120659193Simp	/* Card Interface */
120759193Simp	DEVMETHOD(card_set_res_flags,	pccard_set_res_flags),
120859193Simp	DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset),
120959193Simp	DEVMETHOD(card_get_type,	pccard_card_gettype),
121059193Simp	DEVMETHOD(card_attach_card,	pccard_attach_card),
121159193Simp	DEVMETHOD(card_detach_card,	pccard_detach_card),
121274636Simp	DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe),
121374636Simp	DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach),
121497613Stakawata	DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup),
121559193Simp
121652506Simp	{ 0, 0 }
121752506Simp};
121852506Simp
121952506Simpstatic driver_t pccard_driver = {
122052506Simp	"pccard",
122152506Simp	pccard_methods,
122264850Simp	sizeof(struct pccard_softc)
122352506Simp};
122452506Simp
122552506Simpdevclass_t	pccard_devclass;
122652506Simp
1227101905Simp/* Maybe we need to have a slot device? */
122853873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
122952506SimpDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0);
1230101905SimpDRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0);
123153873SimpDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0);
123264927SimpMODULE_VERSION(pccard, 1);
123370715Sjon/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/
1234