pccard.c revision 82382
166200Simp/*	$NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $	*/
252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard.c 82382 2001-08-27 01:18:21Z imp $ */
352506Simp
452506Simp/*
552506Simp * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
652506Simp *
752506Simp * Redistribution and use in source and binary forms, with or without
852506Simp * modification, are permitted provided that the following conditions
952506Simp * are met:
1052506Simp * 1. Redistributions of source code must retain the above copyright
1152506Simp *    notice, this list of conditions and the following disclaimer.
1252506Simp * 2. Redistributions in binary form must reproduce the above copyright
1352506Simp *    notice, this list of conditions and the following disclaimer in the
1452506Simp *    documentation and/or other materials provided with the distribution.
1552506Simp * 3. All advertising materials mentioning features or use of this software
1652506Simp *    must display the following acknowledgement:
1752506Simp *	This product includes software developed by Marc Horowitz.
1852506Simp * 4. The name of the author may not be used to endorse or promote products
1952506Simp *    derived from this software without specific prior written permission.
2052506Simp *
2152506Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2252506Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2352506Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2452506Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2552506Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2652506Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2752506Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2852506Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2952506Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3052506Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3152506Simp */
3252506Simp
3352506Simp#include <sys/param.h>
3452506Simp#include <sys/systm.h>
3552506Simp#include <sys/malloc.h>
3652506Simp#include <sys/module.h>
3752506Simp#include <sys/kernel.h>
3852506Simp#include <sys/queue.h>
3952506Simp#include <sys/types.h>
4052506Simp
4152506Simp#include <sys/bus.h>
4252506Simp#include <machine/bus.h>
4352506Simp#include <sys/rman.h>
4452506Simp#include <machine/resource.h>
4552506Simp
4652506Simp#include <dev/pccard/pccardreg.h>
4752506Simp#include <dev/pccard/pccardvar.h>
4852506Simp
4955500Simp#include "power_if.h"
5059193Simp#include "card_if.h"
5155500Simp
5255500Simp#define PCCARDDEBUG
5355500Simp
5452506Simp#ifdef PCCARDDEBUG
5555500Simpint	pccard_debug = 1;
5652506Simp#define	DPRINTF(arg) if (pccard_debug) printf arg
5755500Simp#define	DEVPRINTF(arg) if (pccard_debug) device_printf arg
5867333Simp#define PRVERBOSE(arg) printf arg
5967333Simp#define DEVPRVERBOSE(arg) device_printf arg
6052506Simp#else
6152506Simp#define	DPRINTF(arg)
6255500Simp#define	DEVPRINTF(arg)
6367333Simp#define PRVERBOSE(arg) if (bootverbose) printf arg
6467333Simp#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg
6552506Simp#endif
6652506Simp
6752506Simp#ifdef PCCARDVERBOSE
6852506Simpint	pccard_verbose = 1;
6952506Simp#else
7052506Simpint	pccard_verbose = 0;
7152506Simp#endif
7252506Simp
7382378Sjonstatic int	pccard_ccr_read(struct pccard_function *pf, int ccr);
7482378Sjonstatic void	pccard_ccr_write(struct pccard_function *pf, int ccr, int val);
7582378Sjonstatic int	pccard_attach_card(device_t dev);
7682378Sjonstatic int	pccard_detach_card(device_t dev, int flags);
7782378Sjonstatic const struct pccard_product *pccard_product_lookup(device_t dev,
7882378Sjon		    const struct pccard_product *tab, size_t ent_size,
7982378Sjon		    pccard_product_match_fn matchfn);
8082378Sjonstatic int	pccard_card_gettype(device_t dev, int *type);
8182378Sjonstatic void	pccard_function_init(struct pccard_function *pf);
8282378Sjonstatic void	pccard_function_free(struct pccard_function *pf);
8382378Sjonstatic int	pccard_function_enable(struct pccard_function *pf);
8482378Sjonstatic void	pccard_function_disable(struct pccard_function *pf);
8582378Sjonstatic int	pccard_compat_do_probe(device_t bus, device_t dev);
8682378Sjonstatic int	pccard_compat_do_attach(device_t bus, device_t dev);
8782378Sjonstatic int	pccard_add_children(device_t dev, int busno);
8882378Sjonstatic int	pccard_probe(device_t dev);
8982378Sjonstatic int	pccard_attach(device_t dev);
9082378Sjonstatic int	pccard_detach(device_t dev);
9182378Sjonstatic void	pccard_print_resources(struct resource_list *rl,
9282378Sjon		    const char *name, int type, int count, const char *format);
9382378Sjonstatic int	pccard_print_child(device_t dev, device_t child);
9482378Sjonstatic int	pccard_set_resource(device_t dev, device_t child, int type,
9582378Sjon		    int rid, u_long start, u_long count);
9682378Sjonstatic int	pccard_get_resource(device_t dev, device_t child, int type,
9782378Sjon		    int rid, u_long *startp, u_long *countp);
9882378Sjonstatic void	pccard_delete_resource(device_t dev, device_t child, int type,
9982378Sjon		    int rid);
10082378Sjonstatic int	pccard_set_res_flags(device_t dev, device_t child, int type,
10182378Sjon		    int rid, u_int32_t flags);
10282378Sjonstatic int	pccard_set_memory_offset(device_t dev, device_t child, int rid,
10382378Sjon		    u_int32_t offset, u_int32_t *deltap);
10482378Sjonstatic int	pccard_read_ivar(device_t bus, device_t child, int which,
10582378Sjon		    u_char *result);
10682378Sjonstatic void	pccard_driver_added(device_t dev, driver_t *driver);
10782378Sjonstatic struct resource *pccard_alloc_resource(device_t dev,
10882378Sjon		    device_t child, int type, int *rid, u_long start,
10982378Sjon		    u_long end, u_long count, u_int flags);
11082378Sjonstatic int	pccard_release_resource(device_t dev, device_t child, int type,
11182378Sjon		    int rid, struct resource *r);
11282378Sjonstatic void	pccard_child_detached(device_t parent, device_t dev);
11382378Sjonstatic void	pccard_intr(void *arg);
11482378Sjonstatic int	pccard_setup_intr(device_t dev, device_t child,
11582378Sjon		    struct resource *irq, int flags, driver_intr_t *intr,
11682378Sjon		    void *arg, void **cookiep);
11782378Sjonstatic int	pccard_teardown_intr(device_t dev, device_t child,
11882378Sjon		    struct resource *r, void *cookie);
11952506Simp
12082378Sjonstatic int
12174632Simppccard_ccr_read(struct pccard_function *pf, int ccr)
12252506Simp{
12352506Simp	return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
12452506Simp	    pf->pf_ccr_offset + ccr));
12552506Simp}
12652506Simp
12782378Sjonstatic void
12874632Simppccard_ccr_write(struct pccard_function *pf, int ccr, int val)
12952506Simp{
13052506Simp	if ((pf->ccr_mask) & (1 << (ccr / 2))) {
13152506Simp		bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
13252506Simp		    pf->pf_ccr_offset + ccr, val);
13352506Simp	}
13452506Simp}
13552506Simp
13659193Simpstatic int
13759193Simppccard_attach_card(device_t dev)
13852506Simp{
13964850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
14052506Simp	struct pccard_function *pf;
14165917Simp	struct pccard_ivar *ivar;
14261788Simp	device_t child;
14352506Simp
14452506Simp	/*
14552506Simp	 * this is here so that when socket_enable calls gettype, trt happens
14652506Simp	 */
14752506Simp	STAILQ_INIT(&sc->card.pf_head);
14852506Simp
14955500Simp	DEVPRINTF((dev, "chip_socket_enable\n"));
15055500Simp	POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
15152506Simp
15255500Simp	DEVPRINTF((dev, "read_cis\n"));
15352506Simp	pccard_read_cis(sc);
15452506Simp
15555500Simp	DEVPRINTF((dev, "check_cis_quirks\n"));
15652506Simp	pccard_check_cis_quirks(dev);
15752506Simp
15852506Simp	/*
15952506Simp	 * bail now if the card has no functions, or if there was an error in
16052506Simp	 * the cis.
16152506Simp	 */
16252506Simp
16370715Sjon	if (sc->card.error) {
16470715Sjon		device_printf (dev, "CARD ERROR!\n");
16552506Simp		return (1);
16670715Sjon	}
16770715Sjon	if (STAILQ_EMPTY(&sc->card.pf_head)) {
16870715Sjon		device_printf (dev, "Card has no functions!\n");
16952506Simp		return (1);
17070715Sjon	}
17152506Simp
17261788Simp	if (1)
17352506Simp		pccard_print_cis(dev);
17452506Simp
17555500Simp	DEVPRINTF((dev, "functions scanning\n"));
17652506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
17752506Simp		if (STAILQ_EMPTY(&pf->cfe_head))
17852506Simp			continue;
17952506Simp
18052506Simp		pf->sc = sc;
18152506Simp		pf->cfe = NULL;
18264927Simp		pf->dev = NULL;
18352506Simp	}
18482378Sjon
18552506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
18652506Simp		if (STAILQ_EMPTY(&pf->cfe_head))
18752506Simp			continue;
18861788Simp		/*
18961788Simp		 * In NetBSD, the drivers are responsible for activating
19061788Simp		 * each function of a card.  I think that in FreeBSD we
19161788Simp		 * want to activate them enough for the usual bus_*_resource
19261788Simp		 * routines will do the right thing.  This many mean a
19361788Simp		 * departure from the current NetBSD model.
19461788Simp		 *
19561788Simp		 * This could get really ugly for multifunction cards.  But
19661788Simp		 * it might also just fall out of the FreeBSD resource model.
19761788Simp		 *
19861788Simp		 */
19967897Sdwmalone		ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF,
20067897Sdwmalone		    M_WAITOK | M_ZERO);
20161788Simp		child = device_add_child(dev, NULL, -1);
20265917Simp		device_set_ivars(child, ivar);
20366847Simp		ivar->fcn = pf;
20467187Simp		pf->dev = child;
20567167Simp		/*
20667167Simp		 * XXX We might want to move the next two lines into
20767167Simp		 * XXX the pccard interface layer.  For the moment, this
20867167Simp		 * XXX is OK, but some drivers want to pick the config
20967167Simp		 * XXX entry to use as well as some address tweaks (mostly
21067167Simp		 * XXX due to bugs in decode logic that makes some
21167167Simp		 * XXX addresses illegal or broken).
21267167Simp		 */
21365917Simp		pccard_function_init(pf);
21482378Sjon		if (sc->sc_enabled_count == 0)
21582378Sjon			POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
21667333Simp		if (pccard_function_enable(pf) == 0 &&
21767333Simp		    device_probe_and_attach(child) == 0) {
21855500Simp			DEVPRINTF((sc->dev, "function %d CCR at %d "
21967167Simp			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
22067167Simp			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
22167167Simp			    pccard_ccr_read(pf, 0x00),
22252506Simp			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
22352506Simp			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
22452506Simp			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
22552506Simp			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
22667167Simp		} else {
22782378Sjon			pccard_function_disable(pf);
22852506Simp		}
22952506Simp	}
23082378Sjon	if (sc->sc_enabled_count == 0)
23182378Sjon		pccard_detach_card(dev, 0);
23274632Simp	return (0);
23352506Simp}
23452506Simp
23559193Simpstatic int
23659193Simppccard_detach_card(device_t dev, int flags)
23752506Simp{
23864850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
23952506Simp	struct pccard_function *pf;
24082378Sjon	struct pccard_config_entry *cfe;
24152506Simp
24252506Simp	/*
24352506Simp	 * We are running on either the PCCARD socket's event thread
24452506Simp	 * or in user context detaching a device by user request.
24552506Simp	 */
24652506Simp	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
24782378Sjon		int state = device_get_state(pf->dev);
24861788Simp
24982378Sjon		if (state == DS_ATTACHED || state == DS_BUSY)
25082378Sjon			device_detach(pf->dev);
25161788Simp		pccard_function_disable(pf);
25282378Sjon		pccard_function_free(pf);
25376424Simp		if (pf->dev != NULL)
25464927Simp			device_delete_child(dev, pf->dev);
25552506Simp	}
25682378Sjon	if (sc->sc_enabled_count == 0)
25782378Sjon		POWER_DISABLE_SOCKET(device_get_parent(dev), dev);
25882378Sjon
25982378Sjon	while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) {
26082378Sjon		while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) {
26182378Sjon			STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list);
26282378Sjon			free(cfe, M_DEVBUF);
26382378Sjon		}
26482378Sjon		STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list);
26582378Sjon		free(pf, M_DEVBUF);
26682378Sjon	}
26774632Simp	return (0);
26852506Simp}
26952506Simp
27082378Sjonstatic const struct pccard_product *
27166200Simppccard_product_lookup(device_t dev, const struct pccard_product *tab,
27266200Simp    size_t ent_size, pccard_product_match_fn matchfn)
27366200Simp{
27466200Simp	const struct pccard_product *ent;
27566200Simp	int matches;
27666200Simp	u_int32_t fcn;
27766200Simp	u_int32_t vendor;
27866200Simp	u_int32_t prod;
27966200Simp	char *vendorstr;
28066200Simp	char *prodstr;
28166200Simp
28266200Simp#ifdef DIAGNOSTIC
28366200Simp	if (sizeof *ent > ent_size)
28470715Sjon		panic("pccard_product_lookup: bogus ent_size %ld",
28566200Simp		    (long) ent_size);
28666200Simp#endif
28766200Simp	if (pccard_get_vendor(dev, &vendor))
28866200Simp		return (NULL);
28966200Simp	if (pccard_get_product(dev, &prod))
29066200Simp		return (NULL);
29166200Simp	if (pccard_get_function_number(dev, &fcn))
29266200Simp		return (NULL);
29366200Simp	if (pccard_get_vendor_str(dev, &vendorstr))
29466200Simp		return (NULL);
29566200Simp	if (pccard_get_product_str(dev, &prodstr))
29666200Simp		return (NULL);
29782378Sjon	for (ent = tab; ent->pp_name != NULL; ent =
29882378Sjon	    (const struct pccard_product *) ((const char *) ent + ent_size)) {
29966200Simp		matches = 1;
30066200Simp		if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY &&
30166200Simp		    vendor != ent->pp_vendor)
30266200Simp			matches = 0;
30366200Simp		if (matches && ent->pp_product != PCCARD_PRODUCT_ANY &&
30466200Simp		    prod != ent->pp_product)
30566200Simp			matches = 0;
30666200Simp		if (matches && fcn != ent->pp_expfunc)
30766200Simp			matches = 0;
30871322Simp		if (matches && ent->pp_cis[0] &&
30971322Simp		    strcmp(ent->pp_cis[0], vendorstr) != 0)
31066200Simp			matches = 0;
31171322Simp		if (matches && ent->pp_cis[1] &&
31271322Simp		    strcmp(ent->pp_cis[1], prodstr) != 0)
31366200Simp			matches = 0;
31471322Simp		/* XXX need to match cis[2] and cis[3] also XXX */
31566200Simp		if (matchfn != NULL)
31666200Simp			matches = (*matchfn)(dev, ent, matches);
31766200Simp		if (matches)
31866200Simp			return (ent);
31966200Simp	}
32066200Simp	return (NULL);
32166200Simp}
32266200Simp
32370715Sjonstatic int
32459193Simppccard_card_gettype(device_t dev, int *type)
32552506Simp{
32664850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
32752506Simp	struct pccard_function *pf;
32852506Simp
32952506Simp	/*
33052506Simp	 * set the iftype to memory if this card has no functions (not yet
33152506Simp	 * probed), or only one function, and that is not initialized yet or
33252506Simp	 * that is memory.
33352506Simp	 */
33452506Simp	pf = STAILQ_FIRST(&sc->card.pf_head);
33552506Simp	if (pf == NULL ||
33652506Simp	    (STAILQ_NEXT(pf, pf_list) == NULL &&
33752506Simp	    (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY)))
33859193Simp		*type = PCCARD_IFTYPE_MEMORY;
33952506Simp	else
34059193Simp		*type = PCCARD_IFTYPE_IO;
34174632Simp	return (0);
34252506Simp}
34352506Simp
34452506Simp/*
34552506Simp * Initialize a PCCARD function.  May be called as long as the function is
34652506Simp * disabled.
34782382Simp *
34882382Simp * Note: pccard_function_init should not keep resources allocated.  It should
34982382Simp * only set them up ala isa pnp, set the values in the rl lists, and return.
35082382Simp * Any resource held after pccard_function_init is called is a bug.  However,
35182382Simp * the bus routines to get the resources also assume that pccard_function_init
35282382Simp * does this, so they need to be fixed too.
35352506Simp */
35482378Sjonstatic void
35570715Sjonpccard_function_init(struct pccard_function *pf)
35652506Simp{
35765917Simp	struct pccard_config_entry *cfe;
35867187Simp	int i;
35967242Simp	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
36067242Simp	struct resource_list *rl = &devi->resources;
36170762Simp	struct resource_list_entry *rle;
36267242Simp	struct resource *r = 0;
36367242Simp	device_t bus;
36467424Simp	int start;
36567424Simp	int end;
36665917Simp
36770715Sjon	if (pf->pf_flags & PFF_ENABLED) {
36870715Sjon		printf("pccard_function_init: function is enabled");
36970715Sjon		return;
37070715Sjon	}
37167242Simp	bus = device_get_parent(pf->dev);
37252506Simp	/* Remember which configuration entry we are using. */
37372012Sphk	STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
37467187Simp		for (i = 0; i < cfe->num_iospace; i++)
37567187Simp			cfe->iores[i] = NULL;
37667187Simp		cfe->irqres = NULL;
37767187Simp		for (i = 0; i < cfe->num_iospace; i++) {
37867424Simp			start = cfe->iospace[i].start;
37967424Simp			if (start)
38067424Simp				end = start + cfe->iospace[i].length - 1;
38167424Simp			else
38267424Simp				end = ~0;
38367187Simp			cfe->iorid[i] = i;
38467242Simp			r = cfe->iores[i] = bus_alloc_resource(bus,
38567424Simp			    SYS_RES_IOPORT, &cfe->iorid[i], start, end,
38670715Sjon			    cfe->iospace[i].length,
38767424Simp			    rman_make_alignment_flags(cfe->iospace[i].length));
38876424Simp			if (cfe->iores[i] == NULL)
38967187Simp				goto not_this_one;
39067242Simp			resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i],
39167242Simp			    rman_get_start(r), rman_get_end(r),
39267242Simp			    cfe->iospace[i].length);
39376424Simp			rle = resource_list_find(rl, SYS_RES_IOPORT,
39476424Simp			    cfe->iorid[i]);
39576424Simp			rle->res = r;
39667187Simp		}
39767187Simp		if (cfe->num_memspace > 0) {
39867187Simp			goto not_this_one;
39967187Simp		}
40067187Simp		if (cfe->irqmask) {
40167187Simp			cfe->irqrid = 0;
40267399Simp			r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ,
40367424Simp			    &cfe->irqrid, 0, ~0, 1, 0);
40476424Simp			if (cfe->irqres == NULL)
40567187Simp				goto not_this_one;
40667242Simp			resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid,
40767242Simp			    rman_get_start(r), rman_get_end(r), 1);
40876424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
40976424Simp			    cfe->irqrid);
41076424Simp			rle->res = r;
41167187Simp		}
41267187Simp		/* If we get to here, we've allocated all we need */
41367167Simp		pf->cfe = cfe;
41467187Simp		break;
41567187Simp	    not_this_one:;
41667424Simp		DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n",
41767424Simp		    cfe->number));
41867333Simp		/*
41967333Simp		 * Release resources that we partially allocated
42067333Simp		 * from this config entry.
42167333Simp		 */
42267187Simp		for (i = 0; i < cfe->num_iospace; i++) {
42376424Simp			if (cfe->iores[i] != NULL) {
42470715Sjon				bus_release_resource(bus, SYS_RES_IOPORT,
42567187Simp				    cfe->iorid[i], cfe->iores[i]);
42682378Sjon				rle = resource_list_find(rl, SYS_RES_IOPORT,
42776424Simp				    cfe->iorid[i]);
42876424Simp				rle->res = NULL;
42976424Simp				resource_list_delete(rl, SYS_RES_IOPORT,
43076424Simp				    cfe->iorid[i]);
43175756Simp			}
43267187Simp			cfe->iores[i] = NULL;
43367187Simp		}
43476424Simp		if (cfe->irqmask && cfe->irqres != NULL) {
43567242Simp			bus_release_resource(bus, SYS_RES_IRQ,
43667187Simp			    cfe->irqrid, cfe->irqres);
43776424Simp			rle = resource_list_find(rl, SYS_RES_IRQ,
43876424Simp			    cfe->irqrid);
43976424Simp			rle->res = NULL;
44076424Simp			resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid);
44167187Simp			cfe->irqres = NULL;
44267187Simp		}
44367167Simp	}
44452506Simp}
44552506Simp
44682378Sjon/*
44782378Sjon * Free resources allocated by pccard_function_init(), May be called as long
44882378Sjon * as the function is disabled.
44982382Simp *
45082382Simp * NOTE: This function should be unnecessary.  pccard_function_init should
45182382Simp * never keep resources initialized.
45282378Sjon */
45382378Sjonstatic void
45482378Sjonpccard_function_free(struct pccard_function *pf)
45582378Sjon{
45682378Sjon	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
45782378Sjon	struct resource_list_entry *rle;
45882378Sjon
45982378Sjon	if (pf->pf_flags & PFF_ENABLED) {
46082378Sjon		printf("pccard_function_init: function is enabled");
46182378Sjon		return;
46282378Sjon	}
46382378Sjon
46482378Sjon	SLIST_FOREACH(rle, &devi->resources, link) {
46582378Sjon		if (rle->res) {
46682378Sjon			if (rle->res->r_dev != pf->sc->dev)
46782378Sjon				device_printf(pf->sc->dev,
46882378Sjon				    "function_free: Resource still owned by "
46982378Sjon				    "child, oops. "
47082378Sjon				    "(type=%d, rid=%d, addr=%lx)\n",
47182378Sjon				    rle->type, rle->rid,
47282378Sjon				    rman_get_start(rle->res));
47382378Sjon			BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
47482378Sjon			    rle->res->r_dev, rle->type, rle->rid, rle->res);
47582378Sjon			rle->res = NULL;
47682378Sjon		}
47782378Sjon	}
47882378Sjon	resource_list_free(&devi->resources);
47982378Sjon}
48082378Sjon
48152506Simp/* Enable a PCCARD function */
48282378Sjonstatic int
48355720Simppccard_function_enable(struct pccard_function *pf)
48452506Simp{
48552506Simp	struct pccard_function *tmp;
48652506Simp	int reg;
48755720Simp	device_t dev = pf->sc->dev;
48870746Simp
48967333Simp	if (pf->cfe == NULL) {
49067333Simp		DEVPRVERBOSE((dev, "No config entry could be allocated.\n"));
49174632Simp		return (ENOMEM);
49267333Simp	}
49352506Simp
49452506Simp	/*
49552506Simp	 * Increase the reference count on the socket, enabling power, if
49652506Simp	 * necessary.
49752506Simp	 */
49882378Sjon	pf->sc->sc_enabled_count++;
49952506Simp
50052506Simp	if (pf->pf_flags & PFF_ENABLED) {
50152506Simp		/*
50252506Simp		 * Don't do anything if we're already enabled.
50352506Simp		 */
50452506Simp		return (0);
50552506Simp	}
50652506Simp
50752506Simp	/*
50852506Simp	 * it's possible for different functions' CCRs to be in the same
50952506Simp	 * underlying page.  Check for that.
51052506Simp	 */
51152506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
51252506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
51352506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
51452506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
51582378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
51682378Sjon		    tmp->pf_ccr_realsize))) {
51752506Simp			pf->pf_ccrt = tmp->pf_ccrt;
51852506Simp			pf->pf_ccrh = tmp->pf_ccrh;
51952506Simp			pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
52052506Simp
52152506Simp			/*
52252506Simp			 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
52352506Simp			 * tmp->ccr_base) + pf->ccr_base;
52452506Simp			 */
52570715Sjon			/* pf->pf_ccr_offset =
52652506Simp			    (tmp->pf_ccr_offset + pf->ccr_base) -
52770715Sjon			    tmp->ccr_base; */
52852506Simp			pf->pf_ccr_window = tmp->pf_ccr_window;
52952506Simp			break;
53052506Simp		}
53152506Simp	}
53252506Simp	if (tmp == NULL) {
53355720Simp		pf->ccr_rid = 0;
53455720Simp		pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
53570715Sjon		    &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE);
53670715Sjon		if (!pf->ccr_res)
53752506Simp			goto bad;
53870746Simp		DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%lx\n",
53970746Simp		    rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res),
54070746Simp		    pf->ccr_base));
54161788Simp		CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
54261788Simp		    pf->ccr_rid, PCCARD_A_MEM_ATTR);
54370715Sjon		CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev,
54470748Simp		    pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset);
54555720Simp		pf->pf_ccrt = rman_get_bustag(pf->ccr_res);
54655720Simp		pf->pf_ccrh = rman_get_bushandle(pf->ccr_res);
54755720Simp		pf->pf_ccr_realsize = 1;
54852506Simp	}
54952506Simp
55052506Simp	reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX);
55152506Simp	reg |= PCCARD_CCR_OPTION_LEVIREQ;
55252506Simp	if (pccard_mfc(pf->sc)) {
55352506Simp		reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE |
55452506Simp			PCCARD_CCR_OPTION_ADDR_DECODE);
55570715Sjon		/*
55667167Simp		 * XXX Need to enable PCCARD_CCR_OPTION_IRQ_ENABLE if
55767167Simp		 * XXX we have an interrupt handler, but we don't know that
55867167Simp		 * XXX at this point.
55967167Simp		 */
56070715Sjon/*		reg |= PCCARD_CCR_OPTION_IREQ_ENABLE;*/
56152506Simp	}
56252506Simp	pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
56352506Simp
56452506Simp	reg = 0;
56552506Simp	if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0)
56652506Simp		reg |= PCCARD_CCR_STATUS_IOIS8;
56752506Simp	if (pf->cfe->flags & PCCARD_CFE_AUDIO)
56852506Simp		reg |= PCCARD_CCR_STATUS_AUDIO;
56952506Simp	pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg);
57052506Simp
57152506Simp	pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0);
57252506Simp
57352506Simp	if (pccard_mfc(pf->sc)) {
57452506Simp		long tmp, iosize;
57552506Simp
57652506Simp		tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
57752506Simp		/* round up to nearest (2^n)-1 */
57852506Simp		for (iosize = 1; iosize < tmp; iosize <<= 1)
57952506Simp			;
58052506Simp		iosize--;
58152506Simp
58252506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
58352506Simp				 pf->pf_mfc_iobase & 0xff);
58452506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
58552506Simp				 (pf->pf_mfc_iobase >> 8) & 0xff);
58652506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
58752506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
58852506Simp
58952506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
59052506Simp	}
59152506Simp
59252506Simp#ifdef PCCARDDEBUG
59352506Simp	if (pccard_debug) {
59452506Simp		STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
59570715Sjon			device_printf(tmp->sc->dev,
59655500Simp			    "function %d CCR at %d offset %x: "
59755500Simp			    "%x %x %x %x, %x %x %x %x, %x\n",
59870715Sjon			    tmp->number, tmp->pf_ccr_window,
59955500Simp			    tmp->pf_ccr_offset,
60055500Simp			    pccard_ccr_read(tmp, 0x00),
60155500Simp			    pccard_ccr_read(tmp, 0x02),
60255500Simp			    pccard_ccr_read(tmp, 0x04),
60355500Simp			    pccard_ccr_read(tmp, 0x06),
60455500Simp			    pccard_ccr_read(tmp, 0x0A),
60570715Sjon			    pccard_ccr_read(tmp, 0x0C),
60655500Simp			    pccard_ccr_read(tmp, 0x0E),
60755500Simp			    pccard_ccr_read(tmp, 0x10),
60855500Simp			    pccard_ccr_read(tmp, 0x12));
60952506Simp		}
61052506Simp	}
61152506Simp#endif
61252506Simp	pf->pf_flags |= PFF_ENABLED;
61352506Simp	return (0);
61452506Simp
61552506Simp bad:
61652506Simp	/*
61752506Simp	 * Decrement the reference count, and power down the socket, if
61852506Simp	 * necessary.
61952506Simp	 */
62082378Sjon	pf->sc->sc_enabled_count--;
62165098Simp	DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count));
62252506Simp
62352506Simp	return (1);
62452506Simp}
62552506Simp
62652506Simp/* Disable PCCARD function. */
62782378Sjonstatic void
62855720Simppccard_function_disable(struct pccard_function *pf)
62952506Simp{
63052506Simp	struct pccard_function *tmp;
63155720Simp	device_t dev = pf->sc->dev;
63252506Simp
63352506Simp	if (pf->cfe == NULL)
63461788Simp		panic("pccard_function_disable: function not initialized");
63552506Simp
63652506Simp	if ((pf->pf_flags & PFF_ENABLED) == 0) {
63752506Simp		/*
63852506Simp		 * Don't do anything if we're already disabled.
63952506Simp		 */
64052506Simp		return;
64152506Simp	}
64252506Simp
64370715Sjon	if (pf->intr_handler != NULL) {
64482378Sjon		struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
64582378Sjon		struct resource_list_entry *rle =
64682378Sjon		    resource_list_find(&devi->resources, SYS_RES_IRQ, 0);
64782378Sjon		BUS_TEARDOWN_INTR(dev, pf->dev, rle->res,
64882378Sjon		    pf->intr_handler_cookie);
64970715Sjon	}
65070715Sjon
65152506Simp	/*
65252506Simp	 * it's possible for different functions' CCRs to be in the same
65352506Simp	 * underlying page.  Check for that.  Note we mark us as disabled
65452506Simp	 * first to avoid matching ourself.
65552506Simp	 */
65652506Simp
65752506Simp	pf->pf_flags &= ~PFF_ENABLED;
65852506Simp	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
65952506Simp		if ((tmp->pf_flags & PFF_ENABLED) &&
66052506Simp		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
66152506Simp		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
66282378Sjon		    (tmp->ccr_base - tmp->pf_ccr_offset +
66382378Sjon		    tmp->pf_ccr_realsize)))
66452506Simp			break;
66552506Simp	}
66652506Simp
66752506Simp	/* Not used by anyone else; unmap the CCR. */
66852506Simp	if (tmp == NULL) {
66970715Sjon		bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid,
67055720Simp		    pf->ccr_res);
67155720Simp		pf->ccr_res = NULL;
67252506Simp	}
67352506Simp
67452506Simp	/*
67552506Simp	 * Decrement the reference count, and power down the socket, if
67652506Simp	 * necessary.
67752506Simp	 */
67882378Sjon	pf->sc->sc_enabled_count--;
67952506Simp}
68052506Simp
68155720Simp#if 0
68255720Simp/* XXX These functions are needed, but not like this XXX */
68352506Simpint
68455720Simppccard_io_map(struct pccard_function *pf, int width, bus_addr_t offset,
68555720Simp    bus_size_t size, struct pccard_io_handle *pcihp, int *windowp)
68652506Simp{
68752506Simp	int reg;
68852506Simp
68967167Simp	if (pccard_chip_io_map(pf->sc->pct, pf->sc->pch, width, offset, size,
69067167Simp	    pcihp, windowp))
69152506Simp		return (1);
69252506Simp
69352506Simp	/*
69452506Simp	 * XXX in the multifunction multi-iospace-per-function case, this
69552506Simp	 * needs to cooperate with io_alloc to make sure that the spaces
69652506Simp	 * don't overlap, and that the ccr's are set correctly
69752506Simp	 */
69852506Simp
69952506Simp	if (pccard_mfc(pf->sc)) {
70052506Simp		long tmp, iosize;
70152506Simp
70252506Simp		if (pf->pf_mfc_iomax == 0) {
70352506Simp			pf->pf_mfc_iobase = pcihp->addr + offset;
70452506Simp			pf->pf_mfc_iomax = pf->pf_mfc_iobase + size;
70552506Simp		} else {
70652506Simp			/* this makes the assumption that nothing overlaps */
70752506Simp			if (pf->pf_mfc_iobase > pcihp->addr + offset)
70852506Simp				pf->pf_mfc_iobase = pcihp->addr + offset;
70952506Simp			if (pf->pf_mfc_iomax < pcihp->addr + offset + size)
71052506Simp				pf->pf_mfc_iomax = pcihp->addr + offset + size;
71152506Simp		}
71252506Simp
71352506Simp		tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
71452506Simp		/* round up to nearest (2^n)-1 */
71552506Simp		for (iosize = 1; iosize >= tmp; iosize <<= 1)
71652506Simp			;
71752506Simp		iosize--;
71852506Simp
71970715Sjon		pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
72055720Simp		    pf->pf_mfc_iobase & 0xff);
72152506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
72255720Simp		    (pf->pf_mfc_iobase >> 8) & 0xff);
72352506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
72452506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
72552506Simp
72652506Simp		pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
72752506Simp
72852506Simp		reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION);
72952506Simp		reg |= PCCARD_CCR_OPTION_ADDR_DECODE;
73052506Simp		pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
73152506Simp	}
73252506Simp	return (0);
73352506Simp}
73452506Simp
73552506Simpvoid
73655720Simppccard_io_unmap(struct pccard_function *pf, int window)
73752506Simp{
73852506Simp
73952506Simp	pccard_chip_io_unmap(pf->sc->pct, pf->sc->pch, window);
74052506Simp
74152506Simp	/* XXX Anything for multi-function cards? */
74252506Simp}
74352506Simp#endif
74452506Simp
74566058Simp/*
74666058Simp * simulate the old "probe" routine.  In the new world order, the driver
74766058Simp * needs to grab devices while in the old they were assigned to the device by
74866058Simp * the pccardd process.  These symbols are exported to the upper layers.
74966058Simp */
75074636Simpstatic int
75174636Simppccard_compat_do_probe(device_t bus, device_t dev)
75266058Simp{
75366058Simp	return (CARD_COMPAT_MATCH(dev));
75466058Simp}
75566058Simp
75674636Simpstatic int
75774636Simppccard_compat_do_attach(device_t bus, device_t dev)
75866058Simp{
75966058Simp	int err;
76066058Simp
76166058Simp	err = CARD_COMPAT_PROBE(dev);
76266058Simp	if (err == 0)
76366058Simp		err = CARD_COMPAT_ATTACH(dev);
76466058Simp	return (err);
76566058Simp}
76666058Simp
76753873Simp#define PCCARD_NPORT	2
76853873Simp#define PCCARD_NMEM	5
76953873Simp#define PCCARD_NIRQ	1
77053873Simp#define PCCARD_NDRQ	0
77153873Simp
77252506Simpstatic int
77352506Simppccard_add_children(device_t dev, int busno)
77452506Simp{
77559193Simp	/* Call parent to scan for any current children */
77674632Simp	return (0);
77752506Simp}
77852506Simp
77952506Simpstatic int
78052506Simppccard_probe(device_t dev)
78152506Simp{
78267333Simp	device_set_desc(dev, "16-bit PCCard bus");
78374632Simp	return (pccard_add_children(dev, device_get_unit(dev)));
78452506Simp}
78552506Simp
78659193Simpstatic int
78759193Simppccard_attach(device_t dev)
78859193Simp{
78964850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
79061788Simp
79159193Simp	sc->dev = dev;
79261788Simp	sc->sc_enabled_count = 0;
79374632Simp	return (bus_generic_attach(dev));
79459193Simp}
79559193Simp
79682378Sjonstatic int
79782378Sjonpccard_detach(device_t dev)
79882378Sjon{
79982378Sjon	pccard_detach_card(dev, 0);
80082378Sjon	return 0;
80182378Sjon}
80282378Sjon
80353873Simpstatic void
80453873Simppccard_print_resources(struct resource_list *rl, const char *name, int type,
80553873Simp    int count, const char *format)
80653873Simp{
80753873Simp	struct resource_list_entry *rle;
80853873Simp	int printed;
80953873Simp	int i;
81053873Simp
81153873Simp	printed = 0;
81253873Simp	for (i = 0; i < count; i++) {
81353873Simp		rle = resource_list_find(rl, type, i);
81476424Simp		if (rle != NULL) {
81553873Simp			if (printed == 0)
81653873Simp				printf(" %s ", name);
81753873Simp			else if (printed > 0)
81853873Simp				printf(",");
81953873Simp			printed++;
82053873Simp			printf(format, rle->start);
82153873Simp			if (rle->count > 1) {
82253873Simp				printf("-");
82353873Simp				printf(format, rle->start + rle->count - 1);
82453873Simp			}
82553873Simp		} else if (i > 3) {
82653873Simp			/* check the first few regardless */
82753873Simp			break;
82853873Simp		}
82953873Simp	}
83053873Simp}
83153873Simp
83253873Simpstatic int
83353873Simppccard_print_child(device_t dev, device_t child)
83453873Simp{
83566847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
83653873Simp	struct resource_list *rl = &devi->resources;
83753873Simp	int retval = 0;
83853873Simp
83953873Simp	retval += bus_print_child_header(dev, child);
84053873Simp	retval += printf(" at");
84153873Simp
84276424Simp	if (devi != NULL) {
84353873Simp		pccard_print_resources(rl, "port", SYS_RES_IOPORT,
84453873Simp		    PCCARD_NPORT, "%#lx");
84553873Simp		pccard_print_resources(rl, "iomem", SYS_RES_MEMORY,
84653873Simp		    PCCARD_NMEM, "%#lx");
84753873Simp		pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ,
84853873Simp		    "%ld");
84970715Sjon		pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ,
85053873Simp		    "%ld");
85167269Simp		retval += printf(" function %d config %d", devi->fcn->number,
85267269Simp		    devi->fcn->cfe->number);
85353873Simp	}
85453873Simp
85553873Simp	retval += bus_print_child_footer(dev, child);
85653873Simp
85753873Simp	return (retval);
85853873Simp}
85953873Simp
86053873Simpstatic int
86153873Simppccard_set_resource(device_t dev, device_t child, int type, int rid,
86253873Simp		 u_long start, u_long count)
86353873Simp{
86466847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
86553873Simp	struct resource_list *rl = &devi->resources;
86653873Simp
86753873Simp	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
86853873Simp	    && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
86974632Simp		return (EINVAL);
87053873Simp	if (rid < 0)
87174632Simp		return (EINVAL);
87253873Simp	if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT)
87374632Simp		return (EINVAL);
87453873Simp	if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM)
87574632Simp		return (EINVAL);
87653873Simp	if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ)
87774632Simp		return (EINVAL);
87853873Simp	if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ)
87974632Simp		return (EINVAL);
88053873Simp
88153873Simp	resource_list_add(rl, type, rid, start, start + count - 1, count);
88282378Sjon	if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev,
88382378Sjon	    type, &rid, start, start + count - 1, count, 0))
88482378Sjon		return 0;
88582378Sjon	else
88682378Sjon		return ENOMEM;
88753873Simp}
88853873Simp
88953873Simpstatic int
89053873Simppccard_get_resource(device_t dev, device_t child, int type, int rid,
89153873Simp    u_long *startp, u_long *countp)
89253873Simp{
89366847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
89453873Simp	struct resource_list *rl = &devi->resources;
89553873Simp	struct resource_list_entry *rle;
89653873Simp
89753873Simp	rle = resource_list_find(rl, type, rid);
89876424Simp	if (rle == NULL)
89974632Simp		return (ENOENT);
90070715Sjon
90176424Simp	if (startp != NULL)
90253873Simp		*startp = rle->start;
90376424Simp	if (countp != NULL)
90453873Simp		*countp = rle->count;
90553873Simp
90674632Simp	return (0);
90753873Simp}
90853873Simp
90953873Simpstatic void
91053873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid)
91153873Simp{
91266847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
91353873Simp	struct resource_list *rl = &devi->resources;
91453873Simp	resource_list_delete(rl, type, rid);
91553873Simp}
91653873Simp
91759193Simpstatic int
91859193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid,
91959193Simp    u_int32_t flags)
92059193Simp{
92174632Simp	return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type,
92274632Simp	    rid, flags));
92359193Simp}
92459193Simp
92559193Simpstatic int
92659193Simppccard_set_memory_offset(device_t dev, device_t child, int rid,
92782378Sjon    u_int32_t offset, u_int32_t *deltap)
92870715Sjon
92959193Simp{
93074632Simp	return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid,
93174632Simp	    offset, deltap));
93259193Simp}
93359193Simp
93466058Simpstatic int
93566058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result)
93666058Simp{
93766847Simp	struct pccard_ivar *devi = PCCARD_IVAR(child);
93866779Simp	struct pccard_function *func = devi->fcn;
93966779Simp	struct pccard_softc *sc = PCCARD_SOFTC(bus);
94066779Simp
94166058Simp	/* PCCARD_IVAR_ETHADDR unhandled from oldcard */
94266779Simp	switch (which) {
94366779Simp	default:
94466779Simp	case PCCARD_IVAR_ETHADDR:
94566779Simp		return (ENOENT);
94666779Simp		break;
94766779Simp	case PCCARD_IVAR_VENDOR:
94866779Simp		*(u_int32_t *) result = sc->card.manufacturer;
94966779Simp		break;
95066779Simp	case PCCARD_IVAR_PRODUCT:
95166779Simp		*(u_int32_t *) result = sc->card.product;
95266779Simp		break;
95375761Simp	case PCCARD_IVAR_FUNCTION:
95475761Simp		*(u_int32_t *) result = func->function;
95575761Simp		break;
95666779Simp	case PCCARD_IVAR_FUNCTION_NUMBER:
95766847Simp		if (!func) {
95866847Simp			device_printf(bus, "No function number, bug!\n");
95966847Simp			return (ENOENT);
96066847Simp		}
96166847Simp		*(u_int32_t *) result = func->number;
96266779Simp		break;
96366779Simp	case PCCARD_IVAR_VENDOR_STR:
96466779Simp		*(char **) result = sc->card.cis1_info[0];
96566779Simp		break;
96666779Simp	case PCCARD_IVAR_PRODUCT_STR:
96766779Simp		*(char **) result = sc->card.cis1_info[1];
96866779Simp		break;
96966779Simp	case PCCARD_IVAR_CIS3_STR:
97066779Simp		*(char **) result = sc->card.cis1_info[2];
97166779Simp		break;
97267167Simp	case PCCARD_IVAR_CIS4_STR:
97367167Simp		*(char **) result = sc->card.cis1_info[2];
97467167Simp		break;
97566779Simp	}
97666779Simp	return (0);
97766058Simp}
97866058Simp
97966779Simpstatic void
98066779Simppccard_driver_added(device_t dev, driver_t *driver)
98166779Simp{
98282378Sjon	struct pccard_softc *sc = PCCARD_SOFTC(dev);
98382378Sjon	struct pccard_function *pf;
98482378Sjon	device_t child;
98582378Sjon
98682378Sjon	if (sc->sc_enabled_count == 0) {
98782378Sjon		CARD_REPROBE_CARD(device_get_parent(dev), dev);
98882378Sjon		return;
98982378Sjon	}
99082378Sjon
99182378Sjon	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
99282378Sjon		if (STAILQ_EMPTY(&pf->cfe_head))
99382378Sjon			continue;
99482378Sjon		child = pf->dev;
99582378Sjon		if (device_get_state(child) != DS_NOTPRESENT)
99682378Sjon			continue;
99782378Sjon		if (pccard_function_enable(pf) == 0 &&
99882378Sjon		    device_probe_and_attach(child) == 0) {
99982378Sjon			DEVPRINTF((sc->dev, "function %d CCR at %d "
100082378Sjon			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
100182378Sjon			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
100282378Sjon			    pccard_ccr_read(pf, 0x00),
100382378Sjon			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
100482378Sjon			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
100582378Sjon			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
100682378Sjon			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
100782378Sjon		} else {
100882378Sjon			pccard_function_disable(pf);
100982378Sjon		}
101082378Sjon	}
101182378Sjon	return;
101266779Simp}
101366058Simp
101467242Simpstatic struct resource *
101567242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid,
101667242Simp    u_long start, u_long end, u_long count, u_int flags)
101767242Simp{
101882378Sjon	struct pccard_ivar *dinfo;
101982378Sjon	struct resource_list_entry *rle = 0;
102082378Sjon	int passthrough = (device_get_parent(child) != dev);
102167242Simp
102282378Sjon	if (passthrough) {
102382378Sjon		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
102482378Sjon		    type, rid, start, end, count, flags));
102582378Sjon	}
102670715Sjon
102782378Sjon	dinfo = device_get_ivars(child);
102882378Sjon	rle = resource_list_find(&dinfo->resources, type, *rid);
102970715Sjon
103082378Sjon	if (!rle)
103182378Sjon		return NULL;		/* no resource of that type/rid */
103270715Sjon
103382378Sjon	if (!rle->res) {
103482378Sjon		device_printf(dev, "WARNING: Resource not reserved by pccard bus\n");
103582378Sjon		return NULL;
103682378Sjon	} else {
103782378Sjon		if (rle->res->r_dev != dev) return NULL;
103882378Sjon		bus_release_resource(dev, type, *rid, rle->res);
103982378Sjon		rle->res = NULL;
104082378Sjon		switch(type) {
104182378Sjon		case SYS_RES_IOPORT:
104282378Sjon		case SYS_RES_MEMORY:
104382378Sjon			if (!(flags & RF_ALIGNMENT_MASK))
104482378Sjon				flags |= rman_make_alignment_flags(rle->count);
104582378Sjon			break;
104682378Sjon		case SYS_RES_IRQ:
104782378Sjon			flags |= RF_SHAREABLE;
104882378Sjon			break;
104982378Sjon		}
105082378Sjon		return resource_list_alloc(&dinfo->resources, dev, child, type,
105182378Sjon		    rid, rle->start, rle->end, rle->count, flags);
105267269Simp	}
105367242Simp}
105467242Simp
105567242Simpstatic int
105667242Simppccard_release_resource(device_t dev, device_t child, int type, int rid,
105767242Simp    struct resource *r)
105867242Simp{
105982378Sjon	struct pccard_ivar *dinfo;
106082378Sjon	int passthrough = (device_get_parent(child) != dev);
106182378Sjon	struct resource_list_entry *rle = 0;
106282378Sjon	int ret;
106382378Sjon	int flags;
106470715Sjon
106582378Sjon	if (passthrough)
106682378Sjon		return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
106782378Sjon		    type, rid, r);
106870715Sjon
106982378Sjon	dinfo = device_get_ivars(child);
107070715Sjon
107182378Sjon	rle = resource_list_find(&dinfo->resources, type, rid);
107270715Sjon
107382378Sjon	if (!rle) {
107482378Sjon		device_printf(dev, "Allocated resource not found, "
107582378Sjon		    "%d %x %lx %lx\n",
107682378Sjon		    type, rid, rman_get_start(r), rman_get_size(r));
107782378Sjon		return ENOENT;
107870715Sjon	}
107982378Sjon	if (!rle->res) {
108082378Sjon		device_printf(dev, "Allocated resource not recorded\n");
108182378Sjon		return ENOENT;
108270715Sjon	}
108370715Sjon
108482378Sjon	ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
108582378Sjon	    type, rid, r);
108682378Sjon	switch(type) {
108782378Sjon	case SYS_RES_IOPORT:
108882378Sjon	case SYS_RES_MEMORY:
108982378Sjon		flags = rman_make_alignment_flags(rle->count);
109082378Sjon		break;
109182378Sjon	case SYS_RES_IRQ:
109282378Sjon		flags = RF_SHAREABLE;
109382378Sjon		break;
109482378Sjon	default:
109582378Sjon		flags = 0;
109670715Sjon	}
109782378Sjon	rle->res = bus_alloc_resource(dev, type, &rid,
109882378Sjon	    rle->start, rle->end, rle->count, flags);
109982378Sjon	if (rle->res == NULL)
110082378Sjon		device_printf(dev, "release_resource: "
110182378Sjon		    "unable to reaquire resource\n");
110282378Sjon	return ret;
110367242Simp}
110467242Simp
110567333Simpstatic void
110667333Simppccard_child_detached(device_t parent, device_t dev)
110767333Simp{
110867333Simp	struct pccard_ivar *ivar = PCCARD_IVAR(dev);
110982378Sjon	struct pccard_function *pf = ivar->fcn;
111067333Simp
111182378Sjon	pccard_function_disable(pf);
111267333Simp}
111367333Simp
111470715Sjonstatic void
111570762Simppccard_intr(void *arg)
111670762Simp{
111782378Sjon	struct pccard_function *pf = (struct pccard_function*) arg;
111882378Sjon	int reg;
111982378Sjon
112082378Sjon	if (pf->intr_handler == NULL)
112182378Sjon		panic("Null interrupt handler?\n");
112282378Sjon
112382378Sjon	reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
112482378Sjon	if (reg & PCCARD_CCR_STATUS_INTR) {
112582378Sjon		pccard_ccr_write(pf, PCCARD_CCR_STATUS,
112682378Sjon				 reg & ~PCCARD_CCR_STATUS_INTR);
112782378Sjon		pf->intr_handler(pf->intr_handler_arg);
112870715Sjon	}
112970715Sjon}
113070715Sjon
113170715Sjonstatic int
113270762Simppccard_setup_intr(device_t dev, device_t child, struct resource *irq,
113370762Simp    int flags, driver_intr_t *intr, void *arg, void **cookiep)
113470715Sjon{
113570715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
113670715Sjon	struct pccard_function *func = ivar->fcn;
113770715Sjon
113870715Sjon	if (func->intr_handler != NULL)
113970762Simp		panic("Only one interrupt handler per function allowed\n");
114070715Sjon
114170715Sjon	func->intr_handler = intr;
114270715Sjon	func->intr_handler_arg = arg;
114382378Sjon	func->intr_handler_cookie = *cookiep;
114470715Sjon	pccard_ccr_write(func, PCCARD_CCR_OPTION,
114582378Sjon	    pccard_ccr_read(func, PCCARD_CCR_OPTION) |
114670762Simp	    PCCARD_CCR_OPTION_IREQ_ENABLE);
114770715Sjon
114882378Sjon	bus_setup_intr(dev, irq, INTR_TYPE_TTY/* | INTR_FAST*/,
114982378Sjon	    pccard_intr, func, cookiep);
115074632Simp	return (0);
115170715Sjon}
115270715Sjon
115370715Sjonstatic int
115470762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r,
115570762Simp    void *cookie)
115670715Sjon{
115770715Sjon	struct pccard_ivar *ivar = PCCARD_IVAR(child);
115870715Sjon	struct pccard_function *func = ivar->fcn;
115982378Sjon	int ret;
116070715Sjon
116170715Sjon	pccard_ccr_write(func, PCCARD_CCR_OPTION,
116270762Simp	    pccard_ccr_read(func, PCCARD_CCR_OPTION) &
116370762Simp	    ~PCCARD_CCR_OPTION_IREQ_ENABLE);
116470715Sjon
116582378Sjon	ret = bus_teardown_intr(dev, r, cookie);
116682378Sjon	if (ret == 0) {
116782378Sjon		func->intr_handler = NULL;
116882378Sjon		func->intr_handler_arg = NULL;
116982378Sjon		func->intr_handler_cookie = NULL;
117082378Sjon	}
117170715Sjon
117282378Sjon	return (ret);
117370715Sjon}
117470715Sjon
117552506Simpstatic device_method_t pccard_methods[] = {
117652506Simp	/* Device interface */
117752506Simp	DEVMETHOD(device_probe,		pccard_probe),
117859193Simp	DEVMETHOD(device_attach,	pccard_attach),
117982378Sjon	DEVMETHOD(device_detach,	pccard_detach),
118052506Simp	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
118152506Simp	DEVMETHOD(device_suspend,	bus_generic_suspend),
118252506Simp	DEVMETHOD(device_resume,	bus_generic_resume),
118352506Simp
118452506Simp	/* Bus interface */
118552506Simp	DEVMETHOD(bus_print_child,	pccard_print_child),
118666779Simp	DEVMETHOD(bus_driver_added,	pccard_driver_added),
118767333Simp	DEVMETHOD(bus_child_detached,	pccard_child_detached),
118867242Simp	DEVMETHOD(bus_alloc_resource,	pccard_alloc_resource),
118967242Simp	DEVMETHOD(bus_release_resource,	pccard_release_resource),
119082378Sjon	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
119182378Sjon	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
119270715Sjon	DEVMETHOD(bus_setup_intr,	pccard_setup_intr),
119370715Sjon	DEVMETHOD(bus_teardown_intr,	pccard_teardown_intr),
119452506Simp	DEVMETHOD(bus_set_resource,	pccard_set_resource),
119552506Simp	DEVMETHOD(bus_get_resource,	pccard_get_resource),
119652506Simp	DEVMETHOD(bus_delete_resource,	pccard_delete_resource),
119766058Simp	DEVMETHOD(bus_read_ivar,	pccard_read_ivar),
119852506Simp
119959193Simp	/* Card Interface */
120059193Simp	DEVMETHOD(card_set_res_flags,	pccard_set_res_flags),
120159193Simp	DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset),
120259193Simp	DEVMETHOD(card_get_type,	pccard_card_gettype),
120359193Simp	DEVMETHOD(card_attach_card,	pccard_attach_card),
120459193Simp	DEVMETHOD(card_detach_card,	pccard_detach_card),
120574636Simp	DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe),
120674636Simp	DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach),
120759193Simp
120852506Simp	{ 0, 0 }
120952506Simp};
121052506Simp
121152506Simpstatic driver_t pccard_driver = {
121252506Simp	"pccard",
121352506Simp	pccard_methods,
121464850Simp	sizeof(struct pccard_softc)
121552506Simp};
121652506Simp
121752506Simpdevclass_t	pccard_devclass;
121852506Simp
121953873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
122052506SimpDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0);
122152506SimpDRIVER_MODULE(pccard, pccbb, pccard_driver, pccard_devclass, 0, 0);
122253873SimpDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0);
122364927SimpMODULE_VERSION(pccard, 1);
122470715Sjon/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/
1225