pccard.c revision 113078
166200Simp/*	$NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $	*/
252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard.c 113078 2003-04-04 14:40:01Z sanpei $ */
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);
86106362Simpstatic int	pccard_detach_card(device_t dev);
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,
227111119Simp		    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
262106362Simppccard_detach_card(device_t dev)
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);
280106896Simp		device_delete_child(dev, pf->dev);
28152506Simp	}
28282378Sjon	if (sc->sc_enabled_count == 0)
28382378Sjon		POWER_DISABLE_SOCKET(device_get_parent(dev), dev);
28482378Sjon
28582378Sjon	while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) {
28682378Sjon		while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) {
28782378Sjon			STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list);
28882378Sjon			free(cfe, M_DEVBUF);
28982378Sjon		}
29082378Sjon		STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list);
29182378Sjon		free(pf, M_DEVBUF);
29282378Sjon	}
29374632Simp	return (0);
29452506Simp}
29552506Simp
29697613Stakawatastatic const struct pccard_product *
29797613Stakawatapccard_do_product_lookup(device_t bus, device_t dev,
298112359Simp    const struct pccard_product *tab, size_t ent_size,
299112359Simp    pccard_product_match_fn matchfn)
30066200Simp{
30166200Simp	const struct pccard_product *ent;
30266200Simp	int matches;
30366200Simp	u_int32_t fcn;
30466200Simp	u_int32_t vendor;
30566200Simp	u_int32_t prod;
30666200Simp	char *vendorstr;
30766200Simp	char *prodstr;
30866200Simp
30966200Simp#ifdef DIAGNOSTIC
31066200Simp	if (sizeof *ent > ent_size)
311112359Simp		panic("pccard_product_lookup: bogus ent_size %jd",
312112359Simp		    (intmax_t) ent_size);
31366200Simp#endif
31466200Simp	if (pccard_get_vendor(dev, &vendor))
31566200Simp		return (NULL);
31666200Simp	if (pccard_get_product(dev, &prod))
31766200Simp		return (NULL);
31866200Simp	if (pccard_get_function_number(dev, &fcn))
31966200Simp		return (NULL);
32066200Simp	if (pccard_get_vendor_str(dev, &vendorstr))
32166200Simp		return (NULL);
32266200Simp	if (pccard_get_product_str(dev, &prodstr))
32366200Simp		return (NULL);
32482378Sjon	for (ent = tab; ent->pp_name != NULL; ent =
32582378Sjon	    (const struct pccard_product *) ((const char *) ent + ent_size)) {
32666200Simp		matches = 1;
32786642Simp		if (ent->pp_vendor == PCCARD_VENDOR_ANY &&
328113078Ssanpei		    ent->pp_product == PCCARD_PRODUCT_ANY &&
32986642Simp		    ent->pp_cis[0] == NULL &&
33086642Simp		    ent->pp_cis[1] == NULL) {
33186642Simp			device_printf(dev,
33286642Simp			    "Total wildcard entry ignored for %s\n",
33386642Simp			    ent->pp_name);
33486642Simp			continue;
33586642Simp		}
33666200Simp		if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY &&
33766200Simp		    vendor != ent->pp_vendor)
33866200Simp			matches = 0;
33966200Simp		if (matches && ent->pp_product != PCCARD_PRODUCT_ANY &&
34066200Simp		    prod != ent->pp_product)
34166200Simp			matches = 0;
34266200Simp		if (matches && fcn != ent->pp_expfunc)
34366200Simp			matches = 0;
34471322Simp		if (matches && ent->pp_cis[0] &&
34571322Simp		    strcmp(ent->pp_cis[0], vendorstr) != 0)
34666200Simp			matches = 0;
34771322Simp		if (matches && ent->pp_cis[1] &&
34871322Simp		    strcmp(ent->pp_cis[1], prodstr) != 0)
34966200Simp			matches = 0;
35071322Simp		/* XXX need to match cis[2] and cis[3] also XXX */
35166200Simp		if (matchfn != NULL)
35266200Simp			matches = (*matchfn)(dev, ent, matches);
35366200Simp		if (matches)
35466200Simp			return (ent);
35566200Simp	}
35666200Simp	return (NULL);
35766200Simp}
35866200Simp
35970715Sjonstatic int
36059193Simppccard_card_gettype(device_t dev, int *type)
36152506Simp{
36264850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
36352506Simp	struct pccard_function *pf;
36452506Simp
36552506Simp	/*
36652506Simp	 * set the iftype to memory if this card has no functions (not yet
36752506Simp	 * probed), or only one function, and that is not initialized yet or
36852506Simp	 * that is memory.
36952506Simp	 */
37052506Simp	pf = STAILQ_FIRST(&sc->card.pf_head);
37152506Simp	if (pf == NULL ||
37252506Simp	    (STAILQ_NEXT(pf, pf_list) == NULL &&
37352506Simp	    (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY)))
37459193Simp		*type = PCCARD_IFTYPE_MEMORY;
37552506Simp	else
37659193Simp		*type = PCCARD_IFTYPE_IO;
37774632Simp	return (0);
37852506Simp}
37952506Simp
38052506Simp/*
38152506Simp * Initialize a PCCARD function.  May be called as long as the function is
38252506Simp * disabled.
38382382Simp *
38482382Simp * Note: pccard_function_init should not keep resources allocated.  It should
38582382Simp * only set them up ala isa pnp, set the values in the rl lists, and return.
38682382Simp * Any resource held after pccard_function_init is called is a bug.  However,
38782382Simp * the bus routines to get the resources also assume that pccard_function_init
38882382Simp * does this, so they need to be fixed too.
38952506Simp */
39082378Sjonstatic void
39170715Sjonpccard_function_init(struct pccard_function *pf)
39252506Simp{
39365917Simp	struct pccard_config_entry *cfe;
39467187Simp	int i;
39567242Simp	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
39667242Simp	struct resource_list *rl = &devi->resources;
39770762Simp	struct resource_list_entry *rle;
39867242Simp	struct resource *r = 0;
39967242Simp	device_t bus;
40067424Simp	int start;
40167424Simp	int end;
40290897Simp	int spaces;
40365917Simp
40470715Sjon	if (pf->pf_flags & PFF_ENABLED) {
40570715Sjon		printf("pccard_function_init: function is enabled");
40670715Sjon		return;
40770715Sjon	}
40867242Simp	bus = device_get_parent(pf->dev);
40952506Simp	/* Remember which configuration entry we are using. */
41072012Sphk	STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
41167187Simp		for (i = 0; i < cfe->num_iospace; i++)
41267187Simp			cfe->iores[i] = NULL;
41367187Simp		cfe->irqres = NULL;
41490897Simp		spaces = 0;
41567187Simp		for (i = 0; i < cfe->num_iospace; i++) {
41667424Simp			start = cfe->iospace[i].start;
41767424Simp			if (start)
41867424Simp				end = start + cfe->iospace[i].length - 1;
41967424Simp			else
42067424Simp				end = ~0;
42167187Simp			cfe->iorid[i] = i;
42290897Simp			DEVPRINTF((bus, "I/O rid %d start %x end %x\n",
42390897Simp			    i, start, end));
42467242Simp			r = cfe->iores[i] = bus_alloc_resource(bus,
42567424Simp			    SYS_RES_IOPORT, &cfe->iorid[i], start, end,
42670715Sjon			    cfe->iospace[i].length,
42767424Simp			    rman_make_alignment_flags(cfe->iospace[i].length));
42876424Simp			if (cfe->iores[i] == NULL)
42967187Simp				goto not_this_one;
43067242Simp			resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i],
43167242Simp			    rman_get_start(r), rman_get_end(r),
43267242Simp			    cfe->iospace[i].length);
43376424Simp			rle = resource_list_find(rl, SYS_RES_IOPORT,
43476424Simp			    cfe->iorid[i]);
43576424Simp			rle->res = r;
43690897Simp			spaces++;
43767187Simp		}
43867187Simp		if (cfe->num_memspace > 0) {
43982781Sshiba			/*
44082781Sshiba			 * Not implement yet, Fix me.
44182781Sshiba			 */
44290897Simp			DEVPRINTF((bus, "Memory space not yet implemented.\n"));
44367187Simp		}
44490897Simp		if (spaces == 0) {
44590897Simp			DEVPRINTF((bus, "Neither memory nor I/O mampped\n"));
44690897Simp			goto not_this_one;
44790897Simp		}
44867187Simp		if (cfe->irqmask) {
44967187Simp			cfe->irqrid = 0;
45067399Simp			r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ,
45167424Simp			    &cfe->irqrid, 0, ~0, 1, 0);
45276424Simp			if (cfe->irqres == NULL)
45367187Simp				goto not_this_one;
45467242Simp			resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid,
45567242Simp			    rman_get_start(r), rman_get_end(r), 1);
45676424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
45776424Simp			    cfe->irqrid);
45876424Simp			rle->res = r;
45967187Simp		}
46067187Simp		/* If we get to here, we've allocated all we need */
46167167Simp		pf->cfe = cfe;
46267187Simp		break;
46367187Simp	    not_this_one:;
46467424Simp		DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n",
46567424Simp		    cfe->number));
46667333Simp		/*
46767333Simp		 * Release resources that we partially allocated
46867333Simp		 * from this config entry.
46967333Simp		 */
47067187Simp		for (i = 0; i < cfe->num_iospace; i++) {
47176424Simp			if (cfe->iores[i] != NULL) {
47270715Sjon				bus_release_resource(bus, SYS_RES_IOPORT,
47367187Simp				    cfe->iorid[i], cfe->iores[i]);
47482378Sjon				rle = resource_list_find(rl, SYS_RES_IOPORT,
47576424Simp				    cfe->iorid[i]);
47676424Simp				rle->res = NULL;
47776424Simp				resource_list_delete(rl, SYS_RES_IOPORT,
47876424Simp				    cfe->iorid[i]);
47975756Simp			}
48067187Simp			cfe->iores[i] = NULL;
48167187Simp		}
48276424Simp		if (cfe->irqmask && cfe->irqres != NULL) {
48367242Simp			bus_release_resource(bus, SYS_RES_IRQ,
48467187Simp			    cfe->irqrid, cfe->irqres);
48576424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
48676424Simp			    cfe->irqrid);
48776424Simp			rle->res = NULL;
48876424Simp			resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid);
48967187Simp			cfe->irqres = NULL;
49067187Simp		}
49167167Simp	}
49252506Simp}
49352506Simp
49482378Sjon/*
49582378Sjon * Free resources allocated by pccard_function_init(), May be called as long
49682378Sjon * as the function is disabled.
49782382Simp *
49882382Simp * NOTE: This function should be unnecessary.  pccard_function_init should
49982382Simp * never keep resources initialized.
50082378Sjon */
50182378Sjonstatic void
50282378Sjonpccard_function_free(struct pccard_function *pf)
50382378Sjon{
50482378Sjon	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
50582378Sjon	struct resource_list_entry *rle;
50682378Sjon
50782378Sjon	if (pf->pf_flags & PFF_ENABLED) {
50882378Sjon		printf("pccard_function_init: function is enabled");
50982378Sjon		return;
51082378Sjon	}
51182378Sjon
51282378Sjon	SLIST_FOREACH(rle, &devi->resources, link) {
51382378Sjon		if (rle->res) {
51482378Sjon			if (rle->res->r_dev != pf->sc->dev)
51582378Sjon				device_printf(pf->sc->dev,
51682378Sjon				    "function_free: Resource still owned by "
51782378Sjon				    "child, oops. "
51882378Sjon				    "(type=%d, rid=%d, addr=%lx)\n",
51982378Sjon				    rle->type, rle->rid,
52082378Sjon				    rman_get_start(rle->res));
52182378Sjon			BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
52282378Sjon			    rle->res->r_dev, rle->type, rle->rid, rle->res);
52382378Sjon			rle->res = NULL;
52482378Sjon		}
52582378Sjon	}
52682378Sjon	resource_list_free(&devi->resources);
52782378Sjon}
52882378Sjon
52952506Simp/* Enable a PCCARD function */
53082378Sjonstatic int
53155720Simppccard_function_enable(struct pccard_function *pf)
53252506Simp{
53352506Simp	struct pccard_function *tmp;
53452506Simp	int reg;
53555720Simp	device_t dev = pf->sc->dev;
53670746Simp
53767333Simp	if (pf->cfe == NULL) {
53867333Simp		DEVPRVERBOSE((dev, "No config entry could be allocated.\n"));
53974632Simp		return (ENOMEM);
54067333Simp	}
54152506Simp
54252506Simp	/*
54352506Simp	 * Increase the reference count on the socket, enabling power, if
54452506Simp	 * necessary.
54552506Simp	 */
54682378Sjon	pf->sc->sc_enabled_count++;
54752506Simp
54852506Simp	if (pf->pf_flags & PFF_ENABLED) {
54952506Simp		/*
55052506Simp		 * Don't do anything if we're already enabled.
55152506Simp		 */
55252506Simp		return (0);
55352506Simp	}
55452506Simp
55552506Simp	/*
55652506Simp	 * it's possible for different functions' CCRs to be in the same
55752506Simp	 * underlying page.  Check for that.
55852506Simp	 */
55952506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
56052506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
56152506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
56252506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
56382378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
56482378Sjon		    tmp->pf_ccr_realsize))) {
56552506Simp			pf->pf_ccrt = tmp->pf_ccrt;
56652506Simp			pf->pf_ccrh = tmp->pf_ccrh;
56752506Simp			pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
56852506Simp
56952506Simp			/*
57052506Simp			 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
57152506Simp			 * tmp->ccr_base) + pf->ccr_base;
57252506Simp			 */
57370715Sjon			/* pf->pf_ccr_offset =
57452506Simp			    (tmp->pf_ccr_offset + pf->ccr_base) -
57570715Sjon			    tmp->ccr_base; */
57652506Simp			pf->pf_ccr_window = tmp->pf_ccr_window;
57752506Simp			break;
57852506Simp		}
57952506Simp	}
58052506Simp	if (tmp == NULL) {
58155720Simp		pf->ccr_rid = 0;
58255720Simp		pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
58370715Sjon		    &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE);
58470715Sjon		if (!pf->ccr_res)
58552506Simp			goto bad;
586106914Smux		DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%x\n",
58770746Simp		    rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res),
58870746Simp		    pf->ccr_base));
58961788Simp		CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
59061788Simp		    pf->ccr_rid, PCCARD_A_MEM_ATTR);
59170715Sjon		CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev,
59270748Simp		    pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset);
59355720Simp		pf->pf_ccrt = rman_get_bustag(pf->ccr_res);
59455720Simp		pf->pf_ccrh = rman_get_bushandle(pf->ccr_res);
59555720Simp		pf->pf_ccr_realsize = 1;
59652506Simp	}
59752506Simp
59852506Simp	reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX);
59952506Simp	reg |= PCCARD_CCR_OPTION_LEVIREQ;
60052506Simp	if (pccard_mfc(pf->sc)) {
60152506Simp		reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE |
60252506Simp			PCCARD_CCR_OPTION_ADDR_DECODE);
60382383Simp		/* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */
60452506Simp	}
60552506Simp	pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
60652506Simp
60752506Simp	reg = 0;
60852506Simp	if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0)
60952506Simp		reg |= PCCARD_CCR_STATUS_IOIS8;
61052506Simp	if (pf->cfe->flags & PCCARD_CFE_AUDIO)
61152506Simp		reg |= PCCARD_CCR_STATUS_AUDIO;
61252506Simp	pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg);
61352506Simp
61452506Simp	pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0);
61552506Simp
61652506Simp	if (pccard_mfc(pf->sc)) {
61752506Simp		long tmp, iosize;
61852506Simp
61952506Simp		tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
62052506Simp		/* round up to nearest (2^n)-1 */
62152506Simp		for (iosize = 1; iosize < tmp; iosize <<= 1)
62252506Simp			;
62352506Simp		iosize--;
62452506Simp
62552506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
62652506Simp				 pf->pf_mfc_iobase & 0xff);
62752506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
62852506Simp				 (pf->pf_mfc_iobase >> 8) & 0xff);
62952506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
63052506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
63152506Simp
63252506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
63352506Simp	}
63452506Simp
63552506Simp#ifdef PCCARDDEBUG
63652506Simp	if (pccard_debug) {
63752506Simp		STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
63870715Sjon			device_printf(tmp->sc->dev,
63955500Simp			    "function %d CCR at %d offset %x: "
64055500Simp			    "%x %x %x %x, %x %x %x %x, %x\n",
64170715Sjon			    tmp->number, tmp->pf_ccr_window,
64255500Simp			    tmp->pf_ccr_offset,
64355500Simp			    pccard_ccr_read(tmp, 0x00),
64455500Simp			    pccard_ccr_read(tmp, 0x02),
64555500Simp			    pccard_ccr_read(tmp, 0x04),
64655500Simp			    pccard_ccr_read(tmp, 0x06),
64755500Simp			    pccard_ccr_read(tmp, 0x0A),
64870715Sjon			    pccard_ccr_read(tmp, 0x0C),
64955500Simp			    pccard_ccr_read(tmp, 0x0E),
65055500Simp			    pccard_ccr_read(tmp, 0x10),
65155500Simp			    pccard_ccr_read(tmp, 0x12));
65252506Simp		}
65352506Simp	}
65452506Simp#endif
65552506Simp	pf->pf_flags |= PFF_ENABLED;
65652506Simp	return (0);
65752506Simp
65852506Simp bad:
65952506Simp	/*
66052506Simp	 * Decrement the reference count, and power down the socket, if
66152506Simp	 * necessary.
66252506Simp	 */
66382378Sjon	pf->sc->sc_enabled_count--;
66465098Simp	DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count));
66552506Simp
66652506Simp	return (1);
66752506Simp}
66852506Simp
66952506Simp/* Disable PCCARD function. */
67082378Sjonstatic void
67155720Simppccard_function_disable(struct pccard_function *pf)
67252506Simp{
67352506Simp	struct pccard_function *tmp;
67455720Simp	device_t dev = pf->sc->dev;
67552506Simp
67652506Simp	if (pf->cfe == NULL)
67761788Simp		panic("pccard_function_disable: function not initialized");
67852506Simp
67952506Simp	if ((pf->pf_flags & PFF_ENABLED) == 0) {
68052506Simp		/*
68152506Simp		 * Don't do anything if we're already disabled.
68252506Simp		 */
68352506Simp		return;
68452506Simp	}
68552506Simp
68670715Sjon	if (pf->intr_handler != NULL) {
68782378Sjon		struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
68882378Sjon		struct resource_list_entry *rle =
68982378Sjon		    resource_list_find(&devi->resources, SYS_RES_IRQ, 0);
69082378Sjon		BUS_TEARDOWN_INTR(dev, pf->dev, rle->res,
69182378Sjon		    pf->intr_handler_cookie);
69270715Sjon	}
69370715Sjon
69452506Simp	/*
69552506Simp	 * it's possible for different functions' CCRs to be in the same
69652506Simp	 * underlying page.  Check for that.  Note we mark us as disabled
69752506Simp	 * first to avoid matching ourself.
69852506Simp	 */
69952506Simp
70052506Simp	pf->pf_flags &= ~PFF_ENABLED;
70152506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
70252506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
70352506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
70452506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
70582378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
70682378Sjon		    tmp->pf_ccr_realsize)))
70752506Simp			break;
70852506Simp	}
70952506Simp
71052506Simp	/* Not used by anyone else; unmap the CCR. */
71152506Simp	if (tmp == NULL) {
71270715Sjon		bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid,
71355720Simp		    pf->ccr_res);
71455720Simp		pf->ccr_res = NULL;
71552506Simp	}
71652506Simp
71752506Simp	/*
71852506Simp	 * Decrement the reference count, and power down the socket, if
71952506Simp	 * necessary.
72052506Simp	 */
72182378Sjon	pf->sc->sc_enabled_count--;
72252506Simp}
72352506Simp
72466058Simp/*
72566058Simp * simulate the old "probe" routine.  In the new world order, the driver
72666058Simp * needs to grab devices while in the old they were assigned to the device by
72766058Simp * the pccardd process.  These symbols are exported to the upper layers.
72866058Simp */
72974636Simpstatic int
73074636Simppccard_compat_do_probe(device_t bus, device_t dev)
73166058Simp{
73266058Simp	return (CARD_COMPAT_MATCH(dev));
73366058Simp}
73466058Simp
73574636Simpstatic int
73674636Simppccard_compat_do_attach(device_t bus, device_t dev)
73766058Simp{
73866058Simp	int err;
73966058Simp
74066058Simp	err = CARD_COMPAT_PROBE(dev);
74166058Simp	if (err == 0)
74266058Simp		err = CARD_COMPAT_ATTACH(dev);
74366058Simp	return (err);
74466058Simp}
74566058Simp
74653873Simp#define PCCARD_NPORT	2
74753873Simp#define PCCARD_NMEM	5
74853873Simp#define PCCARD_NIRQ	1
74953873Simp#define PCCARD_NDRQ	0
75053873Simp
75152506Simpstatic int
75252506Simppccard_add_children(device_t dev, int busno)
75352506Simp{
75459193Simp	/* Call parent to scan for any current children */
75574632Simp	return (0);
75652506Simp}
75752506Simp
75852506Simpstatic int
75952506Simppccard_probe(device_t dev)
76052506Simp{
76167333Simp	device_set_desc(dev, "16-bit PCCard bus");
76274632Simp	return (pccard_add_children(dev, device_get_unit(dev)));
76352506Simp}
76452506Simp
76559193Simpstatic int
76659193Simppccard_attach(device_t dev)
76759193Simp{
76864850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
76961788Simp
77059193Simp	sc->dev = dev;
77161788Simp	sc->sc_enabled_count = 0;
77274632Simp	return (bus_generic_attach(dev));
77359193Simp}
77459193Simp
77582378Sjonstatic int
77682378Sjonpccard_detach(device_t dev)
77782378Sjon{
778106362Simp	pccard_detach_card(dev);
77982378Sjon	return 0;
78082378Sjon}
78182378Sjon
78287975Simpstatic int
78387975Simppccard_suspend(device_t self)
78487975Simp{
785106362Simp	pccard_detach_card(self);
78687975Simp	return (0);
78787975Simp}
78887975Simp
78987975Simpstatic
79087975Simpint
79187975Simppccard_resume(device_t self)
79287975Simp{
79387975Simp	return (0);
79487975Simp}
79587975Simp
79653873Simpstatic void
79753873Simppccard_print_resources(struct resource_list *rl, const char *name, int type,
79853873Simp    int count, const char *format)
79953873Simp{
80053873Simp	struct resource_list_entry *rle;
80153873Simp	int printed;
80253873Simp	int i;
80353873Simp
80453873Simp	printed = 0;
80553873Simp	for (i = 0; i < count; i++) {
80653873Simp		rle = resource_list_find(rl, type, i);
80776424Simp		if (rle != NULL) {
80853873Simp			if (printed == 0)
80953873Simp				printf(" %s ", name);
81053873Simp			else if (printed > 0)
81153873Simp				printf(",");
81253873Simp			printed++;
81353873Simp			printf(format, rle->start);
81453873Simp			if (rle->count > 1) {
81553873Simp				printf("-");
81653873Simp				printf(format, rle->start + rle->count - 1);
81753873Simp			}
81853873Simp		} else if (i > 3) {
81953873Simp			/* check the first few regardless */
82053873Simp			break;
82153873Simp		}
82253873Simp	}
82353873Simp}
82453873Simp
82553873Simpstatic int
82653873Simppccard_print_child(device_t dev, device_t child)
82753873Simp{
82866847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
82953873Simp	struct resource_list *rl = &devi->resources;
83053873Simp	int retval = 0;
83153873Simp
83253873Simp	retval += bus_print_child_header(dev, child);
83353873Simp	retval += printf(" at");
83453873Simp
83576424Simp	if (devi != NULL) {
83653873Simp		pccard_print_resources(rl, "port", SYS_RES_IOPORT,
83753873Simp		    PCCARD_NPORT, "%#lx");
83853873Simp		pccard_print_resources(rl, "iomem", SYS_RES_MEMORY,
83953873Simp		    PCCARD_NMEM, "%#lx");
84053873Simp		pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ,
84153873Simp		    "%ld");
84270715Sjon		pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ,
84353873Simp		    "%ld");
84467269Simp		retval += printf(" function %d config %d", devi->fcn->number,
84567269Simp		    devi->fcn->cfe->number);
84653873Simp	}
84753873Simp
84853873Simp	retval += bus_print_child_footer(dev, child);
84953873Simp
85053873Simp	return (retval);
85153873Simp}
85253873Simp
85353873Simpstatic int
85453873Simppccard_set_resource(device_t dev, device_t child, int type, int rid,
85553873Simp		 u_long start, u_long count)
85653873Simp{
85766847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
85853873Simp	struct resource_list *rl = &devi->resources;
85953873Simp
86053873Simp	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
86153873Simp	    && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
86274632Simp		return (EINVAL);
86353873Simp	if (rid < 0)
86474632Simp		return (EINVAL);
86553873Simp	if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT)
86674632Simp		return (EINVAL);
86753873Simp	if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM)
86874632Simp		return (EINVAL);
86953873Simp	if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ)
87074632Simp		return (EINVAL);
87153873Simp	if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ)
87274632Simp		return (EINVAL);
87353873Simp
87453873Simp	resource_list_add(rl, type, rid, start, start + count - 1, count);
87582378Sjon	if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev,
87682378Sjon	    type, &rid, start, start + count - 1, count, 0))
87782378Sjon		return 0;
87882378Sjon	else
87982378Sjon		return ENOMEM;
88053873Simp}
88153873Simp
88253873Simpstatic int
88353873Simppccard_get_resource(device_t dev, device_t child, int type, int rid,
88453873Simp    u_long *startp, u_long *countp)
88553873Simp{
88666847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
88753873Simp	struct resource_list *rl = &devi->resources;
88853873Simp	struct resource_list_entry *rle;
88953873Simp
89053873Simp	rle = resource_list_find(rl, type, rid);
89176424Simp	if (rle == NULL)
89274632Simp		return (ENOENT);
89370715Sjon
89476424Simp	if (startp != NULL)
89553873Simp		*startp = rle->start;
89676424Simp	if (countp != NULL)
89753873Simp		*countp = rle->count;
89853873Simp
89974632Simp	return (0);
90053873Simp}
90153873Simp
90253873Simpstatic void
90353873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid)
90453873Simp{
90566847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
90653873Simp	struct resource_list *rl = &devi->resources;
90753873Simp	resource_list_delete(rl, type, rid);
90853873Simp}
90953873Simp
91059193Simpstatic int
91159193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid,
91259193Simp    u_int32_t flags)
91359193Simp{
91474632Simp	return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type,
91574632Simp	    rid, flags));
91659193Simp}
91759193Simp
91859193Simpstatic int
91959193Simppccard_set_memory_offset(device_t dev, device_t child, int rid,
92082378Sjon    u_int32_t offset, u_int32_t *deltap)
92170715Sjon
92259193Simp{
92374632Simp	return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid,
92474632Simp	    offset, deltap));
92559193Simp}
92659193Simp
927104641Simpstatic void
928104641Simppccard_probe_nomatch(device_t bus, device_t child)
929104641Simp{
930104641Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
931104641Simp	struct pccard_function *func = devi->fcn;
932104641Simp	struct pccard_softc *sc = PCCARD_SOFTC(bus);
933104641Simp
934104641Simp	device_printf(bus, "<unknown card>");
935104641Simp	printf(" (manufacturer=0x%04x, product=0x%04x) at function %d\n",
936104641Simp	  sc->card.manufacturer, sc->card.product, func->number);
937104641Simp	device_printf(bus, "   CIS info: %s, %s, %s\n", sc->card.cis1_info[0],
938104641Simp	  sc->card.cis1_info[1], sc->card.cis1_info[2]);
939104641Simp	return;
940104641Simp}
941104641Simp
94266058Simpstatic int
943104641Simppccard_child_location_str(device_t bus, device_t child, char *buf,
944104641Simp    size_t buflen)
945104641Simp{
946104641Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
947104641Simp	struct pccard_function *func = devi->fcn;
948104641Simp
949104641Simp	snprintf(buf, buflen, "function=%d", func->number);
950104641Simp	return (0);
951104641Simp}
952104641Simp
953104641Simpstatic int
954104641Simppccard_child_pnpinfo_str(device_t bus, device_t child, char *buf,
955104641Simp    size_t buflen)
956104641Simp{
957104641Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
958104641Simp	struct pccard_function *func = devi->fcn;
959104641Simp	struct pccard_softc *sc = PCCARD_SOFTC(bus);
960104641Simp
961104641Simp	snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x "
962104641Simp	    "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d",
963104641Simp	    sc->card.manufacturer, sc->card.product, sc->card.cis1_info[0],
964104641Simp	    sc->card.cis1_info[1], func->function);
965104641Simp	return (0);
966104641Simp}
967104641Simp
968104641Simpstatic int
96966058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result)
97066058Simp{
97166847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
97266779Simp	struct pccard_function *func = devi->fcn;
97366779Simp	struct pccard_softc *sc = PCCARD_SOFTC(bus);
97466779Simp
97566779Simp	switch (which) {
97666779Simp	default:
97766779Simp	case PCCARD_IVAR_ETHADDR:
97882781Sshiba		bcopy(func->pf_funce_lan_nid, result, ETHER_ADDR_LEN);
97966779Simp		break;
98066779Simp	case PCCARD_IVAR_VENDOR:
98166779Simp		*(u_int32_t *) result = sc->card.manufacturer;
98266779Simp		break;
98366779Simp	case PCCARD_IVAR_PRODUCT:
98466779Simp		*(u_int32_t *) result = sc->card.product;
98566779Simp		break;
98690964Sshiba	case PCCARD_IVAR_PRODEXT:
98790964Sshiba		*(u_int16_t *) result = sc->card.prodext;
98890964Sshiba		break;
98975761Simp	case PCCARD_IVAR_FUNCTION:
99075761Simp		*(u_int32_t *) result = func->function;
99175761Simp		break;
99266779Simp	case PCCARD_IVAR_FUNCTION_NUMBER:
99366847Simp		if (!func) {
99466847Simp			device_printf(bus, "No function number, bug!\n");
99566847Simp			return (ENOENT);
99666847Simp		}
99766847Simp		*(u_int32_t *) result = func->number;
99866779Simp		break;
99966779Simp	case PCCARD_IVAR_VENDOR_STR:
100066779Simp		*(char **) result = sc->card.cis1_info[0];
100166779Simp		break;
100266779Simp	case PCCARD_IVAR_PRODUCT_STR:
100366779Simp		*(char **) result = sc->card.cis1_info[1];
100466779Simp		break;
100566779Simp	case PCCARD_IVAR_CIS3_STR:
100666779Simp		*(char **) result = sc->card.cis1_info[2];
100766779Simp		break;
100867167Simp	case PCCARD_IVAR_CIS4_STR:
1009104610Simp		*(char **) result = sc->card.cis1_info[3];
101067167Simp		break;
101166779Simp	}
101266779Simp	return (0);
101366058Simp}
101466058Simp
101566779Simpstatic void
101666779Simppccard_driver_added(device_t dev, driver_t *driver)
101766779Simp{
101882378Sjon	struct pccard_softc *sc = PCCARD_SOFTC(dev);
101982378Sjon	struct pccard_function *pf;
102082378Sjon	device_t child;
102182378Sjon
102282378Sjon	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
102382378Sjon		if (STAILQ_EMPTY(&pf->cfe_head))
102482378Sjon			continue;
102582378Sjon		child = pf->dev;
102682378Sjon		if (device_get_state(child) != DS_NOTPRESENT)
102782378Sjon			continue;
102882378Sjon		if (pccard_function_enable(pf) == 0 &&
102982378Sjon		    device_probe_and_attach(child) == 0) {
103082378Sjon			DEVPRINTF((sc->dev, "function %d CCR at %d "
103182378Sjon			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
103282378Sjon			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
103382378Sjon			    pccard_ccr_read(pf, 0x00),
103482378Sjon			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
103582378Sjon			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
103682378Sjon			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
103782378Sjon			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
103882378Sjon		} else {
103986907Simp			if (pf->cfe != NULL)
104086907Simp				pccard_function_disable(pf);
104182378Sjon		}
104282378Sjon	}
104382378Sjon	return;
104466779Simp}
104566058Simp
104667242Simpstatic struct resource *
104767242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid,
104867242Simp    u_long start, u_long end, u_long count, u_int flags)
104967242Simp{
105082378Sjon	struct pccard_ivar *dinfo;
105182378Sjon	struct resource_list_entry *rle = 0;
105282378Sjon	int passthrough = (device_get_parent(child) != dev);
1053104641Simp	struct resource *r = NULL;
105467242Simp
105582378Sjon	if (passthrough) {
105682378Sjon		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
105782378Sjon		    type, rid, start, end, count, flags));
105882378Sjon	}
105970715Sjon
106082378Sjon	dinfo = device_get_ivars(child);
106182378Sjon	rle = resource_list_find(&dinfo->resources, type, *rid);
106270715Sjon
1063104641Simp	if (rle == NULL)
1064104641Simp		return (NULL);		/* no resource of that type/rid */
106570715Sjon
1066104641Simp	if (rle->res == NULL) {
106782378Sjon		switch(type) {
106882378Sjon		case SYS_RES_IOPORT:
1069104641Simp			r = bus_alloc_resource(dev, type, rid, start, end,
1070104641Simp			    count, rman_make_alignment_flags(count));
1071104641Simp			if (r == NULL)
1072104641Simp				goto bad;
1073104641Simp			resource_list_add(&dinfo->resources, type, *rid,
1074104641Simp			    rman_get_start(r), rman_get_end(r), count);
1075104641Simp			rle = resource_list_find(&dinfo->resources, type, *rid);
1076104641Simp			if (!rle)
1077104641Simp				goto bad;
1078104641Simp			rle->res = r;
1079104641Simp			break;
108082378Sjon		case SYS_RES_MEMORY:
108182378Sjon			break;
108282378Sjon		case SYS_RES_IRQ:
108382378Sjon			break;
108482378Sjon		}
108590897Simp		return (rle->res);
108667269Simp	}
1087104641Simp	if (rle->res->r_dev != dev)
1088104641Simp		return (NULL);
1089104641Simp	bus_release_resource(dev, type, *rid, rle->res);
1090104641Simp	rle->res = NULL;
1091104641Simp	switch(type) {
1092104641Simp	case SYS_RES_IOPORT:
1093104641Simp	case SYS_RES_MEMORY:
1094104641Simp		if (!(flags & RF_ALIGNMENT_MASK))
1095104641Simp			flags |= rman_make_alignment_flags(rle->count);
1096104641Simp		break;
1097104641Simp	case SYS_RES_IRQ:
1098104641Simp		flags |= RF_SHAREABLE;
1099104641Simp		break;
1100104641Simp	}
1101104641Simp	rle->res = resource_list_alloc(&dinfo->resources, dev, child,
1102104641Simp	    type, rid, rle->start, rle->end, rle->count, flags);
1103104641Simp	return (rle->res);
1104104641Simpbad:;
1105104641Simp	device_printf(dev, "WARNING: Resource not reserved by pccard\n");
1106104641Simp	return (NULL);
110767242Simp}
110867242Simp
110967242Simpstatic int
111067242Simppccard_release_resource(device_t dev, device_t child, int type, int rid,
111167242Simp    struct resource *r)
111267242Simp{
111382378Sjon	struct pccard_ivar *dinfo;
111482378Sjon	int passthrough = (device_get_parent(child) != dev);
111582378Sjon	struct resource_list_entry *rle = 0;
111682378Sjon	int ret;
111782378Sjon	int flags;
111870715Sjon
111982378Sjon	if (passthrough)
112082378Sjon		return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
112182378Sjon		    type, rid, r);
112270715Sjon
112382378Sjon	dinfo = device_get_ivars(child);
112470715Sjon
112582378Sjon	rle = resource_list_find(&dinfo->resources, type, rid);
112670715Sjon
112782378Sjon	if (!rle) {
112882378Sjon		device_printf(dev, "Allocated resource not found, "
112982378Sjon		    "%d %x %lx %lx\n",
113082378Sjon		    type, rid, rman_get_start(r), rman_get_size(r));
113182378Sjon		return ENOENT;
113270715Sjon	}
113382378Sjon	if (!rle->res) {
113482378Sjon		device_printf(dev, "Allocated resource not recorded\n");
113582378Sjon		return ENOENT;
113670715Sjon	}
113770715Sjon
113882378Sjon	ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
113982378Sjon	    type, rid, r);
114082378Sjon	switch(type) {
114182378Sjon	case SYS_RES_IOPORT:
114282378Sjon	case SYS_RES_MEMORY:
114382378Sjon		flags = rman_make_alignment_flags(rle->count);
114482378Sjon		break;
114582378Sjon	case SYS_RES_IRQ:
114682378Sjon		flags = RF_SHAREABLE;
114782378Sjon		break;
114882378Sjon	default:
114982378Sjon		flags = 0;
115070715Sjon	}
115182378Sjon	rle->res = bus_alloc_resource(dev, type, &rid,
115282378Sjon	    rle->start, rle->end, rle->count, flags);
115382378Sjon	if (rle->res == NULL)
115482378Sjon		device_printf(dev, "release_resource: "
115582378Sjon		    "unable to reaquire resource\n");
115682378Sjon	return ret;
115767242Simp}
115867242Simp
115967333Simpstatic void
116067333Simppccard_child_detached(device_t parent, device_t dev)
116167333Simp{
116267333Simp	struct pccard_ivar *ivar = PCCARD_IVAR(dev);
116382378Sjon	struct pccard_function *pf = ivar->fcn;
116467333Simp
116582378Sjon	pccard_function_disable(pf);
116667333Simp}
116767333Simp
116870715Sjonstatic void
116970762Simppccard_intr(void *arg)
117070762Simp{
117182378Sjon	struct pccard_function *pf = (struct pccard_function*) arg;
117282378Sjon	int reg;
1173102923Simp	int doisr = 1;
117482378Sjon
117582383Simp	/*
1176102923Simp	 * MFC cards know if they interrupted, so we have to ack the
1177102923Simp	 * interrupt and call the ISR.  Non-MFC cards don't have these
1178102923Simp	 * bits, so they always get called.  Many non-MFC cards have
1179102923Simp	 * this bit set always upon read, but some do not.
1180102923Simp	 *
1181102923Simp	 * We always ack the interrupt, even if there's no ISR
1182102923Simp	 * for the card.  This is done on the theory that acking
1183102923Simp	 * the interrupt will pacify the card enough to keep an
1184102923Simp	 * interrupt storm from happening.  Of course this won't
1185102923Simp	 * help in the non-MFC case.
118682383Simp	 */
1187102923Simp	if (pccard_mfc(pf->sc)) {
1188102923Simp		reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
1189102923Simp		if (reg & PCCARD_CCR_STATUS_INTR)
1190102923Simp			pccard_ccr_write(pf, PCCARD_CCR_STATUS,
1191102923Simp			    reg & ~PCCARD_CCR_STATUS_INTR);
1192102923Simp		else
1193102923Simp			doisr = 0;
1194102923Simp	}
1195102923Simp	if (pf->intr_handler != NULL && doisr)
119682378Sjon		pf->intr_handler(pf->intr_handler_arg);
119770715Sjon}
119870715Sjon
119970715Sjonstatic int
120070762Simppccard_setup_intr(device_t dev, device_t child, struct resource *irq,
120170762Simp    int flags, driver_intr_t *intr, void *arg, void **cookiep)
120270715Sjon{
1203102713Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
120470715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
120570715Sjon	struct pccard_function *func = ivar->fcn;
120690445Simp	int err;
120770715Sjon
120870715Sjon	if (func->intr_handler != NULL)
1209101762Simp		panic("Only one interrupt handler per function allowed");
121090445Simp	err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr,
121190445Simp	    func, cookiep);
121290445Simp	if (err != 0)
121390445Simp		return (err);
121470715Sjon	func->intr_handler = intr;
121570715Sjon	func->intr_handler_arg = arg;
121682378Sjon	func->intr_handler_cookie = *cookiep;
1217102713Simp	if (pccard_mfc(sc)) {
1218102713Simp		pccard_ccr_write(func, PCCARD_CCR_OPTION,
1219102713Simp		    pccard_ccr_read(func, PCCARD_CCR_OPTION) |
1220102713Simp		    PCCARD_CCR_OPTION_IREQ_ENABLE);
1221102713Simp	}
122274632Simp	return (0);
122370715Sjon}
122470715Sjon
122570715Sjonstatic int
122670762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r,
122770762Simp    void *cookie)
122870715Sjon{
1229102713Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
123070715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
123170715Sjon	struct pccard_function *func = ivar->fcn;
123282378Sjon	int ret;
123370715Sjon
1234102713Simp	if (pccard_mfc(sc)) {
1235102713Simp		pccard_ccr_write(func, PCCARD_CCR_OPTION,
1236102713Simp		    pccard_ccr_read(func, PCCARD_CCR_OPTION) &
1237102713Simp		    ~PCCARD_CCR_OPTION_IREQ_ENABLE);
1238102713Simp	}
123990445Simp	ret = bus_generic_teardown_intr(dev, child, r, cookie);
124082378Sjon	if (ret == 0) {
124182378Sjon		func->intr_handler = NULL;
124282378Sjon		func->intr_handler_arg = NULL;
124382378Sjon		func->intr_handler_cookie = NULL;
124482378Sjon	}
124570715Sjon
124682378Sjon	return (ret);
124770715Sjon}
124870715Sjon
124952506Simpstatic device_method_t pccard_methods[] = {
125052506Simp	/* Device interface */
125152506Simp	DEVMETHOD(device_probe,		pccard_probe),
125259193Simp	DEVMETHOD(device_attach,	pccard_attach),
125382378Sjon	DEVMETHOD(device_detach,	pccard_detach),
125452506Simp	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
125587975Simp	DEVMETHOD(device_suspend,	pccard_suspend),
125687975Simp	DEVMETHOD(device_resume,	pccard_resume),
125752506Simp
125852506Simp	/* Bus interface */
125952506Simp	DEVMETHOD(bus_print_child,	pccard_print_child),
126066779Simp	DEVMETHOD(bus_driver_added,	pccard_driver_added),
126167333Simp	DEVMETHOD(bus_child_detached,	pccard_child_detached),
126267242Simp	DEVMETHOD(bus_alloc_resource,	pccard_alloc_resource),
126367242Simp	DEVMETHOD(bus_release_resource,	pccard_release_resource),
126482378Sjon	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
126582378Sjon	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
126670715Sjon	DEVMETHOD(bus_setup_intr,	pccard_setup_intr),
126770715Sjon	DEVMETHOD(bus_teardown_intr,	pccard_teardown_intr),
126852506Simp	DEVMETHOD(bus_set_resource,	pccard_set_resource),
126952506Simp	DEVMETHOD(bus_get_resource,	pccard_get_resource),
127052506Simp	DEVMETHOD(bus_delete_resource,	pccard_delete_resource),
1271104641Simp	DEVMETHOD(bus_probe_nomatch,	pccard_probe_nomatch),
127266058Simp	DEVMETHOD(bus_read_ivar,	pccard_read_ivar),
1273104641Simp	DEVMETHOD(bus_child_pnpinfo_str, pccard_child_pnpinfo_str),
1274104641Simp	DEVMETHOD(bus_child_location_str, pccard_child_location_str),
127552506Simp
127659193Simp	/* Card Interface */
127759193Simp	DEVMETHOD(card_set_res_flags,	pccard_set_res_flags),
127859193Simp	DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset),
127959193Simp	DEVMETHOD(card_get_type,	pccard_card_gettype),
128059193Simp	DEVMETHOD(card_attach_card,	pccard_attach_card),
128159193Simp	DEVMETHOD(card_detach_card,	pccard_detach_card),
128274636Simp	DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe),
128374636Simp	DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach),
128497613Stakawata	DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup),
128559193Simp
128652506Simp	{ 0, 0 }
128752506Simp};
128852506Simp
128952506Simpstatic driver_t pccard_driver = {
129052506Simp	"pccard",
129152506Simp	pccard_methods,
129264850Simp	sizeof(struct pccard_softc)
129352506Simp};
129452506Simp
129552506Simpdevclass_t	pccard_devclass;
129652506Simp
1297101905Simp/* Maybe we need to have a slot device? */
129853873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
129952506SimpDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0);
1300101905SimpDRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0);
130153873SimpDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0);
130264927SimpMODULE_VERSION(pccard, 1);
130370715Sjon/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/
1304