pccard.c revision 86907
166200Simp/*	$NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $	*/
252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard.c 86907 2001-11-26 07:14:00Z 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>
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
4682781Sshiba#include <net/ethernet.h>
4782781Sshiba
4852506Simp#include <dev/pccard/pccardreg.h>
4952506Simp#include <dev/pccard/pccardvar.h>
5052506Simp
5155500Simp#include "power_if.h"
5259193Simp#include "card_if.h"
5355500Simp
5455500Simp#define PCCARDDEBUG
5555500Simp
5652506Simp#ifdef PCCARDDEBUG
5755500Simpint	pccard_debug = 1;
5852506Simp#define	DPRINTF(arg) if (pccard_debug) printf arg
5955500Simp#define	DEVPRINTF(arg) if (pccard_debug) device_printf arg
6067333Simp#define PRVERBOSE(arg) printf arg
6167333Simp#define DEVPRVERBOSE(arg) device_printf arg
6252506Simp#else
6352506Simp#define	DPRINTF(arg)
6455500Simp#define	DEVPRINTF(arg)
6567333Simp#define PRVERBOSE(arg) if (bootverbose) printf arg
6667333Simp#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg
6752506Simp#endif
6852506Simp
6952506Simp#ifdef PCCARDVERBOSE
7052506Simpint	pccard_verbose = 1;
7152506Simp#else
7252506Simpint	pccard_verbose = 0;
7352506Simp#endif
7452506Simp
7582378Sjonstatic int	pccard_ccr_read(struct pccard_function *pf, int ccr);
7682378Sjonstatic void	pccard_ccr_write(struct pccard_function *pf, int ccr, int val);
7782378Sjonstatic int	pccard_attach_card(device_t dev);
7882378Sjonstatic int	pccard_detach_card(device_t dev, int flags);
7982378Sjonstatic int	pccard_card_gettype(device_t dev, int *type);
8082378Sjonstatic void	pccard_function_init(struct pccard_function *pf);
8182378Sjonstatic void	pccard_function_free(struct pccard_function *pf);
8282378Sjonstatic int	pccard_function_enable(struct pccard_function *pf);
8382378Sjonstatic void	pccard_function_disable(struct pccard_function *pf);
8482378Sjonstatic int	pccard_compat_do_probe(device_t bus, device_t dev);
8582378Sjonstatic int	pccard_compat_do_attach(device_t bus, device_t dev);
8682378Sjonstatic int	pccard_add_children(device_t dev, int busno);
8782378Sjonstatic int	pccard_probe(device_t dev);
8882378Sjonstatic int	pccard_attach(device_t dev);
8982378Sjonstatic int	pccard_detach(device_t dev);
9082378Sjonstatic void	pccard_print_resources(struct resource_list *rl,
9182378Sjon		    const char *name, int type, int count, const char *format);
9282378Sjonstatic int	pccard_print_child(device_t dev, device_t child);
9382378Sjonstatic int	pccard_set_resource(device_t dev, device_t child, int type,
9482378Sjon		    int rid, u_long start, u_long count);
9582378Sjonstatic int	pccard_get_resource(device_t dev, device_t child, int type,
9682378Sjon		    int rid, u_long *startp, u_long *countp);
9782378Sjonstatic void	pccard_delete_resource(device_t dev, device_t child, int type,
9882378Sjon		    int rid);
9982378Sjonstatic int	pccard_set_res_flags(device_t dev, device_t child, int type,
10082378Sjon		    int rid, u_int32_t flags);
10182378Sjonstatic int	pccard_set_memory_offset(device_t dev, device_t child, int rid,
10282378Sjon		    u_int32_t offset, u_int32_t *deltap);
10382378Sjonstatic int	pccard_read_ivar(device_t bus, device_t child, int which,
10482378Sjon		    u_char *result);
10582378Sjonstatic void	pccard_driver_added(device_t dev, driver_t *driver);
10682378Sjonstatic struct resource *pccard_alloc_resource(device_t dev,
10782378Sjon		    device_t child, int type, int *rid, u_long start,
10882378Sjon		    u_long end, u_long count, u_int flags);
10982378Sjonstatic int	pccard_release_resource(device_t dev, device_t child, int type,
11082378Sjon		    int rid, struct resource *r);
11182378Sjonstatic void	pccard_child_detached(device_t parent, device_t dev);
11282378Sjonstatic void	pccard_intr(void *arg);
11382378Sjonstatic int	pccard_setup_intr(device_t dev, device_t child,
11482378Sjon		    struct resource *irq, int flags, driver_intr_t *intr,
11582378Sjon		    void *arg, void **cookiep);
11682378Sjonstatic int	pccard_teardown_intr(device_t dev, device_t child,
11782378Sjon		    struct resource *r, void *cookie);
11852506Simp
11982378Sjonstatic int
12074632Simppccard_ccr_read(struct pccard_function *pf, int ccr)
12152506Simp{
12252506Simp	return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
12352506Simp	    pf->pf_ccr_offset + ccr));
12452506Simp}
12552506Simp
12682378Sjonstatic void
12774632Simppccard_ccr_write(struct pccard_function *pf, int ccr, int val)
12852506Simp{
12952506Simp	if ((pf->ccr_mask) & (1 << (ccr / 2))) {
13052506Simp		bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
13152506Simp		    pf->pf_ccr_offset + ccr, val);
13252506Simp	}
13352506Simp}
13452506Simp
13559193Simpstatic int
13659193Simppccard_attach_card(device_t dev)
13752506Simp{
13864850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
13952506Simp	struct pccard_function *pf;
14065917Simp	struct pccard_ivar *ivar;
14161788Simp	device_t child;
14252506Simp
14352506Simp	/*
14452506Simp	 * this is here so that when socket_enable calls gettype, trt happens
14552506Simp	 */
14652506Simp	STAILQ_INIT(&sc->card.pf_head);
14752506Simp
14855500Simp	DEVPRINTF((dev, "chip_socket_enable\n"));
14955500Simp	POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
15052506Simp
15155500Simp	DEVPRINTF((dev, "read_cis\n"));
15252506Simp	pccard_read_cis(sc);
15352506Simp
15455500Simp	DEVPRINTF((dev, "check_cis_quirks\n"));
15552506Simp	pccard_check_cis_quirks(dev);
15652506Simp
15752506Simp	/*
15852506Simp	 * bail now if the card has no functions, or if there was an error in
15952506Simp	 * the cis.
16052506Simp	 */
16152506Simp
16270715Sjon	if (sc->card.error) {
16370715Sjon		device_printf (dev, "CARD ERROR!\n");
16452506Simp		return (1);
16570715Sjon	}
16670715Sjon	if (STAILQ_EMPTY(&sc->card.pf_head)) {
16770715Sjon		device_printf (dev, "Card has no functions!\n");
16852506Simp		return (1);
16970715Sjon	}
17052506Simp
17161788Simp	if (1)
17252506Simp		pccard_print_cis(dev);
17352506Simp
17455500Simp	DEVPRINTF((dev, "functions scanning\n"));
17552506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
17652506Simp		if (STAILQ_EMPTY(&pf->cfe_head))
17752506Simp			continue;
17852506Simp
17952506Simp		pf->sc = sc;
18052506Simp		pf->cfe = NULL;
18164927Simp		pf->dev = NULL;
18252506Simp	}
18382378Sjon
18452506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
18552506Simp		if (STAILQ_EMPTY(&pf->cfe_head))
18652506Simp			continue;
18761788Simp		/*
18861788Simp		 * In NetBSD, the drivers are responsible for activating
18961788Simp		 * each function of a card.  I think that in FreeBSD we
19061788Simp		 * want to activate them enough for the usual bus_*_resource
19161788Simp		 * routines will do the right thing.  This many mean a
19261788Simp		 * departure from the current NetBSD model.
19361788Simp		 *
19461788Simp		 * This could get really ugly for multifunction cards.  But
19561788Simp		 * it might also just fall out of the FreeBSD resource model.
19661788Simp		 *
19761788Simp		 */
19867897Sdwmalone		ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF,
19967897Sdwmalone		    M_WAITOK | M_ZERO);
20061788Simp		child = device_add_child(dev, NULL, -1);
20165917Simp		device_set_ivars(child, ivar);
20266847Simp		ivar->fcn = pf;
20367187Simp		pf->dev = child;
20467167Simp		/*
20567167Simp		 * XXX We might want to move the next two lines into
20667167Simp		 * XXX the pccard interface layer.  For the moment, this
20767167Simp		 * XXX is OK, but some drivers want to pick the config
20867167Simp		 * XXX entry to use as well as some address tweaks (mostly
20967167Simp		 * XXX due to bugs in decode logic that makes some
21067167Simp		 * XXX addresses illegal or broken).
21167167Simp		 */
21265917Simp		pccard_function_init(pf);
21382378Sjon		if (sc->sc_enabled_count == 0)
21482378Sjon			POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
21567333Simp		if (pccard_function_enable(pf) == 0 &&
21667333Simp		    device_probe_and_attach(child) == 0) {
21755500Simp			DEVPRINTF((sc->dev, "function %d CCR at %d "
21867167Simp			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
21967167Simp			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
22067167Simp			    pccard_ccr_read(pf, 0x00),
22152506Simp			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
22252506Simp			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
22352506Simp			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
22452506Simp			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
22567167Simp		} else {
22686907Simp			if (pf->cfe != NULL)
22786907Simp				pccard_function_disable(pf);
22852506Simp		}
22952506Simp	}
23082378Sjon	if (sc->sc_enabled_count == 0)
23182378Sjon		pccard_detach_card(dev, 0);
23274632Simp	return (0);
23352506Simp}
23452506Simp
23559193Simpstatic int
23659193Simppccard_detach_card(device_t dev, int flags)
23752506Simp{
23864850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
23952506Simp	struct pccard_function *pf;
24082378Sjon	struct pccard_config_entry *cfe;
24152506Simp
24252506Simp	/*
24352506Simp	 * We are running on either the PCCARD socket's event thread
24452506Simp	 * or in user context detaching a device by user request.
24552506Simp	 */
24652506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
24782378Sjon		int state = device_get_state(pf->dev);
24861788Simp
24982378Sjon		if (state == DS_ATTACHED || state == DS_BUSY)
25082378Sjon			device_detach(pf->dev);
25186907Simp		if (pf->cfe != NULL)
25286907Simp			pccard_function_disable(pf);
25382378Sjon		pccard_function_free(pf);
25476424Simp		if (pf->dev != NULL)
25564927Simp			device_delete_child(dev, pf->dev);
25652506Simp	}
25782378Sjon	if (sc->sc_enabled_count == 0)
25882378Sjon		POWER_DISABLE_SOCKET(device_get_parent(dev), dev);
25982378Sjon
26082378Sjon	while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) {
26182378Sjon		while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) {
26282378Sjon			STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list);
26382378Sjon			free(cfe, M_DEVBUF);
26482378Sjon		}
26582378Sjon		STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list);
26682378Sjon		free(pf, M_DEVBUF);
26782378Sjon	}
26874632Simp	return (0);
26952506Simp}
27052506Simp
27182415Sjonconst struct pccard_product *
27266200Simppccard_product_lookup(device_t dev, const struct pccard_product *tab,
27366200Simp    size_t ent_size, pccard_product_match_fn matchfn)
27466200Simp{
27566200Simp	const struct pccard_product *ent;
27666200Simp	int matches;
27766200Simp	u_int32_t fcn;
27866200Simp	u_int32_t vendor;
27966200Simp	u_int32_t prod;
28066200Simp	char *vendorstr;
28166200Simp	char *prodstr;
28266200Simp
28366200Simp#ifdef DIAGNOSTIC
28466200Simp	if (sizeof *ent > ent_size)
28570715Sjon		panic("pccard_product_lookup: bogus ent_size %ld",
28666200Simp		    (long) ent_size);
28766200Simp#endif
28866200Simp	if (pccard_get_vendor(dev, &vendor))
28966200Simp		return (NULL);
29066200Simp	if (pccard_get_product(dev, &prod))
29166200Simp		return (NULL);
29266200Simp	if (pccard_get_function_number(dev, &fcn))
29366200Simp		return (NULL);
29466200Simp	if (pccard_get_vendor_str(dev, &vendorstr))
29566200Simp		return (NULL);
29666200Simp	if (pccard_get_product_str(dev, &prodstr))
29766200Simp		return (NULL);
29882378Sjon	for (ent = tab; ent->pp_name != NULL; ent =
29982378Sjon	    (const struct pccard_product *) ((const char *) ent + ent_size)) {
30066200Simp		matches = 1;
30186642Simp		if (ent->pp_vendor == PCCARD_VENDOR_ANY &&
30286642Simp		    ent->pp_product == PCCARD_VENDOR_ANY &&
30386642Simp		    ent->pp_cis[0] == NULL &&
30486642Simp		    ent->pp_cis[1] == NULL) {
30586642Simp			device_printf(dev,
30686642Simp			    "Total wildcard entry ignored for %s\n",
30786642Simp			    ent->pp_name);
30886642Simp			continue;
30986642Simp		}
31066200Simp		if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY &&
31166200Simp		    vendor != ent->pp_vendor)
31266200Simp			matches = 0;
31366200Simp		if (matches && ent->pp_product != PCCARD_PRODUCT_ANY &&
31466200Simp		    prod != ent->pp_product)
31566200Simp			matches = 0;
31666200Simp		if (matches && fcn != ent->pp_expfunc)
31766200Simp			matches = 0;
31871322Simp		if (matches && ent->pp_cis[0] &&
31971322Simp		    strcmp(ent->pp_cis[0], vendorstr) != 0)
32066200Simp			matches = 0;
32171322Simp		if (matches && ent->pp_cis[1] &&
32271322Simp		    strcmp(ent->pp_cis[1], prodstr) != 0)
32366200Simp			matches = 0;
32471322Simp		/* XXX need to match cis[2] and cis[3] also XXX */
32566200Simp		if (matchfn != NULL)
32666200Simp			matches = (*matchfn)(dev, ent, matches);
32766200Simp		if (matches)
32866200Simp			return (ent);
32966200Simp	}
33066200Simp	return (NULL);
33166200Simp}
33266200Simp
33370715Sjonstatic int
33459193Simppccard_card_gettype(device_t dev, int *type)
33552506Simp{
33664850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
33752506Simp	struct pccard_function *pf;
33852506Simp
33952506Simp	/*
34052506Simp	 * set the iftype to memory if this card has no functions (not yet
34152506Simp	 * probed), or only one function, and that is not initialized yet or
34252506Simp	 * that is memory.
34352506Simp	 */
34452506Simp	pf = STAILQ_FIRST(&sc->card.pf_head);
34552506Simp	if (pf == NULL ||
34652506Simp	    (STAILQ_NEXT(pf, pf_list) == NULL &&
34752506Simp	    (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY)))
34859193Simp		*type = PCCARD_IFTYPE_MEMORY;
34952506Simp	else
35059193Simp		*type = PCCARD_IFTYPE_IO;
35174632Simp	return (0);
35252506Simp}
35352506Simp
35452506Simp/*
35552506Simp * Initialize a PCCARD function.  May be called as long as the function is
35652506Simp * disabled.
35782382Simp *
35882382Simp * Note: pccard_function_init should not keep resources allocated.  It should
35982382Simp * only set them up ala isa pnp, set the values in the rl lists, and return.
36082382Simp * Any resource held after pccard_function_init is called is a bug.  However,
36182382Simp * the bus routines to get the resources also assume that pccard_function_init
36282382Simp * does this, so they need to be fixed too.
36352506Simp */
36482378Sjonstatic void
36570715Sjonpccard_function_init(struct pccard_function *pf)
36652506Simp{
36765917Simp	struct pccard_config_entry *cfe;
36867187Simp	int i;
36967242Simp	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
37067242Simp	struct resource_list *rl = &devi->resources;
37170762Simp	struct resource_list_entry *rle;
37267242Simp	struct resource *r = 0;
37367242Simp	device_t bus;
37467424Simp	int start;
37567424Simp	int end;
37665917Simp
37770715Sjon	if (pf->pf_flags & PFF_ENABLED) {
37870715Sjon		printf("pccard_function_init: function is enabled");
37970715Sjon		return;
38070715Sjon	}
38167242Simp	bus = device_get_parent(pf->dev);
38252506Simp	/* Remember which configuration entry we are using. */
38372012Sphk	STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
38467187Simp		for (i = 0; i < cfe->num_iospace; i++)
38567187Simp			cfe->iores[i] = NULL;
38667187Simp		cfe->irqres = NULL;
38767187Simp		for (i = 0; i < cfe->num_iospace; i++) {
38867424Simp			start = cfe->iospace[i].start;
38967424Simp			if (start)
39067424Simp				end = start + cfe->iospace[i].length - 1;
39167424Simp			else
39267424Simp				end = ~0;
39367187Simp			cfe->iorid[i] = i;
39467242Simp			r = cfe->iores[i] = bus_alloc_resource(bus,
39567424Simp			    SYS_RES_IOPORT, &cfe->iorid[i], start, end,
39670715Sjon			    cfe->iospace[i].length,
39767424Simp			    rman_make_alignment_flags(cfe->iospace[i].length));
39876424Simp			if (cfe->iores[i] == NULL)
39967187Simp				goto not_this_one;
40067242Simp			resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i],
40167242Simp			    rman_get_start(r), rman_get_end(r),
40267242Simp			    cfe->iospace[i].length);
40376424Simp			rle = resource_list_find(rl, SYS_RES_IOPORT,
40476424Simp			    cfe->iorid[i]);
40576424Simp			rle->res = r;
40667187Simp		}
40767187Simp		if (cfe->num_memspace > 0) {
40882781Sshiba			/*
40982781Sshiba			 * Not implement yet, Fix me.
41082781Sshiba			 */
41167187Simp		}
41267187Simp		if (cfe->irqmask) {
41367187Simp			cfe->irqrid = 0;
41467399Simp			r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ,
41567424Simp			    &cfe->irqrid, 0, ~0, 1, 0);
41676424Simp			if (cfe->irqres == NULL)
41767187Simp				goto not_this_one;
41867242Simp			resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid,
41967242Simp			    rman_get_start(r), rman_get_end(r), 1);
42076424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
42176424Simp			    cfe->irqrid);
42276424Simp			rle->res = r;
42367187Simp		}
42467187Simp		/* If we get to here, we've allocated all we need */
42567167Simp		pf->cfe = cfe;
42667187Simp		break;
42767187Simp	    not_this_one:;
42867424Simp		DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n",
42967424Simp		    cfe->number));
43067333Simp		/*
43167333Simp		 * Release resources that we partially allocated
43267333Simp		 * from this config entry.
43367333Simp		 */
43467187Simp		for (i = 0; i < cfe->num_iospace; i++) {
43576424Simp			if (cfe->iores[i] != NULL) {
43670715Sjon				bus_release_resource(bus, SYS_RES_IOPORT,
43767187Simp				    cfe->iorid[i], cfe->iores[i]);
43882378Sjon				rle = resource_list_find(rl, SYS_RES_IOPORT,
43976424Simp				    cfe->iorid[i]);
44076424Simp				rle->res = NULL;
44176424Simp				resource_list_delete(rl, SYS_RES_IOPORT,
44276424Simp				    cfe->iorid[i]);
44375756Simp			}
44467187Simp			cfe->iores[i] = NULL;
44567187Simp		}
44676424Simp		if (cfe->irqmask && cfe->irqres != NULL) {
44767242Simp			bus_release_resource(bus, SYS_RES_IRQ,
44867187Simp			    cfe->irqrid, cfe->irqres);
44976424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
45076424Simp			    cfe->irqrid);
45176424Simp			rle->res = NULL;
45276424Simp			resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid);
45367187Simp			cfe->irqres = NULL;
45467187Simp		}
45567167Simp	}
45652506Simp}
45752506Simp
45882378Sjon/*
45982378Sjon * Free resources allocated by pccard_function_init(), May be called as long
46082378Sjon * as the function is disabled.
46182382Simp *
46282382Simp * NOTE: This function should be unnecessary.  pccard_function_init should
46382382Simp * never keep resources initialized.
46482378Sjon */
46582378Sjonstatic void
46682378Sjonpccard_function_free(struct pccard_function *pf)
46782378Sjon{
46882378Sjon	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
46982378Sjon	struct resource_list_entry *rle;
47082378Sjon
47182378Sjon	if (pf->pf_flags & PFF_ENABLED) {
47282378Sjon		printf("pccard_function_init: function is enabled");
47382378Sjon		return;
47482378Sjon	}
47582378Sjon
47682378Sjon	SLIST_FOREACH(rle, &devi->resources, link) {
47782378Sjon		if (rle->res) {
47882378Sjon			if (rle->res->r_dev != pf->sc->dev)
47982378Sjon				device_printf(pf->sc->dev,
48082378Sjon				    "function_free: Resource still owned by "
48182378Sjon				    "child, oops. "
48282378Sjon				    "(type=%d, rid=%d, addr=%lx)\n",
48382378Sjon				    rle->type, rle->rid,
48482378Sjon				    rman_get_start(rle->res));
48582378Sjon			BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
48682378Sjon			    rle->res->r_dev, rle->type, rle->rid, rle->res);
48782378Sjon			rle->res = NULL;
48882378Sjon		}
48982378Sjon	}
49082378Sjon	resource_list_free(&devi->resources);
49182378Sjon}
49282378Sjon
49352506Simp/* Enable a PCCARD function */
49482378Sjonstatic int
49555720Simppccard_function_enable(struct pccard_function *pf)
49652506Simp{
49752506Simp	struct pccard_function *tmp;
49852506Simp	int reg;
49955720Simp	device_t dev = pf->sc->dev;
50070746Simp
50167333Simp	if (pf->cfe == NULL) {
50267333Simp		DEVPRVERBOSE((dev, "No config entry could be allocated.\n"));
50374632Simp		return (ENOMEM);
50467333Simp	}
50552506Simp
50652506Simp	/*
50752506Simp	 * Increase the reference count on the socket, enabling power, if
50852506Simp	 * necessary.
50952506Simp	 */
51082378Sjon	pf->sc->sc_enabled_count++;
51152506Simp
51252506Simp	if (pf->pf_flags & PFF_ENABLED) {
51352506Simp		/*
51452506Simp		 * Don't do anything if we're already enabled.
51552506Simp		 */
51652506Simp		return (0);
51752506Simp	}
51852506Simp
51952506Simp	/*
52052506Simp	 * it's possible for different functions' CCRs to be in the same
52152506Simp	 * underlying page.  Check for that.
52252506Simp	 */
52352506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
52452506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
52552506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
52652506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
52782378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
52882378Sjon		    tmp->pf_ccr_realsize))) {
52952506Simp			pf->pf_ccrt = tmp->pf_ccrt;
53052506Simp			pf->pf_ccrh = tmp->pf_ccrh;
53152506Simp			pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
53252506Simp
53352506Simp			/*
53452506Simp			 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
53552506Simp			 * tmp->ccr_base) + pf->ccr_base;
53652506Simp			 */
53770715Sjon			/* pf->pf_ccr_offset =
53852506Simp			    (tmp->pf_ccr_offset + pf->ccr_base) -
53970715Sjon			    tmp->ccr_base; */
54052506Simp			pf->pf_ccr_window = tmp->pf_ccr_window;
54152506Simp			break;
54252506Simp		}
54352506Simp	}
54452506Simp	if (tmp == NULL) {
54555720Simp		pf->ccr_rid = 0;
54655720Simp		pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
54770715Sjon		    &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE);
54870715Sjon		if (!pf->ccr_res)
54952506Simp			goto bad;
55070746Simp		DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%lx\n",
55170746Simp		    rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res),
55270746Simp		    pf->ccr_base));
55361788Simp		CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
55461788Simp		    pf->ccr_rid, PCCARD_A_MEM_ATTR);
55570715Sjon		CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev,
55670748Simp		    pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset);
55755720Simp		pf->pf_ccrt = rman_get_bustag(pf->ccr_res);
55855720Simp		pf->pf_ccrh = rman_get_bushandle(pf->ccr_res);
55955720Simp		pf->pf_ccr_realsize = 1;
56052506Simp	}
56152506Simp
56252506Simp	reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX);
56352506Simp	reg |= PCCARD_CCR_OPTION_LEVIREQ;
56452506Simp	if (pccard_mfc(pf->sc)) {
56552506Simp		reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE |
56652506Simp			PCCARD_CCR_OPTION_ADDR_DECODE);
56782383Simp		/* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */
56852506Simp	}
56952506Simp	pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
57052506Simp
57152506Simp	reg = 0;
57252506Simp	if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0)
57352506Simp		reg |= PCCARD_CCR_STATUS_IOIS8;
57452506Simp	if (pf->cfe->flags & PCCARD_CFE_AUDIO)
57552506Simp		reg |= PCCARD_CCR_STATUS_AUDIO;
57652506Simp	pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg);
57752506Simp
57852506Simp	pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0);
57952506Simp
58052506Simp	if (pccard_mfc(pf->sc)) {
58152506Simp		long tmp, iosize;
58252506Simp
58352506Simp		tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
58452506Simp		/* round up to nearest (2^n)-1 */
58552506Simp		for (iosize = 1; iosize < tmp; iosize <<= 1)
58652506Simp			;
58752506Simp		iosize--;
58852506Simp
58952506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
59052506Simp				 pf->pf_mfc_iobase & 0xff);
59152506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
59252506Simp				 (pf->pf_mfc_iobase >> 8) & 0xff);
59352506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
59452506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
59552506Simp
59652506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
59752506Simp	}
59852506Simp
59952506Simp#ifdef PCCARDDEBUG
60052506Simp	if (pccard_debug) {
60152506Simp		STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
60270715Sjon			device_printf(tmp->sc->dev,
60355500Simp			    "function %d CCR at %d offset %x: "
60455500Simp			    "%x %x %x %x, %x %x %x %x, %x\n",
60570715Sjon			    tmp->number, tmp->pf_ccr_window,
60655500Simp			    tmp->pf_ccr_offset,
60755500Simp			    pccard_ccr_read(tmp, 0x00),
60855500Simp			    pccard_ccr_read(tmp, 0x02),
60955500Simp			    pccard_ccr_read(tmp, 0x04),
61055500Simp			    pccard_ccr_read(tmp, 0x06),
61155500Simp			    pccard_ccr_read(tmp, 0x0A),
61270715Sjon			    pccard_ccr_read(tmp, 0x0C),
61355500Simp			    pccard_ccr_read(tmp, 0x0E),
61455500Simp			    pccard_ccr_read(tmp, 0x10),
61555500Simp			    pccard_ccr_read(tmp, 0x12));
61652506Simp		}
61752506Simp	}
61852506Simp#endif
61952506Simp	pf->pf_flags |= PFF_ENABLED;
62052506Simp	return (0);
62152506Simp
62252506Simp bad:
62352506Simp	/*
62452506Simp	 * Decrement the reference count, and power down the socket, if
62552506Simp	 * necessary.
62652506Simp	 */
62782378Sjon	pf->sc->sc_enabled_count--;
62865098Simp	DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count));
62952506Simp
63052506Simp	return (1);
63152506Simp}
63252506Simp
63352506Simp/* Disable PCCARD function. */
63482378Sjonstatic void
63555720Simppccard_function_disable(struct pccard_function *pf)
63652506Simp{
63752506Simp	struct pccard_function *tmp;
63855720Simp	device_t dev = pf->sc->dev;
63952506Simp
64052506Simp	if (pf->cfe == NULL)
64161788Simp		panic("pccard_function_disable: function not initialized");
64252506Simp
64352506Simp	if ((pf->pf_flags & PFF_ENABLED) == 0) {
64452506Simp		/*
64552506Simp		 * Don't do anything if we're already disabled.
64652506Simp		 */
64752506Simp		return;
64852506Simp	}
64952506Simp
65070715Sjon	if (pf->intr_handler != NULL) {
65182378Sjon		struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
65282378Sjon		struct resource_list_entry *rle =
65382378Sjon		    resource_list_find(&devi->resources, SYS_RES_IRQ, 0);
65482378Sjon		BUS_TEARDOWN_INTR(dev, pf->dev, rle->res,
65582378Sjon		    pf->intr_handler_cookie);
65670715Sjon	}
65770715Sjon
65852506Simp	/*
65952506Simp	 * it's possible for different functions' CCRs to be in the same
66052506Simp	 * underlying page.  Check for that.  Note we mark us as disabled
66152506Simp	 * first to avoid matching ourself.
66252506Simp	 */
66352506Simp
66452506Simp	pf->pf_flags &= ~PFF_ENABLED;
66552506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
66652506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
66752506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
66852506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
66982378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
67082378Sjon		    tmp->pf_ccr_realsize)))
67152506Simp			break;
67252506Simp	}
67352506Simp
67452506Simp	/* Not used by anyone else; unmap the CCR. */
67552506Simp	if (tmp == NULL) {
67670715Sjon		bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid,
67755720Simp		    pf->ccr_res);
67855720Simp		pf->ccr_res = NULL;
67952506Simp	}
68052506Simp
68152506Simp	/*
68252506Simp	 * Decrement the reference count, and power down the socket, if
68352506Simp	 * necessary.
68452506Simp	 */
68582378Sjon	pf->sc->sc_enabled_count--;
68652506Simp}
68752506Simp
68855720Simp#if 0
68955720Simp/* XXX These functions are needed, but not like this XXX */
69052506Simpint
69155720Simppccard_io_map(struct pccard_function *pf, int width, bus_addr_t offset,
69255720Simp    bus_size_t size, struct pccard_io_handle *pcihp, int *windowp)
69352506Simp{
69452506Simp	int reg;
69552506Simp
69667167Simp	if (pccard_chip_io_map(pf->sc->pct, pf->sc->pch, width, offset, size,
69767167Simp	    pcihp, windowp))
69852506Simp		return (1);
69952506Simp
70052506Simp	/*
70152506Simp	 * XXX in the multifunction multi-iospace-per-function case, this
70252506Simp	 * needs to cooperate with io_alloc to make sure that the spaces
70352506Simp	 * don't overlap, and that the ccr's are set correctly
70452506Simp	 */
70552506Simp
70652506Simp	if (pccard_mfc(pf->sc)) {
70752506Simp		long tmp, iosize;
70852506Simp
70952506Simp		if (pf->pf_mfc_iomax == 0) {
71052506Simp			pf->pf_mfc_iobase = pcihp->addr + offset;
71152506Simp			pf->pf_mfc_iomax = pf->pf_mfc_iobase + size;
71252506Simp		} else {
71352506Simp			/* this makes the assumption that nothing overlaps */
71452506Simp			if (pf->pf_mfc_iobase > pcihp->addr + offset)
71552506Simp				pf->pf_mfc_iobase = pcihp->addr + offset;
71652506Simp			if (pf->pf_mfc_iomax < pcihp->addr + offset + size)
71752506Simp				pf->pf_mfc_iomax = pcihp->addr + offset + size;
71852506Simp		}
71952506Simp
72052506Simp		tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
72152506Simp		/* round up to nearest (2^n)-1 */
72252506Simp		for (iosize = 1; iosize >= tmp; iosize <<= 1)
72352506Simp			;
72452506Simp		iosize--;
72552506Simp
72670715Sjon		pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
72755720Simp		    pf->pf_mfc_iobase & 0xff);
72852506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
72955720Simp		    (pf->pf_mfc_iobase >> 8) & 0xff);
73052506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
73152506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
73252506Simp
73352506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
73452506Simp
73552506Simp		reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION);
73652506Simp		reg |= PCCARD_CCR_OPTION_ADDR_DECODE;
73752506Simp		pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
73852506Simp	}
73952506Simp	return (0);
74052506Simp}
74152506Simp
74252506Simpvoid
74355720Simppccard_io_unmap(struct pccard_function *pf, int window)
74452506Simp{
74552506Simp
74652506Simp	pccard_chip_io_unmap(pf->sc->pct, pf->sc->pch, window);
74752506Simp
74852506Simp	/* XXX Anything for multi-function cards? */
74952506Simp}
75052506Simp#endif
75152506Simp
75266058Simp/*
75366058Simp * simulate the old "probe" routine.  In the new world order, the driver
75466058Simp * needs to grab devices while in the old they were assigned to the device by
75566058Simp * the pccardd process.  These symbols are exported to the upper layers.
75666058Simp */
75774636Simpstatic int
75874636Simppccard_compat_do_probe(device_t bus, device_t dev)
75966058Simp{
76066058Simp	return (CARD_COMPAT_MATCH(dev));
76166058Simp}
76266058Simp
76374636Simpstatic int
76474636Simppccard_compat_do_attach(device_t bus, device_t dev)
76566058Simp{
76666058Simp	int err;
76766058Simp
76866058Simp	err = CARD_COMPAT_PROBE(dev);
76966058Simp	if (err == 0)
77066058Simp		err = CARD_COMPAT_ATTACH(dev);
77166058Simp	return (err);
77266058Simp}
77366058Simp
77453873Simp#define PCCARD_NPORT	2
77553873Simp#define PCCARD_NMEM	5
77653873Simp#define PCCARD_NIRQ	1
77753873Simp#define PCCARD_NDRQ	0
77853873Simp
77952506Simpstatic int
78052506Simppccard_add_children(device_t dev, int busno)
78152506Simp{
78259193Simp	/* Call parent to scan for any current children */
78374632Simp	return (0);
78452506Simp}
78552506Simp
78652506Simpstatic int
78752506Simppccard_probe(device_t dev)
78852506Simp{
78967333Simp	device_set_desc(dev, "16-bit PCCard bus");
79074632Simp	return (pccard_add_children(dev, device_get_unit(dev)));
79152506Simp}
79252506Simp
79359193Simpstatic int
79459193Simppccard_attach(device_t dev)
79559193Simp{
79664850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
79761788Simp
79859193Simp	sc->dev = dev;
79961788Simp	sc->sc_enabled_count = 0;
80074632Simp	return (bus_generic_attach(dev));
80159193Simp}
80259193Simp
80382378Sjonstatic int
80482378Sjonpccard_detach(device_t dev)
80582378Sjon{
80682378Sjon	pccard_detach_card(dev, 0);
80782378Sjon	return 0;
80882378Sjon}
80982378Sjon
81053873Simpstatic void
81153873Simppccard_print_resources(struct resource_list *rl, const char *name, int type,
81253873Simp    int count, const char *format)
81353873Simp{
81453873Simp	struct resource_list_entry *rle;
81553873Simp	int printed;
81653873Simp	int i;
81753873Simp
81853873Simp	printed = 0;
81953873Simp	for (i = 0; i < count; i++) {
82053873Simp		rle = resource_list_find(rl, type, i);
82176424Simp		if (rle != NULL) {
82253873Simp			if (printed == 0)
82353873Simp				printf(" %s ", name);
82453873Simp			else if (printed > 0)
82553873Simp				printf(",");
82653873Simp			printed++;
82753873Simp			printf(format, rle->start);
82853873Simp			if (rle->count > 1) {
82953873Simp				printf("-");
83053873Simp				printf(format, rle->start + rle->count - 1);
83153873Simp			}
83253873Simp		} else if (i > 3) {
83353873Simp			/* check the first few regardless */
83453873Simp			break;
83553873Simp		}
83653873Simp	}
83753873Simp}
83853873Simp
83953873Simpstatic int
84053873Simppccard_print_child(device_t dev, device_t child)
84153873Simp{
84266847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
84353873Simp	struct resource_list *rl = &devi->resources;
84453873Simp	int retval = 0;
84553873Simp
84653873Simp	retval += bus_print_child_header(dev, child);
84753873Simp	retval += printf(" at");
84853873Simp
84976424Simp	if (devi != NULL) {
85053873Simp		pccard_print_resources(rl, "port", SYS_RES_IOPORT,
85153873Simp		    PCCARD_NPORT, "%#lx");
85253873Simp		pccard_print_resources(rl, "iomem", SYS_RES_MEMORY,
85353873Simp		    PCCARD_NMEM, "%#lx");
85453873Simp		pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ,
85553873Simp		    "%ld");
85670715Sjon		pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ,
85753873Simp		    "%ld");
85867269Simp		retval += printf(" function %d config %d", devi->fcn->number,
85967269Simp		    devi->fcn->cfe->number);
86053873Simp	}
86153873Simp
86253873Simp	retval += bus_print_child_footer(dev, child);
86353873Simp
86453873Simp	return (retval);
86553873Simp}
86653873Simp
86753873Simpstatic int
86853873Simppccard_set_resource(device_t dev, device_t child, int type, int rid,
86953873Simp		 u_long start, u_long count)
87053873Simp{
87166847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
87253873Simp	struct resource_list *rl = &devi->resources;
87353873Simp
87453873Simp	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
87553873Simp	    && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
87674632Simp		return (EINVAL);
87753873Simp	if (rid < 0)
87874632Simp		return (EINVAL);
87953873Simp	if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT)
88074632Simp		return (EINVAL);
88153873Simp	if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM)
88274632Simp		return (EINVAL);
88353873Simp	if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ)
88474632Simp		return (EINVAL);
88553873Simp	if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ)
88674632Simp		return (EINVAL);
88753873Simp
88853873Simp	resource_list_add(rl, type, rid, start, start + count - 1, count);
88982378Sjon	if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev,
89082378Sjon	    type, &rid, start, start + count - 1, count, 0))
89182378Sjon		return 0;
89282378Sjon	else
89382378Sjon		return ENOMEM;
89453873Simp}
89553873Simp
89653873Simpstatic int
89753873Simppccard_get_resource(device_t dev, device_t child, int type, int rid,
89853873Simp    u_long *startp, u_long *countp)
89953873Simp{
90066847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
90153873Simp	struct resource_list *rl = &devi->resources;
90253873Simp	struct resource_list_entry *rle;
90353873Simp
90453873Simp	rle = resource_list_find(rl, type, rid);
90576424Simp	if (rle == NULL)
90674632Simp		return (ENOENT);
90770715Sjon
90876424Simp	if (startp != NULL)
90953873Simp		*startp = rle->start;
91076424Simp	if (countp != NULL)
91153873Simp		*countp = rle->count;
91253873Simp
91374632Simp	return (0);
91453873Simp}
91553873Simp
91653873Simpstatic void
91753873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid)
91853873Simp{
91966847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
92053873Simp	struct resource_list *rl = &devi->resources;
92153873Simp	resource_list_delete(rl, type, rid);
92253873Simp}
92353873Simp
92459193Simpstatic int
92559193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid,
92659193Simp    u_int32_t flags)
92759193Simp{
92874632Simp	return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type,
92974632Simp	    rid, flags));
93059193Simp}
93159193Simp
93259193Simpstatic int
93359193Simppccard_set_memory_offset(device_t dev, device_t child, int rid,
93482378Sjon    u_int32_t offset, u_int32_t *deltap)
93570715Sjon
93659193Simp{
93774632Simp	return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid,
93874632Simp	    offset, deltap));
93959193Simp}
94059193Simp
94166058Simpstatic int
94266058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result)
94366058Simp{
94466847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
94566779Simp	struct pccard_function *func = devi->fcn;
94666779Simp	struct pccard_softc *sc = PCCARD_SOFTC(bus);
94766779Simp
94866058Simp	/* PCCARD_IVAR_ETHADDR unhandled from oldcard */
94966779Simp	switch (which) {
95066779Simp	default:
95166779Simp	case PCCARD_IVAR_ETHADDR:
95282781Sshiba		bcopy(func->pf_funce_lan_nid, result, ETHER_ADDR_LEN);
95366779Simp		break;
95466779Simp	case PCCARD_IVAR_VENDOR:
95566779Simp		*(u_int32_t *) result = sc->card.manufacturer;
95666779Simp		break;
95766779Simp	case PCCARD_IVAR_PRODUCT:
95866779Simp		*(u_int32_t *) result = sc->card.product;
95966779Simp		break;
96075761Simp	case PCCARD_IVAR_FUNCTION:
96175761Simp		*(u_int32_t *) result = func->function;
96275761Simp		break;
96366779Simp	case PCCARD_IVAR_FUNCTION_NUMBER:
96466847Simp		if (!func) {
96566847Simp			device_printf(bus, "No function number, bug!\n");
96666847Simp			return (ENOENT);
96766847Simp		}
96866847Simp		*(u_int32_t *) result = func->number;
96966779Simp		break;
97066779Simp	case PCCARD_IVAR_VENDOR_STR:
97166779Simp		*(char **) result = sc->card.cis1_info[0];
97266779Simp		break;
97366779Simp	case PCCARD_IVAR_PRODUCT_STR:
97466779Simp		*(char **) result = sc->card.cis1_info[1];
97566779Simp		break;
97666779Simp	case PCCARD_IVAR_CIS3_STR:
97766779Simp		*(char **) result = sc->card.cis1_info[2];
97866779Simp		break;
97967167Simp	case PCCARD_IVAR_CIS4_STR:
98067167Simp		*(char **) result = sc->card.cis1_info[2];
98167167Simp		break;
98266779Simp	}
98366779Simp	return (0);
98466058Simp}
98566058Simp
98666779Simpstatic void
98766779Simppccard_driver_added(device_t dev, driver_t *driver)
98866779Simp{
98982378Sjon	struct pccard_softc *sc = PCCARD_SOFTC(dev);
99082378Sjon	struct pccard_function *pf;
99182378Sjon	device_t child;
99282378Sjon
99382378Sjon	if (sc->sc_enabled_count == 0) {
99482378Sjon		CARD_REPROBE_CARD(device_get_parent(dev), dev);
99582378Sjon		return;
99682378Sjon	}
99782378Sjon
99882378Sjon	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
99982378Sjon		if (STAILQ_EMPTY(&pf->cfe_head))
100082378Sjon			continue;
100182378Sjon		child = pf->dev;
100282378Sjon		if (device_get_state(child) != DS_NOTPRESENT)
100382378Sjon			continue;
100482378Sjon		if (pccard_function_enable(pf) == 0 &&
100582378Sjon		    device_probe_and_attach(child) == 0) {
100682378Sjon			DEVPRINTF((sc->dev, "function %d CCR at %d "
100782378Sjon			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
100882378Sjon			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
100982378Sjon			    pccard_ccr_read(pf, 0x00),
101082378Sjon			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
101182378Sjon			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
101282378Sjon			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
101382378Sjon			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
101482378Sjon		} else {
101586907Simp			if (pf->cfe != NULL)
101686907Simp				pccard_function_disable(pf);
101782378Sjon		}
101882378Sjon	}
101982378Sjon	return;
102066779Simp}
102166058Simp
102267242Simpstatic struct resource *
102367242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid,
102467242Simp    u_long start, u_long end, u_long count, u_int flags)
102567242Simp{
102682378Sjon	struct pccard_ivar *dinfo;
102782378Sjon	struct resource_list_entry *rle = 0;
102882378Sjon	int passthrough = (device_get_parent(child) != dev);
102967242Simp
103082378Sjon	if (passthrough) {
103182378Sjon		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
103282378Sjon		    type, rid, start, end, count, flags));
103382378Sjon	}
103470715Sjon
103582378Sjon	dinfo = device_get_ivars(child);
103682378Sjon	rle = resource_list_find(&dinfo->resources, type, *rid);
103770715Sjon
103882378Sjon	if (!rle)
103982378Sjon		return NULL;		/* no resource of that type/rid */
104070715Sjon
104182378Sjon	if (!rle->res) {
104282378Sjon		device_printf(dev, "WARNING: Resource not reserved by pccard bus\n");
104382378Sjon		return NULL;
104482378Sjon	} else {
104582378Sjon		if (rle->res->r_dev != dev) return NULL;
104682378Sjon		bus_release_resource(dev, type, *rid, rle->res);
104782378Sjon		rle->res = NULL;
104882378Sjon		switch(type) {
104982378Sjon		case SYS_RES_IOPORT:
105082378Sjon		case SYS_RES_MEMORY:
105182378Sjon			if (!(flags & RF_ALIGNMENT_MASK))
105282378Sjon				flags |= rman_make_alignment_flags(rle->count);
105382378Sjon			break;
105482378Sjon		case SYS_RES_IRQ:
105582378Sjon			flags |= RF_SHAREABLE;
105682378Sjon			break;
105782378Sjon		}
105882378Sjon		return resource_list_alloc(&dinfo->resources, dev, child, type,
105982378Sjon		    rid, rle->start, rle->end, rle->count, flags);
106067269Simp	}
106167242Simp}
106267242Simp
106367242Simpstatic int
106467242Simppccard_release_resource(device_t dev, device_t child, int type, int rid,
106567242Simp    struct resource *r)
106667242Simp{
106782378Sjon	struct pccard_ivar *dinfo;
106882378Sjon	int passthrough = (device_get_parent(child) != dev);
106982378Sjon	struct resource_list_entry *rle = 0;
107082378Sjon	int ret;
107182378Sjon	int flags;
107270715Sjon
107382378Sjon	if (passthrough)
107482378Sjon		return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
107582378Sjon		    type, rid, r);
107670715Sjon
107782378Sjon	dinfo = device_get_ivars(child);
107870715Sjon
107982378Sjon	rle = resource_list_find(&dinfo->resources, type, rid);
108070715Sjon
108182378Sjon	if (!rle) {
108282378Sjon		device_printf(dev, "Allocated resource not found, "
108382378Sjon		    "%d %x %lx %lx\n",
108482378Sjon		    type, rid, rman_get_start(r), rman_get_size(r));
108582378Sjon		return ENOENT;
108670715Sjon	}
108782378Sjon	if (!rle->res) {
108882378Sjon		device_printf(dev, "Allocated resource not recorded\n");
108982378Sjon		return ENOENT;
109070715Sjon	}
109170715Sjon
109282378Sjon	ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
109382378Sjon	    type, rid, r);
109482378Sjon	switch(type) {
109582378Sjon	case SYS_RES_IOPORT:
109682378Sjon	case SYS_RES_MEMORY:
109782378Sjon		flags = rman_make_alignment_flags(rle->count);
109882378Sjon		break;
109982378Sjon	case SYS_RES_IRQ:
110082378Sjon		flags = RF_SHAREABLE;
110182378Sjon		break;
110282378Sjon	default:
110382378Sjon		flags = 0;
110470715Sjon	}
110582378Sjon	rle->res = bus_alloc_resource(dev, type, &rid,
110682378Sjon	    rle->start, rle->end, rle->count, flags);
110782378Sjon	if (rle->res == NULL)
110882378Sjon		device_printf(dev, "release_resource: "
110982378Sjon		    "unable to reaquire resource\n");
111082378Sjon	return ret;
111167242Simp}
111267242Simp
111367333Simpstatic void
111467333Simppccard_child_detached(device_t parent, device_t dev)
111567333Simp{
111667333Simp	struct pccard_ivar *ivar = PCCARD_IVAR(dev);
111782378Sjon	struct pccard_function *pf = ivar->fcn;
111867333Simp
111982378Sjon	pccard_function_disable(pf);
112067333Simp}
112167333Simp
112270715Sjonstatic void
112370762Simppccard_intr(void *arg)
112470762Simp{
112582378Sjon	struct pccard_function *pf = (struct pccard_function*) arg;
112682378Sjon	int reg;
112782378Sjon
112882383Simp	/*
112982383Simp	 * If we go to resetting a card, we may need a null interrupt hanlder
113082383Simp	 * to work (since the system may call it before the device can
113182383Simp	 * establish an ISR) due to interrupt sharing at a higher level.
113282383Simp	 */
113382378Sjon	if (pf->intr_handler == NULL)
113482378Sjon		panic("Null interrupt handler?\n");
113582378Sjon
113682383Simp	/*
113782383Simp	 * XXX The CCR_STATUS register bits used here are
113882383Simp	 * only valid for multi function cards.
113982383Simp	 */
114082378Sjon	reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
114182378Sjon	if (reg & PCCARD_CCR_STATUS_INTR) {
114282378Sjon		pccard_ccr_write(pf, PCCARD_CCR_STATUS,
114382378Sjon				 reg & ~PCCARD_CCR_STATUS_INTR);
114482378Sjon		pf->intr_handler(pf->intr_handler_arg);
114570715Sjon	}
114670715Sjon}
114770715Sjon
114870715Sjonstatic int
114970762Simppccard_setup_intr(device_t dev, device_t child, struct resource *irq,
115070762Simp    int flags, driver_intr_t *intr, void *arg, void **cookiep)
115170715Sjon{
115270715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
115370715Sjon	struct pccard_function *func = ivar->fcn;
115470715Sjon
115570715Sjon	if (func->intr_handler != NULL)
115670762Simp		panic("Only one interrupt handler per function allowed\n");
115770715Sjon
115870715Sjon	func->intr_handler = intr;
115970715Sjon	func->intr_handler_arg = arg;
116082378Sjon	func->intr_handler_cookie = *cookiep;
116170715Sjon	pccard_ccr_write(func, PCCARD_CCR_OPTION,
116282378Sjon	    pccard_ccr_read(func, PCCARD_CCR_OPTION) |
116370762Simp	    PCCARD_CCR_OPTION_IREQ_ENABLE);
116470715Sjon
116582383Simp	/*
116682383Simp	 * XXX Don't use TTY type for our interrupt handler.  It makes
116782383Simp	 * the spl masks wrong on -stable.  Instead, we should use the type
116882383Simp	 * that was requested of us.
116982383Simp	 */
117082378Sjon	bus_setup_intr(dev, irq, INTR_TYPE_TTY/* | INTR_FAST*/,
117182378Sjon	    pccard_intr, func, cookiep);
117274632Simp	return (0);
117370715Sjon}
117470715Sjon
117570715Sjonstatic int
117670762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r,
117770762Simp    void *cookie)
117870715Sjon{
117970715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
118070715Sjon	struct pccard_function *func = ivar->fcn;
118182378Sjon	int ret;
118270715Sjon
118370715Sjon	pccard_ccr_write(func, PCCARD_CCR_OPTION,
118470762Simp	    pccard_ccr_read(func, PCCARD_CCR_OPTION) &
118570762Simp	    ~PCCARD_CCR_OPTION_IREQ_ENABLE);
118670715Sjon
118782378Sjon	ret = bus_teardown_intr(dev, r, cookie);
118882378Sjon	if (ret == 0) {
118982378Sjon		func->intr_handler = NULL;
119082378Sjon		func->intr_handler_arg = NULL;
119182378Sjon		func->intr_handler_cookie = NULL;
119282378Sjon	}
119370715Sjon
119482378Sjon	return (ret);
119570715Sjon}
119670715Sjon
119752506Simpstatic device_method_t pccard_methods[] = {
119852506Simp	/* Device interface */
119952506Simp	DEVMETHOD(device_probe,		pccard_probe),
120059193Simp	DEVMETHOD(device_attach,	pccard_attach),
120182378Sjon	DEVMETHOD(device_detach,	pccard_detach),
120252506Simp	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
120352506Simp	DEVMETHOD(device_suspend,	bus_generic_suspend),
120452506Simp	DEVMETHOD(device_resume,	bus_generic_resume),
120552506Simp
120652506Simp	/* Bus interface */
120752506Simp	DEVMETHOD(bus_print_child,	pccard_print_child),
120866779Simp	DEVMETHOD(bus_driver_added,	pccard_driver_added),
120967333Simp	DEVMETHOD(bus_child_detached,	pccard_child_detached),
121067242Simp	DEVMETHOD(bus_alloc_resource,	pccard_alloc_resource),
121167242Simp	DEVMETHOD(bus_release_resource,	pccard_release_resource),
121282378Sjon	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
121382378Sjon	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
121470715Sjon	DEVMETHOD(bus_setup_intr,	pccard_setup_intr),
121570715Sjon	DEVMETHOD(bus_teardown_intr,	pccard_teardown_intr),
121652506Simp	DEVMETHOD(bus_set_resource,	pccard_set_resource),
121752506Simp	DEVMETHOD(bus_get_resource,	pccard_get_resource),
121852506Simp	DEVMETHOD(bus_delete_resource,	pccard_delete_resource),
121966058Simp	DEVMETHOD(bus_read_ivar,	pccard_read_ivar),
122052506Simp
122159193Simp	/* Card Interface */
122259193Simp	DEVMETHOD(card_set_res_flags,	pccard_set_res_flags),
122359193Simp	DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset),
122459193Simp	DEVMETHOD(card_get_type,	pccard_card_gettype),
122559193Simp	DEVMETHOD(card_attach_card,	pccard_attach_card),
122659193Simp	DEVMETHOD(card_detach_card,	pccard_detach_card),
122774636Simp	DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe),
122874636Simp	DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach),
122959193Simp
123052506Simp	{ 0, 0 }
123152506Simp};
123252506Simp
123352506Simpstatic driver_t pccard_driver = {
123452506Simp	"pccard",
123552506Simp	pccard_methods,
123664850Simp	sizeof(struct pccard_softc)
123752506Simp};
123852506Simp
123952506Simpdevclass_t	pccard_devclass;
124052506Simp
124153873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
124252506SimpDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0);
124352506SimpDRIVER_MODULE(pccard, pccbb, pccard_driver, pccard_devclass, 0, 0);
124453873SimpDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0);
124564927SimpMODULE_VERSION(pccard, 1);
124670715Sjon/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/
1247