pccard.c revision 82415
166200Simp/*	$NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $	*/
252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard.c 82415 2001-08-27 11:28:00Z jon $ */
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>
3952506Simp#include <sys/types.h>
4052506Simp
4152506Simp#include <sys/bus.h>
4252506Simp#include <machine/bus.h>
4352506Simp#include <sys/rman.h>
4452506Simp#include <machine/resource.h>
4552506Simp
4652506Simp#include <dev/pccard/pccardreg.h>
4752506Simp#include <dev/pccard/pccardvar.h>
4852506Simp
4955500Simp#include "power_if.h"
5059193Simp#include "card_if.h"
5155500Simp
5255500Simp#define PCCARDDEBUG
5355500Simp
5452506Simp#ifdef PCCARDDEBUG
5555500Simpint	pccard_debug = 1;
5652506Simp#define	DPRINTF(arg) if (pccard_debug) printf arg
5755500Simp#define	DEVPRINTF(arg) if (pccard_debug) device_printf arg
5867333Simp#define PRVERBOSE(arg) printf arg
5967333Simp#define DEVPRVERBOSE(arg) device_printf arg
6052506Simp#else
6152506Simp#define	DPRINTF(arg)
6255500Simp#define	DEVPRINTF(arg)
6367333Simp#define PRVERBOSE(arg) if (bootverbose) printf arg
6467333Simp#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg
6552506Simp#endif
6652506Simp
6752506Simp#ifdef PCCARDVERBOSE
6852506Simpint	pccard_verbose = 1;
6952506Simp#else
7052506Simpint	pccard_verbose = 0;
7152506Simp#endif
7252506Simp
7382378Sjonstatic int	pccard_ccr_read(struct pccard_function *pf, int ccr);
7482378Sjonstatic void	pccard_ccr_write(struct pccard_function *pf, int ccr, int val);
7582378Sjonstatic int	pccard_attach_card(device_t dev);
7682378Sjonstatic int	pccard_detach_card(device_t dev, int flags);
7782378Sjonstatic int	pccard_card_gettype(device_t dev, int *type);
7882378Sjonstatic void	pccard_function_init(struct pccard_function *pf);
7982378Sjonstatic void	pccard_function_free(struct pccard_function *pf);
8082378Sjonstatic int	pccard_function_enable(struct pccard_function *pf);
8182378Sjonstatic void	pccard_function_disable(struct pccard_function *pf);
8282378Sjonstatic int	pccard_compat_do_probe(device_t bus, device_t dev);
8382378Sjonstatic int	pccard_compat_do_attach(device_t bus, device_t dev);
8482378Sjonstatic int	pccard_add_children(device_t dev, int busno);
8582378Sjonstatic int	pccard_probe(device_t dev);
8682378Sjonstatic int	pccard_attach(device_t dev);
8782378Sjonstatic int	pccard_detach(device_t dev);
8882378Sjonstatic void	pccard_print_resources(struct resource_list *rl,
8982378Sjon		    const char *name, int type, int count, const char *format);
9082378Sjonstatic int	pccard_print_child(device_t dev, device_t child);
9182378Sjonstatic int	pccard_set_resource(device_t dev, device_t child, int type,
9282378Sjon		    int rid, u_long start, u_long count);
9382378Sjonstatic int	pccard_get_resource(device_t dev, device_t child, int type,
9482378Sjon		    int rid, u_long *startp, u_long *countp);
9582378Sjonstatic void	pccard_delete_resource(device_t dev, device_t child, int type,
9682378Sjon		    int rid);
9782378Sjonstatic int	pccard_set_res_flags(device_t dev, device_t child, int type,
9882378Sjon		    int rid, u_int32_t flags);
9982378Sjonstatic int	pccard_set_memory_offset(device_t dev, device_t child, int rid,
10082378Sjon		    u_int32_t offset, u_int32_t *deltap);
10182378Sjonstatic int	pccard_read_ivar(device_t bus, device_t child, int which,
10282378Sjon		    u_char *result);
10382378Sjonstatic void	pccard_driver_added(device_t dev, driver_t *driver);
10482378Sjonstatic struct resource *pccard_alloc_resource(device_t dev,
10582378Sjon		    device_t child, int type, int *rid, u_long start,
10682378Sjon		    u_long end, u_long count, u_int flags);
10782378Sjonstatic int	pccard_release_resource(device_t dev, device_t child, int type,
10882378Sjon		    int rid, struct resource *r);
10982378Sjonstatic void	pccard_child_detached(device_t parent, device_t dev);
11082378Sjonstatic void	pccard_intr(void *arg);
11182378Sjonstatic int	pccard_setup_intr(device_t dev, device_t child,
11282378Sjon		    struct resource *irq, int flags, driver_intr_t *intr,
11382378Sjon		    void *arg, void **cookiep);
11482378Sjonstatic int	pccard_teardown_intr(device_t dev, device_t child,
11582378Sjon		    struct resource *r, void *cookie);
11652506Simp
11782378Sjonstatic int
11874632Simppccard_ccr_read(struct pccard_function *pf, int ccr)
11952506Simp{
12052506Simp	return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
12152506Simp	    pf->pf_ccr_offset + ccr));
12252506Simp}
12352506Simp
12482378Sjonstatic void
12574632Simppccard_ccr_write(struct pccard_function *pf, int ccr, int val)
12652506Simp{
12752506Simp	if ((pf->ccr_mask) & (1 << (ccr / 2))) {
12852506Simp		bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
12952506Simp		    pf->pf_ccr_offset + ccr, val);
13052506Simp	}
13152506Simp}
13252506Simp
13359193Simpstatic int
13459193Simppccard_attach_card(device_t dev)
13552506Simp{
13664850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
13752506Simp	struct pccard_function *pf;
13865917Simp	struct pccard_ivar *ivar;
13961788Simp	device_t child;
14052506Simp
14152506Simp	/*
14252506Simp	 * this is here so that when socket_enable calls gettype, trt happens
14352506Simp	 */
14452506Simp	STAILQ_INIT(&sc->card.pf_head);
14552506Simp
14655500Simp	DEVPRINTF((dev, "chip_socket_enable\n"));
14755500Simp	POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
14852506Simp
14955500Simp	DEVPRINTF((dev, "read_cis\n"));
15052506Simp	pccard_read_cis(sc);
15152506Simp
15255500Simp	DEVPRINTF((dev, "check_cis_quirks\n"));
15352506Simp	pccard_check_cis_quirks(dev);
15452506Simp
15552506Simp	/*
15652506Simp	 * bail now if the card has no functions, or if there was an error in
15752506Simp	 * the cis.
15852506Simp	 */
15952506Simp
16070715Sjon	if (sc->card.error) {
16170715Sjon		device_printf (dev, "CARD ERROR!\n");
16252506Simp		return (1);
16370715Sjon	}
16470715Sjon	if (STAILQ_EMPTY(&sc->card.pf_head)) {
16570715Sjon		device_printf (dev, "Card has no functions!\n");
16652506Simp		return (1);
16770715Sjon	}
16852506Simp
16961788Simp	if (1)
17052506Simp		pccard_print_cis(dev);
17152506Simp
17255500Simp	DEVPRINTF((dev, "functions scanning\n"));
17352506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
17452506Simp		if (STAILQ_EMPTY(&pf->cfe_head))
17552506Simp			continue;
17652506Simp
17752506Simp		pf->sc = sc;
17852506Simp		pf->cfe = NULL;
17964927Simp		pf->dev = NULL;
18052506Simp	}
18182378Sjon
18252506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
18352506Simp		if (STAILQ_EMPTY(&pf->cfe_head))
18452506Simp			continue;
18561788Simp		/*
18661788Simp		 * In NetBSD, the drivers are responsible for activating
18761788Simp		 * each function of a card.  I think that in FreeBSD we
18861788Simp		 * want to activate them enough for the usual bus_*_resource
18961788Simp		 * routines will do the right thing.  This many mean a
19061788Simp		 * departure from the current NetBSD model.
19161788Simp		 *
19261788Simp		 * This could get really ugly for multifunction cards.  But
19361788Simp		 * it might also just fall out of the FreeBSD resource model.
19461788Simp		 *
19561788Simp		 */
19667897Sdwmalone		ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF,
19767897Sdwmalone		    M_WAITOK | M_ZERO);
19861788Simp		child = device_add_child(dev, NULL, -1);
19965917Simp		device_set_ivars(child, ivar);
20066847Simp		ivar->fcn = pf;
20167187Simp		pf->dev = child;
20267167Simp		/*
20367167Simp		 * XXX We might want to move the next two lines into
20467167Simp		 * XXX the pccard interface layer.  For the moment, this
20567167Simp		 * XXX is OK, but some drivers want to pick the config
20667167Simp		 * XXX entry to use as well as some address tweaks (mostly
20767167Simp		 * XXX due to bugs in decode logic that makes some
20867167Simp		 * XXX addresses illegal or broken).
20967167Simp		 */
21065917Simp		pccard_function_init(pf);
21182378Sjon		if (sc->sc_enabled_count == 0)
21282378Sjon			POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
21367333Simp		if (pccard_function_enable(pf) == 0 &&
21467333Simp		    device_probe_and_attach(child) == 0) {
21555500Simp			DEVPRINTF((sc->dev, "function %d CCR at %d "
21667167Simp			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
21767167Simp			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
21867167Simp			    pccard_ccr_read(pf, 0x00),
21952506Simp			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
22052506Simp			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
22152506Simp			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
22252506Simp			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
22367167Simp		} else {
22482378Sjon			pccard_function_disable(pf);
22552506Simp		}
22652506Simp	}
22782378Sjon	if (sc->sc_enabled_count == 0)
22882378Sjon		pccard_detach_card(dev, 0);
22974632Simp	return (0);
23052506Simp}
23152506Simp
23259193Simpstatic int
23359193Simppccard_detach_card(device_t dev, int flags)
23452506Simp{
23564850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
23652506Simp	struct pccard_function *pf;
23782378Sjon	struct pccard_config_entry *cfe;
23852506Simp
23952506Simp	/*
24052506Simp	 * We are running on either the PCCARD socket's event thread
24152506Simp	 * or in user context detaching a device by user request.
24252506Simp	 */
24352506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
24482378Sjon		int state = device_get_state(pf->dev);
24561788Simp
24682378Sjon		if (state == DS_ATTACHED || state == DS_BUSY)
24782378Sjon			device_detach(pf->dev);
24861788Simp		pccard_function_disable(pf);
24982378Sjon		pccard_function_free(pf);
25076424Simp		if (pf->dev != NULL)
25164927Simp			device_delete_child(dev, pf->dev);
25252506Simp	}
25382378Sjon	if (sc->sc_enabled_count == 0)
25482378Sjon		POWER_DISABLE_SOCKET(device_get_parent(dev), dev);
25582378Sjon
25682378Sjon	while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) {
25782378Sjon		while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) {
25882378Sjon			STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list);
25982378Sjon			free(cfe, M_DEVBUF);
26082378Sjon		}
26182378Sjon		STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list);
26282378Sjon		free(pf, M_DEVBUF);
26382378Sjon	}
26474632Simp	return (0);
26552506Simp}
26652506Simp
26782415Sjonconst struct pccard_product *
26866200Simppccard_product_lookup(device_t dev, const struct pccard_product *tab,
26966200Simp    size_t ent_size, pccard_product_match_fn matchfn)
27066200Simp{
27166200Simp	const struct pccard_product *ent;
27266200Simp	int matches;
27366200Simp	u_int32_t fcn;
27466200Simp	u_int32_t vendor;
27566200Simp	u_int32_t prod;
27666200Simp	char *vendorstr;
27766200Simp	char *prodstr;
27866200Simp
27966200Simp#ifdef DIAGNOSTIC
28066200Simp	if (sizeof *ent > ent_size)
28170715Sjon		panic("pccard_product_lookup: bogus ent_size %ld",
28266200Simp		    (long) ent_size);
28366200Simp#endif
28466200Simp	if (pccard_get_vendor(dev, &vendor))
28566200Simp		return (NULL);
28666200Simp	if (pccard_get_product(dev, &prod))
28766200Simp		return (NULL);
28866200Simp	if (pccard_get_function_number(dev, &fcn))
28966200Simp		return (NULL);
29066200Simp	if (pccard_get_vendor_str(dev, &vendorstr))
29166200Simp		return (NULL);
29266200Simp	if (pccard_get_product_str(dev, &prodstr))
29366200Simp		return (NULL);
29482378Sjon	for (ent = tab; ent->pp_name != NULL; ent =
29582378Sjon	    (const struct pccard_product *) ((const char *) ent + ent_size)) {
29666200Simp		matches = 1;
29766200Simp		if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY &&
29866200Simp		    vendor != ent->pp_vendor)
29966200Simp			matches = 0;
30066200Simp		if (matches && ent->pp_product != PCCARD_PRODUCT_ANY &&
30166200Simp		    prod != ent->pp_product)
30266200Simp			matches = 0;
30366200Simp		if (matches && fcn != ent->pp_expfunc)
30466200Simp			matches = 0;
30571322Simp		if (matches && ent->pp_cis[0] &&
30671322Simp		    strcmp(ent->pp_cis[0], vendorstr) != 0)
30766200Simp			matches = 0;
30871322Simp		if (matches && ent->pp_cis[1] &&
30971322Simp		    strcmp(ent->pp_cis[1], prodstr) != 0)
31066200Simp			matches = 0;
31171322Simp		/* XXX need to match cis[2] and cis[3] also XXX */
31266200Simp		if (matchfn != NULL)
31366200Simp			matches = (*matchfn)(dev, ent, matches);
31466200Simp		if (matches)
31566200Simp			return (ent);
31666200Simp	}
31766200Simp	return (NULL);
31866200Simp}
31966200Simp
32070715Sjonstatic int
32159193Simppccard_card_gettype(device_t dev, int *type)
32252506Simp{
32364850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
32452506Simp	struct pccard_function *pf;
32552506Simp
32652506Simp	/*
32752506Simp	 * set the iftype to memory if this card has no functions (not yet
32852506Simp	 * probed), or only one function, and that is not initialized yet or
32952506Simp	 * that is memory.
33052506Simp	 */
33152506Simp	pf = STAILQ_FIRST(&sc->card.pf_head);
33252506Simp	if (pf == NULL ||
33352506Simp	    (STAILQ_NEXT(pf, pf_list) == NULL &&
33452506Simp	    (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY)))
33559193Simp		*type = PCCARD_IFTYPE_MEMORY;
33652506Simp	else
33759193Simp		*type = PCCARD_IFTYPE_IO;
33874632Simp	return (0);
33952506Simp}
34052506Simp
34152506Simp/*
34252506Simp * Initialize a PCCARD function.  May be called as long as the function is
34352506Simp * disabled.
34482382Simp *
34582382Simp * Note: pccard_function_init should not keep resources allocated.  It should
34682382Simp * only set them up ala isa pnp, set the values in the rl lists, and return.
34782382Simp * Any resource held after pccard_function_init is called is a bug.  However,
34882382Simp * the bus routines to get the resources also assume that pccard_function_init
34982382Simp * does this, so they need to be fixed too.
35052506Simp */
35182378Sjonstatic void
35270715Sjonpccard_function_init(struct pccard_function *pf)
35352506Simp{
35465917Simp	struct pccard_config_entry *cfe;
35567187Simp	int i;
35667242Simp	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
35767242Simp	struct resource_list *rl = &devi->resources;
35870762Simp	struct resource_list_entry *rle;
35967242Simp	struct resource *r = 0;
36067242Simp	device_t bus;
36167424Simp	int start;
36267424Simp	int end;
36365917Simp
36470715Sjon	if (pf->pf_flags & PFF_ENABLED) {
36570715Sjon		printf("pccard_function_init: function is enabled");
36670715Sjon		return;
36770715Sjon	}
36867242Simp	bus = device_get_parent(pf->dev);
36952506Simp	/* Remember which configuration entry we are using. */
37072012Sphk	STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
37167187Simp		for (i = 0; i < cfe->num_iospace; i++)
37267187Simp			cfe->iores[i] = NULL;
37367187Simp		cfe->irqres = NULL;
37467187Simp		for (i = 0; i < cfe->num_iospace; i++) {
37567424Simp			start = cfe->iospace[i].start;
37667424Simp			if (start)
37767424Simp				end = start + cfe->iospace[i].length - 1;
37867424Simp			else
37967424Simp				end = ~0;
38067187Simp			cfe->iorid[i] = i;
38167242Simp			r = cfe->iores[i] = bus_alloc_resource(bus,
38267424Simp			    SYS_RES_IOPORT, &cfe->iorid[i], start, end,
38370715Sjon			    cfe->iospace[i].length,
38467424Simp			    rman_make_alignment_flags(cfe->iospace[i].length));
38576424Simp			if (cfe->iores[i] == NULL)
38667187Simp				goto not_this_one;
38767242Simp			resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i],
38867242Simp			    rman_get_start(r), rman_get_end(r),
38967242Simp			    cfe->iospace[i].length);
39076424Simp			rle = resource_list_find(rl, SYS_RES_IOPORT,
39176424Simp			    cfe->iorid[i]);
39276424Simp			rle->res = r;
39367187Simp		}
39467187Simp		if (cfe->num_memspace > 0) {
39567187Simp			goto not_this_one;
39667187Simp		}
39767187Simp		if (cfe->irqmask) {
39867187Simp			cfe->irqrid = 0;
39967399Simp			r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ,
40067424Simp			    &cfe->irqrid, 0, ~0, 1, 0);
40176424Simp			if (cfe->irqres == NULL)
40267187Simp				goto not_this_one;
40367242Simp			resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid,
40467242Simp			    rman_get_start(r), rman_get_end(r), 1);
40576424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
40676424Simp			    cfe->irqrid);
40776424Simp			rle->res = r;
40867187Simp		}
40967187Simp		/* If we get to here, we've allocated all we need */
41067167Simp		pf->cfe = cfe;
41167187Simp		break;
41267187Simp	    not_this_one:;
41367424Simp		DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n",
41467424Simp		    cfe->number));
41567333Simp		/*
41667333Simp		 * Release resources that we partially allocated
41767333Simp		 * from this config entry.
41867333Simp		 */
41967187Simp		for (i = 0; i < cfe->num_iospace; i++) {
42076424Simp			if (cfe->iores[i] != NULL) {
42170715Sjon				bus_release_resource(bus, SYS_RES_IOPORT,
42267187Simp				    cfe->iorid[i], cfe->iores[i]);
42382378Sjon				rle = resource_list_find(rl, SYS_RES_IOPORT,
42476424Simp				    cfe->iorid[i]);
42576424Simp				rle->res = NULL;
42676424Simp				resource_list_delete(rl, SYS_RES_IOPORT,
42776424Simp				    cfe->iorid[i]);
42875756Simp			}
42967187Simp			cfe->iores[i] = NULL;
43067187Simp		}
43176424Simp		if (cfe->irqmask && cfe->irqres != NULL) {
43267242Simp			bus_release_resource(bus, SYS_RES_IRQ,
43367187Simp			    cfe->irqrid, cfe->irqres);
43476424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
43576424Simp			    cfe->irqrid);
43676424Simp			rle->res = NULL;
43776424Simp			resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid);
43867187Simp			cfe->irqres = NULL;
43967187Simp		}
44067167Simp	}
44152506Simp}
44252506Simp
44382378Sjon/*
44482378Sjon * Free resources allocated by pccard_function_init(), May be called as long
44582378Sjon * as the function is disabled.
44682382Simp *
44782382Simp * NOTE: This function should be unnecessary.  pccard_function_init should
44882382Simp * never keep resources initialized.
44982378Sjon */
45082378Sjonstatic void
45182378Sjonpccard_function_free(struct pccard_function *pf)
45282378Sjon{
45382378Sjon	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
45482378Sjon	struct resource_list_entry *rle;
45582378Sjon
45682378Sjon	if (pf->pf_flags & PFF_ENABLED) {
45782378Sjon		printf("pccard_function_init: function is enabled");
45882378Sjon		return;
45982378Sjon	}
46082378Sjon
46182378Sjon	SLIST_FOREACH(rle, &devi->resources, link) {
46282378Sjon		if (rle->res) {
46382378Sjon			if (rle->res->r_dev != pf->sc->dev)
46482378Sjon				device_printf(pf->sc->dev,
46582378Sjon				    "function_free: Resource still owned by "
46682378Sjon				    "child, oops. "
46782378Sjon				    "(type=%d, rid=%d, addr=%lx)\n",
46882378Sjon				    rle->type, rle->rid,
46982378Sjon				    rman_get_start(rle->res));
47082378Sjon			BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
47182378Sjon			    rle->res->r_dev, rle->type, rle->rid, rle->res);
47282378Sjon			rle->res = NULL;
47382378Sjon		}
47482378Sjon	}
47582378Sjon	resource_list_free(&devi->resources);
47682378Sjon}
47782378Sjon
47852506Simp/* Enable a PCCARD function */
47982378Sjonstatic int
48055720Simppccard_function_enable(struct pccard_function *pf)
48152506Simp{
48252506Simp	struct pccard_function *tmp;
48352506Simp	int reg;
48455720Simp	device_t dev = pf->sc->dev;
48570746Simp
48667333Simp	if (pf->cfe == NULL) {
48767333Simp		DEVPRVERBOSE((dev, "No config entry could be allocated.\n"));
48874632Simp		return (ENOMEM);
48967333Simp	}
49052506Simp
49152506Simp	/*
49252506Simp	 * Increase the reference count on the socket, enabling power, if
49352506Simp	 * necessary.
49452506Simp	 */
49582378Sjon	pf->sc->sc_enabled_count++;
49652506Simp
49752506Simp	if (pf->pf_flags & PFF_ENABLED) {
49852506Simp		/*
49952506Simp		 * Don't do anything if we're already enabled.
50052506Simp		 */
50152506Simp		return (0);
50252506Simp	}
50352506Simp
50452506Simp	/*
50552506Simp	 * it's possible for different functions' CCRs to be in the same
50652506Simp	 * underlying page.  Check for that.
50752506Simp	 */
50852506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
50952506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
51052506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
51152506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
51282378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
51382378Sjon		    tmp->pf_ccr_realsize))) {
51452506Simp			pf->pf_ccrt = tmp->pf_ccrt;
51552506Simp			pf->pf_ccrh = tmp->pf_ccrh;
51652506Simp			pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
51752506Simp
51852506Simp			/*
51952506Simp			 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
52052506Simp			 * tmp->ccr_base) + pf->ccr_base;
52152506Simp			 */
52270715Sjon			/* pf->pf_ccr_offset =
52352506Simp			    (tmp->pf_ccr_offset + pf->ccr_base) -
52470715Sjon			    tmp->ccr_base; */
52552506Simp			pf->pf_ccr_window = tmp->pf_ccr_window;
52652506Simp			break;
52752506Simp		}
52852506Simp	}
52952506Simp	if (tmp == NULL) {
53055720Simp		pf->ccr_rid = 0;
53155720Simp		pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
53270715Sjon		    &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE);
53370715Sjon		if (!pf->ccr_res)
53452506Simp			goto bad;
53570746Simp		DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%lx\n",
53670746Simp		    rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res),
53770746Simp		    pf->ccr_base));
53861788Simp		CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
53961788Simp		    pf->ccr_rid, PCCARD_A_MEM_ATTR);
54070715Sjon		CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev,
54170748Simp		    pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset);
54255720Simp		pf->pf_ccrt = rman_get_bustag(pf->ccr_res);
54355720Simp		pf->pf_ccrh = rman_get_bushandle(pf->ccr_res);
54455720Simp		pf->pf_ccr_realsize = 1;
54552506Simp	}
54652506Simp
54752506Simp	reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX);
54852506Simp	reg |= PCCARD_CCR_OPTION_LEVIREQ;
54952506Simp	if (pccard_mfc(pf->sc)) {
55052506Simp		reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE |
55152506Simp			PCCARD_CCR_OPTION_ADDR_DECODE);
55282383Simp		/* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */
55352506Simp	}
55452506Simp	pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
55552506Simp
55652506Simp	reg = 0;
55752506Simp	if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0)
55852506Simp		reg |= PCCARD_CCR_STATUS_IOIS8;
55952506Simp	if (pf->cfe->flags & PCCARD_CFE_AUDIO)
56052506Simp		reg |= PCCARD_CCR_STATUS_AUDIO;
56152506Simp	pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg);
56252506Simp
56352506Simp	pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0);
56452506Simp
56552506Simp	if (pccard_mfc(pf->sc)) {
56652506Simp		long tmp, iosize;
56752506Simp
56852506Simp		tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
56952506Simp		/* round up to nearest (2^n)-1 */
57052506Simp		for (iosize = 1; iosize < tmp; iosize <<= 1)
57152506Simp			;
57252506Simp		iosize--;
57352506Simp
57452506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
57552506Simp				 pf->pf_mfc_iobase & 0xff);
57652506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
57752506Simp				 (pf->pf_mfc_iobase >> 8) & 0xff);
57852506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
57952506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
58052506Simp
58152506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
58252506Simp	}
58352506Simp
58452506Simp#ifdef PCCARDDEBUG
58552506Simp	if (pccard_debug) {
58652506Simp		STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
58770715Sjon			device_printf(tmp->sc->dev,
58855500Simp			    "function %d CCR at %d offset %x: "
58955500Simp			    "%x %x %x %x, %x %x %x %x, %x\n",
59070715Sjon			    tmp->number, tmp->pf_ccr_window,
59155500Simp			    tmp->pf_ccr_offset,
59255500Simp			    pccard_ccr_read(tmp, 0x00),
59355500Simp			    pccard_ccr_read(tmp, 0x02),
59455500Simp			    pccard_ccr_read(tmp, 0x04),
59555500Simp			    pccard_ccr_read(tmp, 0x06),
59655500Simp			    pccard_ccr_read(tmp, 0x0A),
59770715Sjon			    pccard_ccr_read(tmp, 0x0C),
59855500Simp			    pccard_ccr_read(tmp, 0x0E),
59955500Simp			    pccard_ccr_read(tmp, 0x10),
60055500Simp			    pccard_ccr_read(tmp, 0x12));
60152506Simp		}
60252506Simp	}
60352506Simp#endif
60452506Simp	pf->pf_flags |= PFF_ENABLED;
60552506Simp	return (0);
60652506Simp
60752506Simp bad:
60852506Simp	/*
60952506Simp	 * Decrement the reference count, and power down the socket, if
61052506Simp	 * necessary.
61152506Simp	 */
61282378Sjon	pf->sc->sc_enabled_count--;
61365098Simp	DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count));
61452506Simp
61552506Simp	return (1);
61652506Simp}
61752506Simp
61852506Simp/* Disable PCCARD function. */
61982378Sjonstatic void
62055720Simppccard_function_disable(struct pccard_function *pf)
62152506Simp{
62252506Simp	struct pccard_function *tmp;
62355720Simp	device_t dev = pf->sc->dev;
62452506Simp
62552506Simp	if (pf->cfe == NULL)
62661788Simp		panic("pccard_function_disable: function not initialized");
62752506Simp
62852506Simp	if ((pf->pf_flags & PFF_ENABLED) == 0) {
62952506Simp		/*
63052506Simp		 * Don't do anything if we're already disabled.
63152506Simp		 */
63252506Simp		return;
63352506Simp	}
63452506Simp
63570715Sjon	if (pf->intr_handler != NULL) {
63682378Sjon		struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
63782378Sjon		struct resource_list_entry *rle =
63882378Sjon		    resource_list_find(&devi->resources, SYS_RES_IRQ, 0);
63982378Sjon		BUS_TEARDOWN_INTR(dev, pf->dev, rle->res,
64082378Sjon		    pf->intr_handler_cookie);
64170715Sjon	}
64270715Sjon
64352506Simp	/*
64452506Simp	 * it's possible for different functions' CCRs to be in the same
64552506Simp	 * underlying page.  Check for that.  Note we mark us as disabled
64652506Simp	 * first to avoid matching ourself.
64752506Simp	 */
64852506Simp
64952506Simp	pf->pf_flags &= ~PFF_ENABLED;
65052506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
65152506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
65252506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
65352506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
65482378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
65582378Sjon		    tmp->pf_ccr_realsize)))
65652506Simp			break;
65752506Simp	}
65852506Simp
65952506Simp	/* Not used by anyone else; unmap the CCR. */
66052506Simp	if (tmp == NULL) {
66170715Sjon		bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid,
66255720Simp		    pf->ccr_res);
66355720Simp		pf->ccr_res = NULL;
66452506Simp	}
66552506Simp
66652506Simp	/*
66752506Simp	 * Decrement the reference count, and power down the socket, if
66852506Simp	 * necessary.
66952506Simp	 */
67082378Sjon	pf->sc->sc_enabled_count--;
67152506Simp}
67252506Simp
67355720Simp#if 0
67455720Simp/* XXX These functions are needed, but not like this XXX */
67552506Simpint
67655720Simppccard_io_map(struct pccard_function *pf, int width, bus_addr_t offset,
67755720Simp    bus_size_t size, struct pccard_io_handle *pcihp, int *windowp)
67852506Simp{
67952506Simp	int reg;
68052506Simp
68167167Simp	if (pccard_chip_io_map(pf->sc->pct, pf->sc->pch, width, offset, size,
68267167Simp	    pcihp, windowp))
68352506Simp		return (1);
68452506Simp
68552506Simp	/*
68652506Simp	 * XXX in the multifunction multi-iospace-per-function case, this
68752506Simp	 * needs to cooperate with io_alloc to make sure that the spaces
68852506Simp	 * don't overlap, and that the ccr's are set correctly
68952506Simp	 */
69052506Simp
69152506Simp	if (pccard_mfc(pf->sc)) {
69252506Simp		long tmp, iosize;
69352506Simp
69452506Simp		if (pf->pf_mfc_iomax == 0) {
69552506Simp			pf->pf_mfc_iobase = pcihp->addr + offset;
69652506Simp			pf->pf_mfc_iomax = pf->pf_mfc_iobase + size;
69752506Simp		} else {
69852506Simp			/* this makes the assumption that nothing overlaps */
69952506Simp			if (pf->pf_mfc_iobase > pcihp->addr + offset)
70052506Simp				pf->pf_mfc_iobase = pcihp->addr + offset;
70152506Simp			if (pf->pf_mfc_iomax < pcihp->addr + offset + size)
70252506Simp				pf->pf_mfc_iomax = pcihp->addr + offset + size;
70352506Simp		}
70452506Simp
70552506Simp		tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
70652506Simp		/* round up to nearest (2^n)-1 */
70752506Simp		for (iosize = 1; iosize >= tmp; iosize <<= 1)
70852506Simp			;
70952506Simp		iosize--;
71052506Simp
71170715Sjon		pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
71255720Simp		    pf->pf_mfc_iobase & 0xff);
71352506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
71455720Simp		    (pf->pf_mfc_iobase >> 8) & 0xff);
71552506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
71652506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
71752506Simp
71852506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
71952506Simp
72052506Simp		reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION);
72152506Simp		reg |= PCCARD_CCR_OPTION_ADDR_DECODE;
72252506Simp		pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
72352506Simp	}
72452506Simp	return (0);
72552506Simp}
72652506Simp
72752506Simpvoid
72855720Simppccard_io_unmap(struct pccard_function *pf, int window)
72952506Simp{
73052506Simp
73152506Simp	pccard_chip_io_unmap(pf->sc->pct, pf->sc->pch, window);
73252506Simp
73352506Simp	/* XXX Anything for multi-function cards? */
73452506Simp}
73552506Simp#endif
73652506Simp
73766058Simp/*
73866058Simp * simulate the old "probe" routine.  In the new world order, the driver
73966058Simp * needs to grab devices while in the old they were assigned to the device by
74066058Simp * the pccardd process.  These symbols are exported to the upper layers.
74166058Simp */
74274636Simpstatic int
74374636Simppccard_compat_do_probe(device_t bus, device_t dev)
74466058Simp{
74566058Simp	return (CARD_COMPAT_MATCH(dev));
74666058Simp}
74766058Simp
74874636Simpstatic int
74974636Simppccard_compat_do_attach(device_t bus, device_t dev)
75066058Simp{
75166058Simp	int err;
75266058Simp
75366058Simp	err = CARD_COMPAT_PROBE(dev);
75466058Simp	if (err == 0)
75566058Simp		err = CARD_COMPAT_ATTACH(dev);
75666058Simp	return (err);
75766058Simp}
75866058Simp
75953873Simp#define PCCARD_NPORT	2
76053873Simp#define PCCARD_NMEM	5
76153873Simp#define PCCARD_NIRQ	1
76253873Simp#define PCCARD_NDRQ	0
76353873Simp
76452506Simpstatic int
76552506Simppccard_add_children(device_t dev, int busno)
76652506Simp{
76759193Simp	/* Call parent to scan for any current children */
76874632Simp	return (0);
76952506Simp}
77052506Simp
77152506Simpstatic int
77252506Simppccard_probe(device_t dev)
77352506Simp{
77467333Simp	device_set_desc(dev, "16-bit PCCard bus");
77574632Simp	return (pccard_add_children(dev, device_get_unit(dev)));
77652506Simp}
77752506Simp
77859193Simpstatic int
77959193Simppccard_attach(device_t dev)
78059193Simp{
78164850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
78261788Simp
78359193Simp	sc->dev = dev;
78461788Simp	sc->sc_enabled_count = 0;
78574632Simp	return (bus_generic_attach(dev));
78659193Simp}
78759193Simp
78882378Sjonstatic int
78982378Sjonpccard_detach(device_t dev)
79082378Sjon{
79182378Sjon	pccard_detach_card(dev, 0);
79282378Sjon	return 0;
79382378Sjon}
79482378Sjon
79553873Simpstatic void
79653873Simppccard_print_resources(struct resource_list *rl, const char *name, int type,
79753873Simp    int count, const char *format)
79853873Simp{
79953873Simp	struct resource_list_entry *rle;
80053873Simp	int printed;
80153873Simp	int i;
80253873Simp
80353873Simp	printed = 0;
80453873Simp	for (i = 0; i < count; i++) {
80553873Simp		rle = resource_list_find(rl, type, i);
80676424Simp		if (rle != NULL) {
80753873Simp			if (printed == 0)
80853873Simp				printf(" %s ", name);
80953873Simp			else if (printed > 0)
81053873Simp				printf(",");
81153873Simp			printed++;
81253873Simp			printf(format, rle->start);
81353873Simp			if (rle->count > 1) {
81453873Simp				printf("-");
81553873Simp				printf(format, rle->start + rle->count - 1);
81653873Simp			}
81753873Simp		} else if (i > 3) {
81853873Simp			/* check the first few regardless */
81953873Simp			break;
82053873Simp		}
82153873Simp	}
82253873Simp}
82353873Simp
82453873Simpstatic int
82553873Simppccard_print_child(device_t dev, device_t child)
82653873Simp{
82766847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
82853873Simp	struct resource_list *rl = &devi->resources;
82953873Simp	int retval = 0;
83053873Simp
83153873Simp	retval += bus_print_child_header(dev, child);
83253873Simp	retval += printf(" at");
83353873Simp
83476424Simp	if (devi != NULL) {
83553873Simp		pccard_print_resources(rl, "port", SYS_RES_IOPORT,
83653873Simp		    PCCARD_NPORT, "%#lx");
83753873Simp		pccard_print_resources(rl, "iomem", SYS_RES_MEMORY,
83853873Simp		    PCCARD_NMEM, "%#lx");
83953873Simp		pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ,
84053873Simp		    "%ld");
84170715Sjon		pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ,
84253873Simp		    "%ld");
84367269Simp		retval += printf(" function %d config %d", devi->fcn->number,
84467269Simp		    devi->fcn->cfe->number);
84553873Simp	}
84653873Simp
84753873Simp	retval += bus_print_child_footer(dev, child);
84853873Simp
84953873Simp	return (retval);
85053873Simp}
85153873Simp
85253873Simpstatic int
85353873Simppccard_set_resource(device_t dev, device_t child, int type, int rid,
85453873Simp		 u_long start, u_long count)
85553873Simp{
85666847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
85753873Simp	struct resource_list *rl = &devi->resources;
85853873Simp
85953873Simp	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
86053873Simp	    && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
86174632Simp		return (EINVAL);
86253873Simp	if (rid < 0)
86374632Simp		return (EINVAL);
86453873Simp	if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT)
86574632Simp		return (EINVAL);
86653873Simp	if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM)
86774632Simp		return (EINVAL);
86853873Simp	if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ)
86974632Simp		return (EINVAL);
87053873Simp	if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ)
87174632Simp		return (EINVAL);
87253873Simp
87353873Simp	resource_list_add(rl, type, rid, start, start + count - 1, count);
87482378Sjon	if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev,
87582378Sjon	    type, &rid, start, start + count - 1, count, 0))
87682378Sjon		return 0;
87782378Sjon	else
87882378Sjon		return ENOMEM;
87953873Simp}
88053873Simp
88153873Simpstatic int
88253873Simppccard_get_resource(device_t dev, device_t child, int type, int rid,
88353873Simp    u_long *startp, u_long *countp)
88453873Simp{
88566847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
88653873Simp	struct resource_list *rl = &devi->resources;
88753873Simp	struct resource_list_entry *rle;
88853873Simp
88953873Simp	rle = resource_list_find(rl, type, rid);
89076424Simp	if (rle == NULL)
89174632Simp		return (ENOENT);
89270715Sjon
89376424Simp	if (startp != NULL)
89453873Simp		*startp = rle->start;
89576424Simp	if (countp != NULL)
89653873Simp		*countp = rle->count;
89753873Simp
89874632Simp	return (0);
89953873Simp}
90053873Simp
90153873Simpstatic void
90253873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid)
90353873Simp{
90466847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
90553873Simp	struct resource_list *rl = &devi->resources;
90653873Simp	resource_list_delete(rl, type, rid);
90753873Simp}
90853873Simp
90959193Simpstatic int
91059193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid,
91159193Simp    u_int32_t flags)
91259193Simp{
91374632Simp	return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type,
91474632Simp	    rid, flags));
91559193Simp}
91659193Simp
91759193Simpstatic int
91859193Simppccard_set_memory_offset(device_t dev, device_t child, int rid,
91982378Sjon    u_int32_t offset, u_int32_t *deltap)
92070715Sjon
92159193Simp{
92274632Simp	return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid,
92374632Simp	    offset, deltap));
92459193Simp}
92559193Simp
92666058Simpstatic int
92766058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result)
92866058Simp{
92966847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
93066779Simp	struct pccard_function *func = devi->fcn;
93166779Simp	struct pccard_softc *sc = PCCARD_SOFTC(bus);
93266779Simp
93366058Simp	/* PCCARD_IVAR_ETHADDR unhandled from oldcard */
93466779Simp	switch (which) {
93566779Simp	default:
93666779Simp	case PCCARD_IVAR_ETHADDR:
93766779Simp		return (ENOENT);
93866779Simp		break;
93966779Simp	case PCCARD_IVAR_VENDOR:
94066779Simp		*(u_int32_t *) result = sc->card.manufacturer;
94166779Simp		break;
94266779Simp	case PCCARD_IVAR_PRODUCT:
94366779Simp		*(u_int32_t *) result = sc->card.product;
94466779Simp		break;
94575761Simp	case PCCARD_IVAR_FUNCTION:
94675761Simp		*(u_int32_t *) result = func->function;
94775761Simp		break;
94866779Simp	case PCCARD_IVAR_FUNCTION_NUMBER:
94966847Simp		if (!func) {
95066847Simp			device_printf(bus, "No function number, bug!\n");
95166847Simp			return (ENOENT);
95266847Simp		}
95366847Simp		*(u_int32_t *) result = func->number;
95466779Simp		break;
95566779Simp	case PCCARD_IVAR_VENDOR_STR:
95666779Simp		*(char **) result = sc->card.cis1_info[0];
95766779Simp		break;
95866779Simp	case PCCARD_IVAR_PRODUCT_STR:
95966779Simp		*(char **) result = sc->card.cis1_info[1];
96066779Simp		break;
96166779Simp	case PCCARD_IVAR_CIS3_STR:
96266779Simp		*(char **) result = sc->card.cis1_info[2];
96366779Simp		break;
96467167Simp	case PCCARD_IVAR_CIS4_STR:
96567167Simp		*(char **) result = sc->card.cis1_info[2];
96667167Simp		break;
96766779Simp	}
96866779Simp	return (0);
96966058Simp}
97066058Simp
97166779Simpstatic void
97266779Simppccard_driver_added(device_t dev, driver_t *driver)
97366779Simp{
97482378Sjon	struct pccard_softc *sc = PCCARD_SOFTC(dev);
97582378Sjon	struct pccard_function *pf;
97682378Sjon	device_t child;
97782378Sjon
97882378Sjon	if (sc->sc_enabled_count == 0) {
97982378Sjon		CARD_REPROBE_CARD(device_get_parent(dev), dev);
98082378Sjon		return;
98182378Sjon	}
98282378Sjon
98382378Sjon	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
98482378Sjon		if (STAILQ_EMPTY(&pf->cfe_head))
98582378Sjon			continue;
98682378Sjon		child = pf->dev;
98782378Sjon		if (device_get_state(child) != DS_NOTPRESENT)
98882378Sjon			continue;
98982378Sjon		if (pccard_function_enable(pf) == 0 &&
99082378Sjon		    device_probe_and_attach(child) == 0) {
99182378Sjon			DEVPRINTF((sc->dev, "function %d CCR at %d "
99282378Sjon			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
99382378Sjon			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
99482378Sjon			    pccard_ccr_read(pf, 0x00),
99582378Sjon			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
99682378Sjon			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
99782378Sjon			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
99882378Sjon			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
99982378Sjon		} else {
100082378Sjon			pccard_function_disable(pf);
100182378Sjon		}
100282378Sjon	}
100382378Sjon	return;
100466779Simp}
100566058Simp
100667242Simpstatic struct resource *
100767242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid,
100867242Simp    u_long start, u_long end, u_long count, u_int flags)
100967242Simp{
101082378Sjon	struct pccard_ivar *dinfo;
101182378Sjon	struct resource_list_entry *rle = 0;
101282378Sjon	int passthrough = (device_get_parent(child) != dev);
101367242Simp
101482378Sjon	if (passthrough) {
101582378Sjon		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
101682378Sjon		    type, rid, start, end, count, flags));
101782378Sjon	}
101870715Sjon
101982378Sjon	dinfo = device_get_ivars(child);
102082378Sjon	rle = resource_list_find(&dinfo->resources, type, *rid);
102170715Sjon
102282378Sjon	if (!rle)
102382378Sjon		return NULL;		/* no resource of that type/rid */
102470715Sjon
102582378Sjon	if (!rle->res) {
102682378Sjon		device_printf(dev, "WARNING: Resource not reserved by pccard bus\n");
102782378Sjon		return NULL;
102882378Sjon	} else {
102982378Sjon		if (rle->res->r_dev != dev) return NULL;
103082378Sjon		bus_release_resource(dev, type, *rid, rle->res);
103182378Sjon		rle->res = NULL;
103282378Sjon		switch(type) {
103382378Sjon		case SYS_RES_IOPORT:
103482378Sjon		case SYS_RES_MEMORY:
103582378Sjon			if (!(flags & RF_ALIGNMENT_MASK))
103682378Sjon				flags |= rman_make_alignment_flags(rle->count);
103782378Sjon			break;
103882378Sjon		case SYS_RES_IRQ:
103982378Sjon			flags |= RF_SHAREABLE;
104082378Sjon			break;
104182378Sjon		}
104282378Sjon		return resource_list_alloc(&dinfo->resources, dev, child, type,
104382378Sjon		    rid, rle->start, rle->end, rle->count, flags);
104467269Simp	}
104567242Simp}
104667242Simp
104767242Simpstatic int
104867242Simppccard_release_resource(device_t dev, device_t child, int type, int rid,
104967242Simp    struct resource *r)
105067242Simp{
105182378Sjon	struct pccard_ivar *dinfo;
105282378Sjon	int passthrough = (device_get_parent(child) != dev);
105382378Sjon	struct resource_list_entry *rle = 0;
105482378Sjon	int ret;
105582378Sjon	int flags;
105670715Sjon
105782378Sjon	if (passthrough)
105882378Sjon		return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
105982378Sjon		    type, rid, r);
106070715Sjon
106182378Sjon	dinfo = device_get_ivars(child);
106270715Sjon
106382378Sjon	rle = resource_list_find(&dinfo->resources, type, rid);
106470715Sjon
106582378Sjon	if (!rle) {
106682378Sjon		device_printf(dev, "Allocated resource not found, "
106782378Sjon		    "%d %x %lx %lx\n",
106882378Sjon		    type, rid, rman_get_start(r), rman_get_size(r));
106982378Sjon		return ENOENT;
107070715Sjon	}
107182378Sjon	if (!rle->res) {
107282378Sjon		device_printf(dev, "Allocated resource not recorded\n");
107382378Sjon		return ENOENT;
107470715Sjon	}
107570715Sjon
107682378Sjon	ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
107782378Sjon	    type, rid, r);
107882378Sjon	switch(type) {
107982378Sjon	case SYS_RES_IOPORT:
108082378Sjon	case SYS_RES_MEMORY:
108182378Sjon		flags = rman_make_alignment_flags(rle->count);
108282378Sjon		break;
108382378Sjon	case SYS_RES_IRQ:
108482378Sjon		flags = RF_SHAREABLE;
108582378Sjon		break;
108682378Sjon	default:
108782378Sjon		flags = 0;
108870715Sjon	}
108982378Sjon	rle->res = bus_alloc_resource(dev, type, &rid,
109082378Sjon	    rle->start, rle->end, rle->count, flags);
109182378Sjon	if (rle->res == NULL)
109282378Sjon		device_printf(dev, "release_resource: "
109382378Sjon		    "unable to reaquire resource\n");
109482378Sjon	return ret;
109567242Simp}
109667242Simp
109767333Simpstatic void
109867333Simppccard_child_detached(device_t parent, device_t dev)
109967333Simp{
110067333Simp	struct pccard_ivar *ivar = PCCARD_IVAR(dev);
110182378Sjon	struct pccard_function *pf = ivar->fcn;
110267333Simp
110382378Sjon	pccard_function_disable(pf);
110467333Simp}
110567333Simp
110670715Sjonstatic void
110770762Simppccard_intr(void *arg)
110870762Simp{
110982378Sjon	struct pccard_function *pf = (struct pccard_function*) arg;
111082378Sjon	int reg;
111182378Sjon
111282383Simp	/*
111382383Simp	 * If we go to resetting a card, we may need a null interrupt hanlder
111482383Simp	 * to work (since the system may call it before the device can
111582383Simp	 * establish an ISR) due to interrupt sharing at a higher level.
111682383Simp	 */
111782378Sjon	if (pf->intr_handler == NULL)
111882378Sjon		panic("Null interrupt handler?\n");
111982378Sjon
112082383Simp	/*
112182383Simp	 * XXX The CCR_STATUS register bits used here are
112282383Simp	 * only valid for multi function cards.
112382383Simp	 */
112482378Sjon	reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
112582378Sjon	if (reg & PCCARD_CCR_STATUS_INTR) {
112682378Sjon		pccard_ccr_write(pf, PCCARD_CCR_STATUS,
112782378Sjon				 reg & ~PCCARD_CCR_STATUS_INTR);
112882378Sjon		pf->intr_handler(pf->intr_handler_arg);
112970715Sjon	}
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{
113670715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
113770715Sjon	struct pccard_function *func = ivar->fcn;
113870715Sjon
113970715Sjon	if (func->intr_handler != NULL)
114070762Simp		panic("Only one interrupt handler per function allowed\n");
114170715Sjon
114270715Sjon	func->intr_handler = intr;
114370715Sjon	func->intr_handler_arg = arg;
114482378Sjon	func->intr_handler_cookie = *cookiep;
114570715Sjon	pccard_ccr_write(func, PCCARD_CCR_OPTION,
114682378Sjon	    pccard_ccr_read(func, PCCARD_CCR_OPTION) |
114770762Simp	    PCCARD_CCR_OPTION_IREQ_ENABLE);
114870715Sjon
114982383Simp	/*
115082383Simp	 * XXX Don't use TTY type for our interrupt handler.  It makes
115182383Simp	 * the spl masks wrong on -stable.  Instead, we should use the type
115282383Simp	 * that was requested of us.
115382383Simp	 */
115482378Sjon	bus_setup_intr(dev, irq, INTR_TYPE_TTY/* | INTR_FAST*/,
115582378Sjon	    pccard_intr, func, cookiep);
115674632Simp	return (0);
115770715Sjon}
115870715Sjon
115970715Sjonstatic int
116070762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r,
116170762Simp    void *cookie)
116270715Sjon{
116370715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
116470715Sjon	struct pccard_function *func = ivar->fcn;
116582378Sjon	int ret;
116670715Sjon
116770715Sjon	pccard_ccr_write(func, PCCARD_CCR_OPTION,
116870762Simp	    pccard_ccr_read(func, PCCARD_CCR_OPTION) &
116970762Simp	    ~PCCARD_CCR_OPTION_IREQ_ENABLE);
117070715Sjon
117182378Sjon	ret = bus_teardown_intr(dev, r, cookie);
117282378Sjon	if (ret == 0) {
117382378Sjon		func->intr_handler = NULL;
117482378Sjon		func->intr_handler_arg = NULL;
117582378Sjon		func->intr_handler_cookie = NULL;
117682378Sjon	}
117770715Sjon
117882378Sjon	return (ret);
117970715Sjon}
118070715Sjon
118152506Simpstatic device_method_t pccard_methods[] = {
118252506Simp	/* Device interface */
118352506Simp	DEVMETHOD(device_probe,		pccard_probe),
118459193Simp	DEVMETHOD(device_attach,	pccard_attach),
118582378Sjon	DEVMETHOD(device_detach,	pccard_detach),
118652506Simp	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
118752506Simp	DEVMETHOD(device_suspend,	bus_generic_suspend),
118852506Simp	DEVMETHOD(device_resume,	bus_generic_resume),
118952506Simp
119052506Simp	/* Bus interface */
119152506Simp	DEVMETHOD(bus_print_child,	pccard_print_child),
119266779Simp	DEVMETHOD(bus_driver_added,	pccard_driver_added),
119367333Simp	DEVMETHOD(bus_child_detached,	pccard_child_detached),
119467242Simp	DEVMETHOD(bus_alloc_resource,	pccard_alloc_resource),
119567242Simp	DEVMETHOD(bus_release_resource,	pccard_release_resource),
119682378Sjon	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
119782378Sjon	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
119870715Sjon	DEVMETHOD(bus_setup_intr,	pccard_setup_intr),
119970715Sjon	DEVMETHOD(bus_teardown_intr,	pccard_teardown_intr),
120052506Simp	DEVMETHOD(bus_set_resource,	pccard_set_resource),
120152506Simp	DEVMETHOD(bus_get_resource,	pccard_get_resource),
120252506Simp	DEVMETHOD(bus_delete_resource,	pccard_delete_resource),
120366058Simp	DEVMETHOD(bus_read_ivar,	pccard_read_ivar),
120452506Simp
120559193Simp	/* Card Interface */
120659193Simp	DEVMETHOD(card_set_res_flags,	pccard_set_res_flags),
120759193Simp	DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset),
120859193Simp	DEVMETHOD(card_get_type,	pccard_card_gettype),
120959193Simp	DEVMETHOD(card_attach_card,	pccard_attach_card),
121059193Simp	DEVMETHOD(card_detach_card,	pccard_detach_card),
121174636Simp	DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe),
121274636Simp	DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach),
121359193Simp
121452506Simp	{ 0, 0 }
121552506Simp};
121652506Simp
121752506Simpstatic driver_t pccard_driver = {
121852506Simp	"pccard",
121952506Simp	pccard_methods,
122064850Simp	sizeof(struct pccard_softc)
122152506Simp};
122252506Simp
122352506Simpdevclass_t	pccard_devclass;
122452506Simp
122553873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
122652506SimpDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0);
122752506SimpDRIVER_MODULE(pccard, pccbb, pccard_driver, pccard_devclass, 0, 0);
122853873SimpDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0);
122964927SimpMODULE_VERSION(pccard, 1);
123070715Sjon/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/
1231