pccard.c revision 104641
166200Simp/*	$NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $	*/
252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard.c 104641 2002-10-07 23:05:33Z imp $ */
352506Simp
452506Simp/*
552506Simp * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
652506Simp *
752506Simp * Redistribution and use in source and binary forms, with or without
852506Simp * modification, are permitted provided that the following conditions
952506Simp * are met:
1052506Simp * 1. Redistributions of source code must retain the above copyright
1152506Simp *    notice, this list of conditions and the following disclaimer.
1252506Simp * 2. Redistributions in binary form must reproduce the above copyright
1352506Simp *    notice, this list of conditions and the following disclaimer in the
1452506Simp *    documentation and/or other materials provided with the distribution.
1552506Simp * 3. All advertising materials mentioning features or use of this software
1652506Simp *    must display the following acknowledgement:
1752506Simp *	This product includes software developed by Marc Horowitz.
1852506Simp * 4. The name of the author may not be used to endorse or promote products
1952506Simp *    derived from this software without specific prior written permission.
2052506Simp *
2152506Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2252506Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2352506Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2452506Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2552506Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2652506Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2752506Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2852506Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2952506Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3052506Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3152506Simp */
3252506Simp
3352506Simp#include <sys/param.h>
3452506Simp#include <sys/systm.h>
3552506Simp#include <sys/malloc.h>
3652506Simp#include <sys/module.h>
3752506Simp#include <sys/kernel.h>
3852506Simp#include <sys/queue.h>
3991786Simp#include <sys/sysctl.h>
4052506Simp#include <sys/types.h>
4152506Simp
4252506Simp#include <sys/bus.h>
4352506Simp#include <machine/bus.h>
4452506Simp#include <sys/rman.h>
4552506Simp#include <machine/resource.h>
4652506Simp
4782781Sshiba#include <net/ethernet.h>
4882781Sshiba
4952506Simp#include <dev/pccard/pccardreg.h>
5052506Simp#include <dev/pccard/pccardvar.h>
5152506Simp
5255500Simp#include "power_if.h"
5359193Simp#include "card_if.h"
5455500Simp
5555500Simp#define PCCARDDEBUG
5655500Simp
5791786Simp/* sysctl vars */
5891786SimpSYSCTL_NODE(_hw, OID_AUTO, pccard, CTLFLAG_RD, 0, "PCCARD parameters");
5991786Simp
6091786Simpint	pccard_debug = 0;
6191786SimpTUNABLE_INT("hw.pccard.debug", &pccard_debug);
6291786SimpSYSCTL_INT(_hw_pccard, OID_AUTO, debug, CTLFLAG_RW,
6391786Simp    &pccard_debug, 0,
6491786Simp  "pccard debug");
6591786Simp
6691786Simpint	pccard_cis_debug = 0;
6791786SimpTUNABLE_INT("hw.pccard.cis_debug", &pccard_cis_debug);
6891786SimpSYSCTL_INT(_hw_pccard, OID_AUTO, cis_debug, CTLFLAG_RW,
6991786Simp    &pccard_cis_debug, 0, "pccard CIS debug");
7091786Simp
7152506Simp#ifdef PCCARDDEBUG
7252506Simp#define	DPRINTF(arg) if (pccard_debug) printf arg
7355500Simp#define	DEVPRINTF(arg) if (pccard_debug) device_printf arg
7467333Simp#define PRVERBOSE(arg) printf arg
7567333Simp#define DEVPRVERBOSE(arg) device_printf arg
7652506Simp#else
7752506Simp#define	DPRINTF(arg)
7855500Simp#define	DEVPRINTF(arg)
7967333Simp#define PRVERBOSE(arg) if (bootverbose) printf arg
8067333Simp#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg
8152506Simp#endif
8252506Simp
8382378Sjonstatic int	pccard_ccr_read(struct pccard_function *pf, int ccr);
8482378Sjonstatic void	pccard_ccr_write(struct pccard_function *pf, int ccr, int val);
8582378Sjonstatic int	pccard_attach_card(device_t dev);
8682378Sjonstatic int	pccard_detach_card(device_t dev, int flags);
8782378Sjonstatic int	pccard_card_gettype(device_t dev, int *type);
8882378Sjonstatic void	pccard_function_init(struct pccard_function *pf);
8982378Sjonstatic void	pccard_function_free(struct pccard_function *pf);
9082378Sjonstatic int	pccard_function_enable(struct pccard_function *pf);
9182378Sjonstatic void	pccard_function_disable(struct pccard_function *pf);
9282378Sjonstatic int	pccard_compat_do_probe(device_t bus, device_t dev);
9382378Sjonstatic int	pccard_compat_do_attach(device_t bus, device_t dev);
9482378Sjonstatic int	pccard_add_children(device_t dev, int busno);
9582378Sjonstatic int	pccard_probe(device_t dev);
9682378Sjonstatic int	pccard_attach(device_t dev);
9782378Sjonstatic int	pccard_detach(device_t dev);
9882378Sjonstatic void	pccard_print_resources(struct resource_list *rl,
9982378Sjon		    const char *name, int type, int count, const char *format);
10082378Sjonstatic int	pccard_print_child(device_t dev, device_t child);
10182378Sjonstatic int	pccard_set_resource(device_t dev, device_t child, int type,
10282378Sjon		    int rid, u_long start, u_long count);
10382378Sjonstatic int	pccard_get_resource(device_t dev, device_t child, int type,
10482378Sjon		    int rid, u_long *startp, u_long *countp);
10582378Sjonstatic void	pccard_delete_resource(device_t dev, device_t child, int type,
10682378Sjon		    int rid);
10782378Sjonstatic int	pccard_set_res_flags(device_t dev, device_t child, int type,
10882378Sjon		    int rid, u_int32_t flags);
10982378Sjonstatic int	pccard_set_memory_offset(device_t dev, device_t child, int rid,
11082378Sjon		    u_int32_t offset, u_int32_t *deltap);
111104641Simpstatic void	pccard_probe_nomatch(device_t cbdev, device_t child);
11282378Sjonstatic int	pccard_read_ivar(device_t bus, device_t child, int which,
11382378Sjon		    u_char *result);
11482378Sjonstatic void	pccard_driver_added(device_t dev, driver_t *driver);
11582378Sjonstatic struct resource *pccard_alloc_resource(device_t dev,
11682378Sjon		    device_t child, int type, int *rid, u_long start,
11782378Sjon		    u_long end, u_long count, u_int flags);
11882378Sjonstatic int	pccard_release_resource(device_t dev, device_t child, int type,
11982378Sjon		    int rid, struct resource *r);
12082378Sjonstatic void	pccard_child_detached(device_t parent, device_t dev);
12182378Sjonstatic void	pccard_intr(void *arg);
12282378Sjonstatic int	pccard_setup_intr(device_t dev, device_t child,
12382378Sjon		    struct resource *irq, int flags, driver_intr_t *intr,
12482378Sjon		    void *arg, void **cookiep);
12582378Sjonstatic int	pccard_teardown_intr(device_t dev, device_t child,
12682378Sjon		    struct resource *r, void *cookie);
12752506Simp
12897613Stakawatastatic const struct pccard_product *
12997613Stakawatapccard_do_product_lookup(device_t bus, device_t dev,
13097613Stakawata			 const struct pccard_product *tab, size_t ent_size,
13197613Stakawata			 pccard_product_match_fn matchfn);
13297613Stakawata
13397613Stakawata
13482378Sjonstatic int
13574632Simppccard_ccr_read(struct pccard_function *pf, int ccr)
13652506Simp{
13752506Simp	return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
13852506Simp	    pf->pf_ccr_offset + ccr));
13952506Simp}
14052506Simp
14182378Sjonstatic void
14274632Simppccard_ccr_write(struct pccard_function *pf, int ccr, int val)
14352506Simp{
14452506Simp	if ((pf->ccr_mask) & (1 << (ccr / 2))) {
14552506Simp		bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
14652506Simp		    pf->pf_ccr_offset + ccr, val);
14752506Simp	}
14852506Simp}
14952506Simp
15059193Simpstatic int
15159193Simppccard_attach_card(device_t dev)
15252506Simp{
15364850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
15452506Simp	struct pccard_function *pf;
15565917Simp	struct pccard_ivar *ivar;
15661788Simp	device_t child;
157102713Simp	int i;
15852506Simp
15952506Simp	/*
16052506Simp	 * this is here so that when socket_enable calls gettype, trt happens
16152506Simp	 */
16252506Simp	STAILQ_INIT(&sc->card.pf_head);
16352506Simp
16455500Simp	DEVPRINTF((dev, "chip_socket_enable\n"));
16555500Simp	POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
16652506Simp
16755500Simp	DEVPRINTF((dev, "read_cis\n"));
16852506Simp	pccard_read_cis(sc);
16952506Simp
17055500Simp	DEVPRINTF((dev, "check_cis_quirks\n"));
17152506Simp	pccard_check_cis_quirks(dev);
17252506Simp
17352506Simp	/*
17452506Simp	 * bail now if the card has no functions, or if there was an error in
17552506Simp	 * the cis.
17652506Simp	 */
17752506Simp
17870715Sjon	if (sc->card.error) {
179102713Simp		device_printf(dev, "CARD ERROR!\n");
18052506Simp		return (1);
18170715Sjon	}
18270715Sjon	if (STAILQ_EMPTY(&sc->card.pf_head)) {
183102713Simp		device_printf(dev, "Card has no functions!\n");
18452506Simp		return (1);
18570715Sjon	}
18652506Simp
18790436Simp	if (bootverbose || pccard_debug)
18852506Simp		pccard_print_cis(dev);
18952506Simp
19055500Simp	DEVPRINTF((dev, "functions scanning\n"));
191102713Simp	i = -1;
19252506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
193102713Simp		i++;
194102713Simp		if (STAILQ_EMPTY(&pf->cfe_head)) {
195102713Simp			device_printf(dev,
196102713Simp			    "Function %d has no config entries.!\n", i);
19752506Simp			continue;
198102713Simp		}
19952506Simp		pf->sc = sc;
20052506Simp		pf->cfe = NULL;
20164927Simp		pf->dev = NULL;
20252506Simp	}
203104641Simp	DEVPRINTF((dev, "Card has %d functions. pccard_mfc is %d\n", i + 1,
204102713Simp	    pccard_mfc(sc)));
20582378Sjon
20652506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
20752506Simp		if (STAILQ_EMPTY(&pf->cfe_head))
20852506Simp			continue;
20961788Simp		/*
21061788Simp		 * In NetBSD, the drivers are responsible for activating
21161788Simp		 * each function of a card.  I think that in FreeBSD we
21261788Simp		 * want to activate them enough for the usual bus_*_resource
21361788Simp		 * routines will do the right thing.  This many mean a
21461788Simp		 * departure from the current NetBSD model.
21561788Simp		 *
216104641Simp		 * This seems to work well in practice for most cards.
217104641Simp		 * However, there are two cases that are problematic.
218104641Simp		 * If a driver wishes to pick and chose which config
219104641Simp		 * entry to use, then this method falls down.  These
220104641Simp		 * are usually older cards.  In addition, there are
221104641Simp		 * some cards that have multiple hardware units on the
222104641Simp		 * cards, but presents only one CIS chain.  These cards
223104641Simp		 * are combination cards, but only one of these units
224104641Simp		 * can be on at a time.
22561788Simp		 */
22667897Sdwmalone		ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF,
22767897Sdwmalone		    M_WAITOK | M_ZERO);
22861788Simp		child = device_add_child(dev, NULL, -1);
22965917Simp		device_set_ivars(child, ivar);
23066847Simp		ivar->fcn = pf;
23167187Simp		pf->dev = child;
23267167Simp		/*
23367167Simp		 * XXX We might want to move the next two lines into
23467167Simp		 * XXX the pccard interface layer.  For the moment, this
23567167Simp		 * XXX is OK, but some drivers want to pick the config
23667167Simp		 * XXX entry to use as well as some address tweaks (mostly
23767167Simp		 * XXX due to bugs in decode logic that makes some
23867167Simp		 * XXX addresses illegal or broken).
23967167Simp		 */
24065917Simp		pccard_function_init(pf);
24182378Sjon		if (sc->sc_enabled_count == 0)
24282378Sjon			POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
24367333Simp		if (pccard_function_enable(pf) == 0 &&
24467333Simp		    device_probe_and_attach(child) == 0) {
24555500Simp			DEVPRINTF((sc->dev, "function %d CCR at %d "
24667167Simp			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
24767167Simp			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
24867167Simp			    pccard_ccr_read(pf, 0x00),
24952506Simp			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
25052506Simp			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
25152506Simp			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
25252506Simp			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
25367167Simp		} else {
25486907Simp			if (pf->cfe != NULL)
25586907Simp				pccard_function_disable(pf);
25652506Simp		}
25752506Simp	}
25874632Simp	return (0);
25952506Simp}
26052506Simp
26159193Simpstatic int
26259193Simppccard_detach_card(device_t dev, int flags)
26352506Simp{
26464850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
26552506Simp	struct pccard_function *pf;
26682378Sjon	struct pccard_config_entry *cfe;
26752506Simp
26852506Simp	/*
26952506Simp	 * We are running on either the PCCARD socket's event thread
27052506Simp	 * or in user context detaching a device by user request.
27152506Simp	 */
27252506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
27382378Sjon		int state = device_get_state(pf->dev);
27461788Simp
27582378Sjon		if (state == DS_ATTACHED || state == DS_BUSY)
27682378Sjon			device_detach(pf->dev);
27786907Simp		if (pf->cfe != NULL)
27886907Simp			pccard_function_disable(pf);
27982378Sjon		pccard_function_free(pf);
28076424Simp		if (pf->dev != NULL)
28164927Simp			device_delete_child(dev, pf->dev);
28252506Simp	}
28382378Sjon	if (sc->sc_enabled_count == 0)
28482378Sjon		POWER_DISABLE_SOCKET(device_get_parent(dev), dev);
28582378Sjon
28682378Sjon	while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) {
28782378Sjon		while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) {
28882378Sjon			STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list);
28982378Sjon			free(cfe, M_DEVBUF);
29082378Sjon		}
29182378Sjon		STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list);
29282378Sjon		free(pf, M_DEVBUF);
29382378Sjon	}
29474632Simp	return (0);
29552506Simp}
29652506Simp
29797613Stakawatastatic const struct pccard_product *
29897613Stakawatapccard_do_product_lookup(device_t bus, device_t dev,
29997613Stakawata			 const struct pccard_product *tab, size_t ent_size,
30097613Stakawata			 pccard_product_match_fn matchfn)
30166200Simp{
30266200Simp	const struct pccard_product *ent;
30366200Simp	int matches;
30466200Simp	u_int32_t fcn;
30566200Simp	u_int32_t vendor;
30666200Simp	u_int32_t prod;
30766200Simp	char *vendorstr;
30866200Simp	char *prodstr;
30966200Simp
31066200Simp#ifdef DIAGNOSTIC
31166200Simp	if (sizeof *ent > ent_size)
31270715Sjon		panic("pccard_product_lookup: bogus ent_size %ld",
31366200Simp		    (long) ent_size);
31466200Simp#endif
31566200Simp	if (pccard_get_vendor(dev, &vendor))
31666200Simp		return (NULL);
31766200Simp	if (pccard_get_product(dev, &prod))
31866200Simp		return (NULL);
31966200Simp	if (pccard_get_function_number(dev, &fcn))
32066200Simp		return (NULL);
32166200Simp	if (pccard_get_vendor_str(dev, &vendorstr))
32266200Simp		return (NULL);
32366200Simp	if (pccard_get_product_str(dev, &prodstr))
32466200Simp		return (NULL);
32582378Sjon	for (ent = tab; ent->pp_name != NULL; ent =
32682378Sjon	    (const struct pccard_product *) ((const char *) ent + ent_size)) {
32766200Simp		matches = 1;
32886642Simp		if (ent->pp_vendor == PCCARD_VENDOR_ANY &&
32986642Simp		    ent->pp_product == PCCARD_VENDOR_ANY &&
33086642Simp		    ent->pp_cis[0] == NULL &&
33186642Simp		    ent->pp_cis[1] == NULL) {
33286642Simp			device_printf(dev,
33386642Simp			    "Total wildcard entry ignored for %s\n",
33486642Simp			    ent->pp_name);
33586642Simp			continue;
33686642Simp		}
33766200Simp		if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY &&
33866200Simp		    vendor != ent->pp_vendor)
33966200Simp			matches = 0;
34066200Simp		if (matches && ent->pp_product != PCCARD_PRODUCT_ANY &&
34166200Simp		    prod != ent->pp_product)
34266200Simp			matches = 0;
34366200Simp		if (matches && fcn != ent->pp_expfunc)
34466200Simp			matches = 0;
34571322Simp		if (matches && ent->pp_cis[0] &&
34671322Simp		    strcmp(ent->pp_cis[0], vendorstr) != 0)
34766200Simp			matches = 0;
34871322Simp		if (matches && ent->pp_cis[1] &&
34971322Simp		    strcmp(ent->pp_cis[1], prodstr) != 0)
35066200Simp			matches = 0;
35171322Simp		/* XXX need to match cis[2] and cis[3] also XXX */
35266200Simp		if (matchfn != NULL)
35366200Simp			matches = (*matchfn)(dev, ent, matches);
35466200Simp		if (matches)
35566200Simp			return (ent);
35666200Simp	}
35766200Simp	return (NULL);
35866200Simp}
35966200Simp
36070715Sjonstatic int
36159193Simppccard_card_gettype(device_t dev, int *type)
36252506Simp{
36364850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
36452506Simp	struct pccard_function *pf;
36552506Simp
36652506Simp	/*
36752506Simp	 * set the iftype to memory if this card has no functions (not yet
36852506Simp	 * probed), or only one function, and that is not initialized yet or
36952506Simp	 * that is memory.
37052506Simp	 */
37152506Simp	pf = STAILQ_FIRST(&sc->card.pf_head);
37252506Simp	if (pf == NULL ||
37352506Simp	    (STAILQ_NEXT(pf, pf_list) == NULL &&
37452506Simp	    (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY)))
37559193Simp		*type = PCCARD_IFTYPE_MEMORY;
37652506Simp	else
37759193Simp		*type = PCCARD_IFTYPE_IO;
37874632Simp	return (0);
37952506Simp}
38052506Simp
38152506Simp/*
38252506Simp * Initialize a PCCARD function.  May be called as long as the function is
38352506Simp * disabled.
38482382Simp *
38582382Simp * Note: pccard_function_init should not keep resources allocated.  It should
38682382Simp * only set them up ala isa pnp, set the values in the rl lists, and return.
38782382Simp * Any resource held after pccard_function_init is called is a bug.  However,
38882382Simp * the bus routines to get the resources also assume that pccard_function_init
38982382Simp * does this, so they need to be fixed too.
39052506Simp */
39182378Sjonstatic void
39270715Sjonpccard_function_init(struct pccard_function *pf)
39352506Simp{
39465917Simp	struct pccard_config_entry *cfe;
39567187Simp	int i;
39667242Simp	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
39767242Simp	struct resource_list *rl = &devi->resources;
39870762Simp	struct resource_list_entry *rle;
39967242Simp	struct resource *r = 0;
40067242Simp	device_t bus;
40167424Simp	int start;
40267424Simp	int end;
40390897Simp	int spaces;
40465917Simp
40570715Sjon	if (pf->pf_flags & PFF_ENABLED) {
40670715Sjon		printf("pccard_function_init: function is enabled");
40770715Sjon		return;
40870715Sjon	}
40967242Simp	bus = device_get_parent(pf->dev);
41052506Simp	/* Remember which configuration entry we are using. */
41172012Sphk	STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
41267187Simp		for (i = 0; i < cfe->num_iospace; i++)
41367187Simp			cfe->iores[i] = NULL;
41467187Simp		cfe->irqres = NULL;
41590897Simp		spaces = 0;
41667187Simp		for (i = 0; i < cfe->num_iospace; i++) {
41767424Simp			start = cfe->iospace[i].start;
41867424Simp			if (start)
41967424Simp				end = start + cfe->iospace[i].length - 1;
42067424Simp			else
42167424Simp				end = ~0;
42267187Simp			cfe->iorid[i] = i;
42390897Simp			DEVPRINTF((bus, "I/O rid %d start %x end %x\n",
42490897Simp			    i, start, end));
42567242Simp			r = cfe->iores[i] = bus_alloc_resource(bus,
42667424Simp			    SYS_RES_IOPORT, &cfe->iorid[i], start, end,
42770715Sjon			    cfe->iospace[i].length,
42867424Simp			    rman_make_alignment_flags(cfe->iospace[i].length));
42976424Simp			if (cfe->iores[i] == NULL)
43067187Simp				goto not_this_one;
43167242Simp			resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i],
43267242Simp			    rman_get_start(r), rman_get_end(r),
43367242Simp			    cfe->iospace[i].length);
43476424Simp			rle = resource_list_find(rl, SYS_RES_IOPORT,
43576424Simp			    cfe->iorid[i]);
43676424Simp			rle->res = r;
43790897Simp			spaces++;
43867187Simp		}
43967187Simp		if (cfe->num_memspace > 0) {
44082781Sshiba			/*
44182781Sshiba			 * Not implement yet, Fix me.
44282781Sshiba			 */
44390897Simp			DEVPRINTF((bus, "Memory space not yet implemented.\n"));
44467187Simp		}
44590897Simp		if (spaces == 0) {
44690897Simp			DEVPRINTF((bus, "Neither memory nor I/O mampped\n"));
44790897Simp			goto not_this_one;
44890897Simp		}
44967187Simp		if (cfe->irqmask) {
45067187Simp			cfe->irqrid = 0;
45167399Simp			r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ,
45267424Simp			    &cfe->irqrid, 0, ~0, 1, 0);
45376424Simp			if (cfe->irqres == NULL)
45467187Simp				goto not_this_one;
45567242Simp			resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid,
45667242Simp			    rman_get_start(r), rman_get_end(r), 1);
45776424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
45876424Simp			    cfe->irqrid);
45976424Simp			rle->res = r;
46067187Simp		}
46167187Simp		/* If we get to here, we've allocated all we need */
46267167Simp		pf->cfe = cfe;
46367187Simp		break;
46467187Simp	    not_this_one:;
46567424Simp		DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n",
46667424Simp		    cfe->number));
46767333Simp		/*
46867333Simp		 * Release resources that we partially allocated
46967333Simp		 * from this config entry.
47067333Simp		 */
47167187Simp		for (i = 0; i < cfe->num_iospace; i++) {
47276424Simp			if (cfe->iores[i] != NULL) {
47370715Sjon				bus_release_resource(bus, SYS_RES_IOPORT,
47467187Simp				    cfe->iorid[i], cfe->iores[i]);
47582378Sjon				rle = resource_list_find(rl, SYS_RES_IOPORT,
47676424Simp				    cfe->iorid[i]);
47776424Simp				rle->res = NULL;
47876424Simp				resource_list_delete(rl, SYS_RES_IOPORT,
47976424Simp				    cfe->iorid[i]);
48075756Simp			}
48167187Simp			cfe->iores[i] = NULL;
48267187Simp		}
48376424Simp		if (cfe->irqmask && cfe->irqres != NULL) {
48467242Simp			bus_release_resource(bus, SYS_RES_IRQ,
48567187Simp			    cfe->irqrid, cfe->irqres);
48676424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
48776424Simp			    cfe->irqrid);
48876424Simp			rle->res = NULL;
48976424Simp			resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid);
49067187Simp			cfe->irqres = NULL;
49167187Simp		}
49267167Simp	}
49352506Simp}
49452506Simp
49582378Sjon/*
49682378Sjon * Free resources allocated by pccard_function_init(), May be called as long
49782378Sjon * as the function is disabled.
49882382Simp *
49982382Simp * NOTE: This function should be unnecessary.  pccard_function_init should
50082382Simp * never keep resources initialized.
50182378Sjon */
50282378Sjonstatic void
50382378Sjonpccard_function_free(struct pccard_function *pf)
50482378Sjon{
50582378Sjon	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
50682378Sjon	struct resource_list_entry *rle;
50782378Sjon
50882378Sjon	if (pf->pf_flags & PFF_ENABLED) {
50982378Sjon		printf("pccard_function_init: function is enabled");
51082378Sjon		return;
51182378Sjon	}
51282378Sjon
51382378Sjon	SLIST_FOREACH(rle, &devi->resources, link) {
51482378Sjon		if (rle->res) {
51582378Sjon			if (rle->res->r_dev != pf->sc->dev)
51682378Sjon				device_printf(pf->sc->dev,
51782378Sjon				    "function_free: Resource still owned by "
51882378Sjon				    "child, oops. "
51982378Sjon				    "(type=%d, rid=%d, addr=%lx)\n",
52082378Sjon				    rle->type, rle->rid,
52182378Sjon				    rman_get_start(rle->res));
52282378Sjon			BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
52382378Sjon			    rle->res->r_dev, rle->type, rle->rid, rle->res);
52482378Sjon			rle->res = NULL;
52582378Sjon		}
52682378Sjon	}
52782378Sjon	resource_list_free(&devi->resources);
52882378Sjon}
52982378Sjon
53052506Simp/* Enable a PCCARD function */
53182378Sjonstatic int
53255720Simppccard_function_enable(struct pccard_function *pf)
53352506Simp{
53452506Simp	struct pccard_function *tmp;
53552506Simp	int reg;
53655720Simp	device_t dev = pf->sc->dev;
53770746Simp
53867333Simp	if (pf->cfe == NULL) {
53967333Simp		DEVPRVERBOSE((dev, "No config entry could be allocated.\n"));
54074632Simp		return (ENOMEM);
54167333Simp	}
54252506Simp
54352506Simp	/*
54452506Simp	 * Increase the reference count on the socket, enabling power, if
54552506Simp	 * necessary.
54652506Simp	 */
54782378Sjon	pf->sc->sc_enabled_count++;
54852506Simp
54952506Simp	if (pf->pf_flags & PFF_ENABLED) {
55052506Simp		/*
55152506Simp		 * Don't do anything if we're already enabled.
55252506Simp		 */
55352506Simp		return (0);
55452506Simp	}
55552506Simp
55652506Simp	/*
55752506Simp	 * it's possible for different functions' CCRs to be in the same
55852506Simp	 * underlying page.  Check for that.
55952506Simp	 */
56052506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
56152506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
56252506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
56352506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
56482378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
56582378Sjon		    tmp->pf_ccr_realsize))) {
56652506Simp			pf->pf_ccrt = tmp->pf_ccrt;
56752506Simp			pf->pf_ccrh = tmp->pf_ccrh;
56852506Simp			pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
56952506Simp
57052506Simp			/*
57152506Simp			 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
57252506Simp			 * tmp->ccr_base) + pf->ccr_base;
57352506Simp			 */
57470715Sjon			/* pf->pf_ccr_offset =
57552506Simp			    (tmp->pf_ccr_offset + pf->ccr_base) -
57670715Sjon			    tmp->ccr_base; */
57752506Simp			pf->pf_ccr_window = tmp->pf_ccr_window;
57852506Simp			break;
57952506Simp		}
58052506Simp	}
58152506Simp	if (tmp == NULL) {
58255720Simp		pf->ccr_rid = 0;
58355720Simp		pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
58470715Sjon		    &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE);
58570715Sjon		if (!pf->ccr_res)
58652506Simp			goto bad;
58770746Simp		DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%lx\n",
58870746Simp		    rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res),
58970746Simp		    pf->ccr_base));
59061788Simp		CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
59161788Simp		    pf->ccr_rid, PCCARD_A_MEM_ATTR);
59270715Sjon		CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev,
59370748Simp		    pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset);
59455720Simp		pf->pf_ccrt = rman_get_bustag(pf->ccr_res);
59555720Simp		pf->pf_ccrh = rman_get_bushandle(pf->ccr_res);
59655720Simp		pf->pf_ccr_realsize = 1;
59752506Simp	}
59852506Simp
59952506Simp	reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX);
60052506Simp	reg |= PCCARD_CCR_OPTION_LEVIREQ;
60152506Simp	if (pccard_mfc(pf->sc)) {
60252506Simp		reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE |
60352506Simp			PCCARD_CCR_OPTION_ADDR_DECODE);
60482383Simp		/* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */
60552506Simp	}
60652506Simp	pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
60752506Simp
60852506Simp	reg = 0;
60952506Simp	if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0)
61052506Simp		reg |= PCCARD_CCR_STATUS_IOIS8;
61152506Simp	if (pf->cfe->flags & PCCARD_CFE_AUDIO)
61252506Simp		reg |= PCCARD_CCR_STATUS_AUDIO;
61352506Simp	pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg);
61452506Simp
61552506Simp	pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0);
61652506Simp
61752506Simp	if (pccard_mfc(pf->sc)) {
61852506Simp		long tmp, iosize;
61952506Simp
62052506Simp		tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
62152506Simp		/* round up to nearest (2^n)-1 */
62252506Simp		for (iosize = 1; iosize < tmp; iosize <<= 1)
62352506Simp			;
62452506Simp		iosize--;
62552506Simp
62652506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
62752506Simp				 pf->pf_mfc_iobase & 0xff);
62852506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
62952506Simp				 (pf->pf_mfc_iobase >> 8) & 0xff);
63052506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
63152506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
63252506Simp
63352506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
63452506Simp	}
63552506Simp
63652506Simp#ifdef PCCARDDEBUG
63752506Simp	if (pccard_debug) {
63852506Simp		STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
63970715Sjon			device_printf(tmp->sc->dev,
64055500Simp			    "function %d CCR at %d offset %x: "
64155500Simp			    "%x %x %x %x, %x %x %x %x, %x\n",
64270715Sjon			    tmp->number, tmp->pf_ccr_window,
64355500Simp			    tmp->pf_ccr_offset,
64455500Simp			    pccard_ccr_read(tmp, 0x00),
64555500Simp			    pccard_ccr_read(tmp, 0x02),
64655500Simp			    pccard_ccr_read(tmp, 0x04),
64755500Simp			    pccard_ccr_read(tmp, 0x06),
64855500Simp			    pccard_ccr_read(tmp, 0x0A),
64970715Sjon			    pccard_ccr_read(tmp, 0x0C),
65055500Simp			    pccard_ccr_read(tmp, 0x0E),
65155500Simp			    pccard_ccr_read(tmp, 0x10),
65255500Simp			    pccard_ccr_read(tmp, 0x12));
65352506Simp		}
65452506Simp	}
65552506Simp#endif
65652506Simp	pf->pf_flags |= PFF_ENABLED;
65752506Simp	return (0);
65852506Simp
65952506Simp bad:
66052506Simp	/*
66152506Simp	 * Decrement the reference count, and power down the socket, if
66252506Simp	 * necessary.
66352506Simp	 */
66482378Sjon	pf->sc->sc_enabled_count--;
66565098Simp	DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count));
66652506Simp
66752506Simp	return (1);
66852506Simp}
66952506Simp
67052506Simp/* Disable PCCARD function. */
67182378Sjonstatic void
67255720Simppccard_function_disable(struct pccard_function *pf)
67352506Simp{
67452506Simp	struct pccard_function *tmp;
67555720Simp	device_t dev = pf->sc->dev;
67652506Simp
67752506Simp	if (pf->cfe == NULL)
67861788Simp		panic("pccard_function_disable: function not initialized");
67952506Simp
68052506Simp	if ((pf->pf_flags & PFF_ENABLED) == 0) {
68152506Simp		/*
68252506Simp		 * Don't do anything if we're already disabled.
68352506Simp		 */
68452506Simp		return;
68552506Simp	}
68652506Simp
68770715Sjon	if (pf->intr_handler != NULL) {
68882378Sjon		struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
68982378Sjon		struct resource_list_entry *rle =
69082378Sjon		    resource_list_find(&devi->resources, SYS_RES_IRQ, 0);
69182378Sjon		BUS_TEARDOWN_INTR(dev, pf->dev, rle->res,
69282378Sjon		    pf->intr_handler_cookie);
69370715Sjon	}
69470715Sjon
69552506Simp	/*
69652506Simp	 * it's possible for different functions' CCRs to be in the same
69752506Simp	 * underlying page.  Check for that.  Note we mark us as disabled
69852506Simp	 * first to avoid matching ourself.
69952506Simp	 */
70052506Simp
70152506Simp	pf->pf_flags &= ~PFF_ENABLED;
70252506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
70352506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
70452506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
70552506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
70682378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
70782378Sjon		    tmp->pf_ccr_realsize)))
70852506Simp			break;
70952506Simp	}
71052506Simp
71152506Simp	/* Not used by anyone else; unmap the CCR. */
71252506Simp	if (tmp == NULL) {
71370715Sjon		bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid,
71455720Simp		    pf->ccr_res);
71555720Simp		pf->ccr_res = NULL;
71652506Simp	}
71752506Simp
71852506Simp	/*
71952506Simp	 * Decrement the reference count, and power down the socket, if
72052506Simp	 * necessary.
72152506Simp	 */
72282378Sjon	pf->sc->sc_enabled_count--;
72352506Simp}
72452506Simp
72566058Simp/*
72666058Simp * simulate the old "probe" routine.  In the new world order, the driver
72766058Simp * needs to grab devices while in the old they were assigned to the device by
72866058Simp * the pccardd process.  These symbols are exported to the upper layers.
72966058Simp */
73074636Simpstatic int
73174636Simppccard_compat_do_probe(device_t bus, device_t dev)
73266058Simp{
73366058Simp	return (CARD_COMPAT_MATCH(dev));
73466058Simp}
73566058Simp
73674636Simpstatic int
73774636Simppccard_compat_do_attach(device_t bus, device_t dev)
73866058Simp{
73966058Simp	int err;
74066058Simp
74166058Simp	err = CARD_COMPAT_PROBE(dev);
74266058Simp	if (err == 0)
74366058Simp		err = CARD_COMPAT_ATTACH(dev);
74466058Simp	return (err);
74566058Simp}
74666058Simp
74753873Simp#define PCCARD_NPORT	2
74853873Simp#define PCCARD_NMEM	5
74953873Simp#define PCCARD_NIRQ	1
75053873Simp#define PCCARD_NDRQ	0
75153873Simp
75252506Simpstatic int
75352506Simppccard_add_children(device_t dev, int busno)
75452506Simp{
75559193Simp	/* Call parent to scan for any current children */
75674632Simp	return (0);
75752506Simp}
75852506Simp
75952506Simpstatic int
76052506Simppccard_probe(device_t dev)
76152506Simp{
76267333Simp	device_set_desc(dev, "16-bit PCCard bus");
76374632Simp	return (pccard_add_children(dev, device_get_unit(dev)));
76452506Simp}
76552506Simp
76659193Simpstatic int
76759193Simppccard_attach(device_t dev)
76859193Simp{
76964850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
77061788Simp
77159193Simp	sc->dev = dev;
77261788Simp	sc->sc_enabled_count = 0;
77374632Simp	return (bus_generic_attach(dev));
77459193Simp}
77559193Simp
77682378Sjonstatic int
77782378Sjonpccard_detach(device_t dev)
77882378Sjon{
77982378Sjon	pccard_detach_card(dev, 0);
78082378Sjon	return 0;
78182378Sjon}
78282378Sjon
78387975Simpstatic int
78487975Simppccard_suspend(device_t self)
78587975Simp{
78687975Simp	pccard_detach_card(self, 0);
78787975Simp	return (0);
78887975Simp}
78987975Simp
79087975Simpstatic
79187975Simpint
79287975Simppccard_resume(device_t self)
79387975Simp{
79487975Simp	return (0);
79587975Simp}
79687975Simp
79753873Simpstatic void
79853873Simppccard_print_resources(struct resource_list *rl, const char *name, int type,
79953873Simp    int count, const char *format)
80053873Simp{
80153873Simp	struct resource_list_entry *rle;
80253873Simp	int printed;
80353873Simp	int i;
80453873Simp
80553873Simp	printed = 0;
80653873Simp	for (i = 0; i < count; i++) {
80753873Simp		rle = resource_list_find(rl, type, i);
80876424Simp		if (rle != NULL) {
80953873Simp			if (printed == 0)
81053873Simp				printf(" %s ", name);
81153873Simp			else if (printed > 0)
81253873Simp				printf(",");
81353873Simp			printed++;
81453873Simp			printf(format, rle->start);
81553873Simp			if (rle->count > 1) {
81653873Simp				printf("-");
81753873Simp				printf(format, rle->start + rle->count - 1);
81853873Simp			}
81953873Simp		} else if (i > 3) {
82053873Simp			/* check the first few regardless */
82153873Simp			break;
82253873Simp		}
82353873Simp	}
82453873Simp}
82553873Simp
82653873Simpstatic int
82753873Simppccard_print_child(device_t dev, device_t child)
82853873Simp{
82966847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
83053873Simp	struct resource_list *rl = &devi->resources;
83153873Simp	int retval = 0;
83253873Simp
83353873Simp	retval += bus_print_child_header(dev, child);
83453873Simp	retval += printf(" at");
83553873Simp
83676424Simp	if (devi != NULL) {
83753873Simp		pccard_print_resources(rl, "port", SYS_RES_IOPORT,
83853873Simp		    PCCARD_NPORT, "%#lx");
83953873Simp		pccard_print_resources(rl, "iomem", SYS_RES_MEMORY,
84053873Simp		    PCCARD_NMEM, "%#lx");
84153873Simp		pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ,
84253873Simp		    "%ld");
84370715Sjon		pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ,
84453873Simp		    "%ld");
84567269Simp		retval += printf(" function %d config %d", devi->fcn->number,
84667269Simp		    devi->fcn->cfe->number);
84753873Simp	}
84853873Simp
84953873Simp	retval += bus_print_child_footer(dev, child);
85053873Simp
85153873Simp	return (retval);
85253873Simp}
85353873Simp
85453873Simpstatic int
85553873Simppccard_set_resource(device_t dev, device_t child, int type, int rid,
85653873Simp		 u_long start, u_long count)
85753873Simp{
85866847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
85953873Simp	struct resource_list *rl = &devi->resources;
86053873Simp
86153873Simp	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
86253873Simp	    && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
86374632Simp		return (EINVAL);
86453873Simp	if (rid < 0)
86574632Simp		return (EINVAL);
86653873Simp	if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT)
86774632Simp		return (EINVAL);
86853873Simp	if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM)
86974632Simp		return (EINVAL);
87053873Simp	if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ)
87174632Simp		return (EINVAL);
87253873Simp	if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ)
87374632Simp		return (EINVAL);
87453873Simp
87553873Simp	resource_list_add(rl, type, rid, start, start + count - 1, count);
87682378Sjon	if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev,
87782378Sjon	    type, &rid, start, start + count - 1, count, 0))
87882378Sjon		return 0;
87982378Sjon	else
88082378Sjon		return ENOMEM;
88153873Simp}
88253873Simp
88353873Simpstatic int
88453873Simppccard_get_resource(device_t dev, device_t child, int type, int rid,
88553873Simp    u_long *startp, u_long *countp)
88653873Simp{
88766847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
88853873Simp	struct resource_list *rl = &devi->resources;
88953873Simp	struct resource_list_entry *rle;
89053873Simp
89153873Simp	rle = resource_list_find(rl, type, rid);
89276424Simp	if (rle == NULL)
89374632Simp		return (ENOENT);
89470715Sjon
89576424Simp	if (startp != NULL)
89653873Simp		*startp = rle->start;
89776424Simp	if (countp != NULL)
89853873Simp		*countp = rle->count;
89953873Simp
90074632Simp	return (0);
90153873Simp}
90253873Simp
90353873Simpstatic void
90453873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid)
90553873Simp{
90666847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
90753873Simp	struct resource_list *rl = &devi->resources;
90853873Simp	resource_list_delete(rl, type, rid);
90953873Simp}
91053873Simp
91159193Simpstatic int
91259193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid,
91359193Simp    u_int32_t flags)
91459193Simp{
91574632Simp	return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type,
91674632Simp	    rid, flags));
91759193Simp}
91859193Simp
91959193Simpstatic int
92059193Simppccard_set_memory_offset(device_t dev, device_t child, int rid,
92182378Sjon    u_int32_t offset, u_int32_t *deltap)
92270715Sjon
92359193Simp{
92474632Simp	return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid,
92574632Simp	    offset, deltap));
92659193Simp}
92759193Simp
928104641Simpstatic void
929104641Simppccard_probe_nomatch(device_t bus, device_t child)
930104641Simp{
931104641Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
932104641Simp	struct pccard_function *func = devi->fcn;
933104641Simp	struct pccard_softc *sc = PCCARD_SOFTC(bus);
934104641Simp
935104641Simp	device_printf(bus, "<unknown card>");
936104641Simp	printf(" (manufacturer=0x%04x, product=0x%04x) at function %d\n",
937104641Simp	  sc->card.manufacturer, sc->card.product, func->number);
938104641Simp	device_printf(bus, "   CIS info: %s, %s, %s\n", sc->card.cis1_info[0],
939104641Simp	  sc->card.cis1_info[1], sc->card.cis1_info[2]);
940104641Simp	return;
941104641Simp}
942104641Simp
94366058Simpstatic int
944104641Simppccard_child_location_str(device_t bus, device_t child, char *buf,
945104641Simp    size_t buflen)
946104641Simp{
947104641Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
948104641Simp	struct pccard_function *func = devi->fcn;
949104641Simp
950104641Simp	snprintf(buf, buflen, "function=%d", func->number);
951104641Simp	return (0);
952104641Simp}
953104641Simp
954104641Simpstatic int
955104641Simppccard_child_pnpinfo_str(device_t bus, device_t child, char *buf,
956104641Simp    size_t buflen)
957104641Simp{
958104641Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
959104641Simp	struct pccard_function *func = devi->fcn;
960104641Simp	struct pccard_softc *sc = PCCARD_SOFTC(bus);
961104641Simp
962104641Simp	snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x "
963104641Simp	    "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d",
964104641Simp	    sc->card.manufacturer, sc->card.product, sc->card.cis1_info[0],
965104641Simp	    sc->card.cis1_info[1], func->function);
966104641Simp	return (0);
967104641Simp}
968104641Simp
969104641Simpstatic int
97066058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result)
97166058Simp{
97266847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
97366779Simp	struct pccard_function *func = devi->fcn;
97466779Simp	struct pccard_softc *sc = PCCARD_SOFTC(bus);
97566779Simp
97666779Simp	switch (which) {
97766779Simp	default:
97866779Simp	case PCCARD_IVAR_ETHADDR:
97982781Sshiba		bcopy(func->pf_funce_lan_nid, result, ETHER_ADDR_LEN);
98066779Simp		break;
98166779Simp	case PCCARD_IVAR_VENDOR:
98266779Simp		*(u_int32_t *) result = sc->card.manufacturer;
98366779Simp		break;
98466779Simp	case PCCARD_IVAR_PRODUCT:
98566779Simp		*(u_int32_t *) result = sc->card.product;
98666779Simp		break;
98790964Sshiba	case PCCARD_IVAR_PRODEXT:
98890964Sshiba		*(u_int16_t *) result = sc->card.prodext;
98990964Sshiba		break;
99075761Simp	case PCCARD_IVAR_FUNCTION:
99175761Simp		*(u_int32_t *) result = func->function;
99275761Simp		break;
99366779Simp	case PCCARD_IVAR_FUNCTION_NUMBER:
99466847Simp		if (!func) {
99566847Simp			device_printf(bus, "No function number, bug!\n");
99666847Simp			return (ENOENT);
99766847Simp		}
99866847Simp		*(u_int32_t *) result = func->number;
99966779Simp		break;
100066779Simp	case PCCARD_IVAR_VENDOR_STR:
100166779Simp		*(char **) result = sc->card.cis1_info[0];
100266779Simp		break;
100366779Simp	case PCCARD_IVAR_PRODUCT_STR:
100466779Simp		*(char **) result = sc->card.cis1_info[1];
100566779Simp		break;
100666779Simp	case PCCARD_IVAR_CIS3_STR:
100766779Simp		*(char **) result = sc->card.cis1_info[2];
100866779Simp		break;
100967167Simp	case PCCARD_IVAR_CIS4_STR:
1010104610Simp		*(char **) result = sc->card.cis1_info[3];
101167167Simp		break;
101266779Simp	}
101366779Simp	return (0);
101466058Simp}
101566058Simp
101666779Simpstatic void
101766779Simppccard_driver_added(device_t dev, driver_t *driver)
101866779Simp{
101982378Sjon	struct pccard_softc *sc = PCCARD_SOFTC(dev);
102082378Sjon	struct pccard_function *pf;
102182378Sjon	device_t child;
102282378Sjon
102382378Sjon	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
102482378Sjon		if (STAILQ_EMPTY(&pf->cfe_head))
102582378Sjon			continue;
102682378Sjon		child = pf->dev;
102782378Sjon		if (device_get_state(child) != DS_NOTPRESENT)
102882378Sjon			continue;
102982378Sjon		if (pccard_function_enable(pf) == 0 &&
103082378Sjon		    device_probe_and_attach(child) == 0) {
103182378Sjon			DEVPRINTF((sc->dev, "function %d CCR at %d "
103282378Sjon			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
103382378Sjon			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
103482378Sjon			    pccard_ccr_read(pf, 0x00),
103582378Sjon			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
103682378Sjon			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
103782378Sjon			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
103882378Sjon			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
103982378Sjon		} else {
104086907Simp			if (pf->cfe != NULL)
104186907Simp				pccard_function_disable(pf);
104282378Sjon		}
104382378Sjon	}
104482378Sjon	return;
104566779Simp}
104666058Simp
104767242Simpstatic struct resource *
104867242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid,
104967242Simp    u_long start, u_long end, u_long count, u_int flags)
105067242Simp{
105182378Sjon	struct pccard_ivar *dinfo;
105282378Sjon	struct resource_list_entry *rle = 0;
105382378Sjon	int passthrough = (device_get_parent(child) != dev);
1054104641Simp	struct resource *r = NULL;
105567242Simp
105682378Sjon	if (passthrough) {
105782378Sjon		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
105882378Sjon		    type, rid, start, end, count, flags));
105982378Sjon	}
106070715Sjon
106182378Sjon	dinfo = device_get_ivars(child);
106282378Sjon	rle = resource_list_find(&dinfo->resources, type, *rid);
106370715Sjon
1064104641Simp	if (rle == NULL)
1065104641Simp		return (NULL);		/* no resource of that type/rid */
106670715Sjon
1067104641Simp	if (rle->res == NULL) {
106882378Sjon		switch(type) {
106982378Sjon		case SYS_RES_IOPORT:
1070104641Simp			r = bus_alloc_resource(dev, type, rid, start, end,
1071104641Simp			    count, rman_make_alignment_flags(count));
1072104641Simp			if (r == NULL)
1073104641Simp				goto bad;
1074104641Simp			resource_list_add(&dinfo->resources, type, *rid,
1075104641Simp			    rman_get_start(r), rman_get_end(r), count);
1076104641Simp			rle = resource_list_find(&dinfo->resources, type, *rid);
1077104641Simp			if (!rle)
1078104641Simp				goto bad;
1079104641Simp			rle->res = r;
1080104641Simp			break;
108182378Sjon		case SYS_RES_MEMORY:
108282378Sjon			break;
108382378Sjon		case SYS_RES_IRQ:
108482378Sjon			break;
108582378Sjon		}
108690897Simp		return (rle->res);
108767269Simp	}
1088104641Simp	if (rle->res->r_dev != dev)
1089104641Simp		return (NULL);
1090104641Simp	bus_release_resource(dev, type, *rid, rle->res);
1091104641Simp	rle->res = NULL;
1092104641Simp	switch(type) {
1093104641Simp	case SYS_RES_IOPORT:
1094104641Simp	case SYS_RES_MEMORY:
1095104641Simp		if (!(flags & RF_ALIGNMENT_MASK))
1096104641Simp			flags |= rman_make_alignment_flags(rle->count);
1097104641Simp		break;
1098104641Simp	case SYS_RES_IRQ:
1099104641Simp		flags |= RF_SHAREABLE;
1100104641Simp		break;
1101104641Simp	}
1102104641Simp	rle->res = resource_list_alloc(&dinfo->resources, dev, child,
1103104641Simp	    type, rid, rle->start, rle->end, rle->count, flags);
1104104641Simp	return (rle->res);
1105104641Simpbad:;
1106104641Simp	device_printf(dev, "WARNING: Resource not reserved by pccard\n");
1107104641Simp	return (NULL);
110867242Simp}
110967242Simp
111067242Simpstatic int
111167242Simppccard_release_resource(device_t dev, device_t child, int type, int rid,
111267242Simp    struct resource *r)
111367242Simp{
111482378Sjon	struct pccard_ivar *dinfo;
111582378Sjon	int passthrough = (device_get_parent(child) != dev);
111682378Sjon	struct resource_list_entry *rle = 0;
111782378Sjon	int ret;
111882378Sjon	int flags;
111970715Sjon
112082378Sjon	if (passthrough)
112182378Sjon		return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
112282378Sjon		    type, rid, r);
112370715Sjon
112482378Sjon	dinfo = device_get_ivars(child);
112570715Sjon
112682378Sjon	rle = resource_list_find(&dinfo->resources, type, rid);
112770715Sjon
112882378Sjon	if (!rle) {
112982378Sjon		device_printf(dev, "Allocated resource not found, "
113082378Sjon		    "%d %x %lx %lx\n",
113182378Sjon		    type, rid, rman_get_start(r), rman_get_size(r));
113282378Sjon		return ENOENT;
113370715Sjon	}
113482378Sjon	if (!rle->res) {
113582378Sjon		device_printf(dev, "Allocated resource not recorded\n");
113682378Sjon		return ENOENT;
113770715Sjon	}
113870715Sjon
113982378Sjon	ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
114082378Sjon	    type, rid, r);
114182378Sjon	switch(type) {
114282378Sjon	case SYS_RES_IOPORT:
114382378Sjon	case SYS_RES_MEMORY:
114482378Sjon		flags = rman_make_alignment_flags(rle->count);
114582378Sjon		break;
114682378Sjon	case SYS_RES_IRQ:
114782378Sjon		flags = RF_SHAREABLE;
114882378Sjon		break;
114982378Sjon	default:
115082378Sjon		flags = 0;
115170715Sjon	}
115282378Sjon	rle->res = bus_alloc_resource(dev, type, &rid,
115382378Sjon	    rle->start, rle->end, rle->count, flags);
115482378Sjon	if (rle->res == NULL)
115582378Sjon		device_printf(dev, "release_resource: "
115682378Sjon		    "unable to reaquire resource\n");
115782378Sjon	return ret;
115867242Simp}
115967242Simp
116067333Simpstatic void
116167333Simppccard_child_detached(device_t parent, device_t dev)
116267333Simp{
116367333Simp	struct pccard_ivar *ivar = PCCARD_IVAR(dev);
116482378Sjon	struct pccard_function *pf = ivar->fcn;
116567333Simp
116682378Sjon	pccard_function_disable(pf);
116767333Simp}
116867333Simp
116970715Sjonstatic void
117070762Simppccard_intr(void *arg)
117170762Simp{
117282378Sjon	struct pccard_function *pf = (struct pccard_function*) arg;
117382378Sjon	int reg;
1174102923Simp	int doisr = 1;
117582378Sjon
117682383Simp	/*
1177102923Simp	 * MFC cards know if they interrupted, so we have to ack the
1178102923Simp	 * interrupt and call the ISR.  Non-MFC cards don't have these
1179102923Simp	 * bits, so they always get called.  Many non-MFC cards have
1180102923Simp	 * this bit set always upon read, but some do not.
1181102923Simp	 *
1182102923Simp	 * We always ack the interrupt, even if there's no ISR
1183102923Simp	 * for the card.  This is done on the theory that acking
1184102923Simp	 * the interrupt will pacify the card enough to keep an
1185102923Simp	 * interrupt storm from happening.  Of course this won't
1186102923Simp	 * help in the non-MFC case.
118782383Simp	 */
1188102923Simp	if (pccard_mfc(pf->sc)) {
1189102923Simp		reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
1190102923Simp		if (reg & PCCARD_CCR_STATUS_INTR)
1191102923Simp			pccard_ccr_write(pf, PCCARD_CCR_STATUS,
1192102923Simp			    reg & ~PCCARD_CCR_STATUS_INTR);
1193102923Simp		else
1194102923Simp			doisr = 0;
1195102923Simp	}
1196102923Simp	if (pf->intr_handler != NULL && doisr)
119782378Sjon		pf->intr_handler(pf->intr_handler_arg);
119870715Sjon}
119970715Sjon
120070715Sjonstatic int
120170762Simppccard_setup_intr(device_t dev, device_t child, struct resource *irq,
120270762Simp    int flags, driver_intr_t *intr, void *arg, void **cookiep)
120370715Sjon{
1204102713Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
120570715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
120670715Sjon	struct pccard_function *func = ivar->fcn;
120790445Simp	int err;
120870715Sjon
120970715Sjon	if (func->intr_handler != NULL)
1210101762Simp		panic("Only one interrupt handler per function allowed");
121190445Simp	err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr,
121290445Simp	    func, cookiep);
121390445Simp	if (err != 0)
121490445Simp		return (err);
121570715Sjon	func->intr_handler = intr;
121670715Sjon	func->intr_handler_arg = arg;
121782378Sjon	func->intr_handler_cookie = *cookiep;
1218102713Simp	if (pccard_mfc(sc)) {
1219102713Simp		pccard_ccr_write(func, PCCARD_CCR_OPTION,
1220102713Simp		    pccard_ccr_read(func, PCCARD_CCR_OPTION) |
1221102713Simp		    PCCARD_CCR_OPTION_IREQ_ENABLE);
1222102713Simp	}
122374632Simp	return (0);
122470715Sjon}
122570715Sjon
122670715Sjonstatic int
122770762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r,
122870762Simp    void *cookie)
122970715Sjon{
1230102713Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
123170715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
123270715Sjon	struct pccard_function *func = ivar->fcn;
123382378Sjon	int ret;
123470715Sjon
1235102713Simp	if (pccard_mfc(sc)) {
1236102713Simp		pccard_ccr_write(func, PCCARD_CCR_OPTION,
1237102713Simp		    pccard_ccr_read(func, PCCARD_CCR_OPTION) &
1238102713Simp		    ~PCCARD_CCR_OPTION_IREQ_ENABLE);
1239102713Simp	}
124090445Simp	ret = bus_generic_teardown_intr(dev, child, r, cookie);
124182378Sjon	if (ret == 0) {
124282378Sjon		func->intr_handler = NULL;
124382378Sjon		func->intr_handler_arg = NULL;
124482378Sjon		func->intr_handler_cookie = NULL;
124582378Sjon	}
124670715Sjon
124782378Sjon	return (ret);
124870715Sjon}
124970715Sjon
125052506Simpstatic device_method_t pccard_methods[] = {
125152506Simp	/* Device interface */
125252506Simp	DEVMETHOD(device_probe,		pccard_probe),
125359193Simp	DEVMETHOD(device_attach,	pccard_attach),
125482378Sjon	DEVMETHOD(device_detach,	pccard_detach),
125552506Simp	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
125687975Simp	DEVMETHOD(device_suspend,	pccard_suspend),
125787975Simp	DEVMETHOD(device_resume,	pccard_resume),
125852506Simp
125952506Simp	/* Bus interface */
126052506Simp	DEVMETHOD(bus_print_child,	pccard_print_child),
126166779Simp	DEVMETHOD(bus_driver_added,	pccard_driver_added),
126267333Simp	DEVMETHOD(bus_child_detached,	pccard_child_detached),
126367242Simp	DEVMETHOD(bus_alloc_resource,	pccard_alloc_resource),
126467242Simp	DEVMETHOD(bus_release_resource,	pccard_release_resource),
126582378Sjon	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
126682378Sjon	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
126770715Sjon	DEVMETHOD(bus_setup_intr,	pccard_setup_intr),
126870715Sjon	DEVMETHOD(bus_teardown_intr,	pccard_teardown_intr),
126952506Simp	DEVMETHOD(bus_set_resource,	pccard_set_resource),
127052506Simp	DEVMETHOD(bus_get_resource,	pccard_get_resource),
127152506Simp	DEVMETHOD(bus_delete_resource,	pccard_delete_resource),
1272104641Simp	DEVMETHOD(bus_probe_nomatch,	pccard_probe_nomatch),
127366058Simp	DEVMETHOD(bus_read_ivar,	pccard_read_ivar),
1274104641Simp	DEVMETHOD(bus_child_pnpinfo_str, pccard_child_pnpinfo_str),
1275104641Simp	DEVMETHOD(bus_child_location_str, pccard_child_location_str),
127652506Simp
127759193Simp	/* Card Interface */
127859193Simp	DEVMETHOD(card_set_res_flags,	pccard_set_res_flags),
127959193Simp	DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset),
128059193Simp	DEVMETHOD(card_get_type,	pccard_card_gettype),
128159193Simp	DEVMETHOD(card_attach_card,	pccard_attach_card),
128259193Simp	DEVMETHOD(card_detach_card,	pccard_detach_card),
128374636Simp	DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe),
128474636Simp	DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach),
128597613Stakawata	DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup),
128659193Simp
128752506Simp	{ 0, 0 }
128852506Simp};
128952506Simp
129052506Simpstatic driver_t pccard_driver = {
129152506Simp	"pccard",
129252506Simp	pccard_methods,
129364850Simp	sizeof(struct pccard_softc)
129452506Simp};
129552506Simp
129652506Simpdevclass_t	pccard_devclass;
129752506Simp
1298101905Simp/* Maybe we need to have a slot device? */
129953873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
130052506SimpDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0);
1301101905SimpDRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0);
130253873SimpDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0);
130364927SimpMODULE_VERSION(pccard, 1);
130470715Sjon/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/
1305