pccard.c revision 150362
1/*	$NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $	*/
2
3/*-
4 * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by Marc Horowitz.
17 * 4. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/dev/pccard/pccard.c 150362 2005-09-20 06:47:33Z imp $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/malloc.h>
38#include <sys/module.h>
39#include <sys/kernel.h>
40#include <sys/queue.h>
41#include <sys/sysctl.h>
42#include <sys/types.h>
43
44#include <sys/bus.h>
45#include <machine/bus.h>
46#include <sys/rman.h>
47#include <machine/resource.h>
48
49#include <net/ethernet.h>
50
51#include <dev/pccard/pccardreg.h>
52#include <dev/pccard/pccardvar.h>
53#include <dev/pccard/pccardvarp.h>
54#include <dev/pccard/pccard_cis.h>
55
56#include "power_if.h"
57#include "card_if.h"
58
59#define PCCARDDEBUG
60
61/* sysctl vars */
62SYSCTL_NODE(_hw, OID_AUTO, pccard, CTLFLAG_RD, 0, "PCCARD parameters");
63
64int	pccard_debug = 0;
65TUNABLE_INT("hw.pccard.debug", &pccard_debug);
66SYSCTL_INT(_hw_pccard, OID_AUTO, debug, CTLFLAG_RW,
67    &pccard_debug, 0,
68  "pccard debug");
69
70int	pccard_cis_debug = 0;
71TUNABLE_INT("hw.pccard.cis_debug", &pccard_cis_debug);
72SYSCTL_INT(_hw_pccard, OID_AUTO, cis_debug, CTLFLAG_RW,
73    &pccard_cis_debug, 0, "pccard CIS debug");
74
75#ifdef PCCARDDEBUG
76#define	DPRINTF(arg) if (pccard_debug) printf arg
77#define	DEVPRINTF(arg) if (pccard_debug) device_printf arg
78#define PRVERBOSE(arg) printf arg
79#define DEVPRVERBOSE(arg) device_printf arg
80#else
81#define	DPRINTF(arg)
82#define	DEVPRINTF(arg)
83#define PRVERBOSE(arg) if (bootverbose) printf arg
84#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg
85#endif
86
87static int	pccard_ccr_read(struct pccard_function *pf, int ccr);
88static void	pccard_ccr_write(struct pccard_function *pf, int ccr, int val);
89static int	pccard_attach_card(device_t dev);
90static int	pccard_detach_card(device_t dev);
91static void	pccard_function_init(struct pccard_function *pf);
92static void	pccard_function_free(struct pccard_function *pf);
93static int	pccard_function_enable(struct pccard_function *pf);
94static void	pccard_function_disable(struct pccard_function *pf);
95static int	pccard_compat_do_probe(device_t bus, device_t dev);
96static int	pccard_compat_do_attach(device_t bus, device_t dev);
97static int	pccard_add_children(device_t dev, int busno);
98static int	pccard_probe(device_t dev);
99static int	pccard_attach(device_t dev);
100static int	pccard_detach(device_t dev);
101static void	pccard_print_resources(struct resource_list *rl,
102		    const char *name, int type, int count, const char *format);
103static int	pccard_print_child(device_t dev, device_t child);
104static int	pccard_set_resource(device_t dev, device_t child, int type,
105		    int rid, u_long start, u_long count);
106static int	pccard_get_resource(device_t dev, device_t child, int type,
107		    int rid, u_long *startp, u_long *countp);
108static void	pccard_delete_resource(device_t dev, device_t child, int type,
109		    int rid);
110static int	pccard_set_res_flags(device_t dev, device_t child, int type,
111		    int rid, uint32_t flags);
112static int	pccard_set_memory_offset(device_t dev, device_t child, int rid,
113		    uint32_t offset, uint32_t *deltap);
114static void	pccard_probe_nomatch(device_t cbdev, device_t child);
115static int	pccard_read_ivar(device_t bus, device_t child, int which,
116		    u_char *result);
117static void	pccard_driver_added(device_t dev, driver_t *driver);
118static struct resource *pccard_alloc_resource(device_t dev,
119		    device_t child, int type, int *rid, u_long start,
120		    u_long end, u_long count, u_int flags);
121static int	pccard_release_resource(device_t dev, device_t child, int type,
122		    int rid, struct resource *r);
123static void	pccard_child_detached(device_t parent, device_t dev);
124static void	pccard_intr(void *arg);
125static int	pccard_setup_intr(device_t dev, device_t child,
126		    struct resource *irq, int flags, driver_intr_t *intr,
127		    void *arg, void **cookiep);
128static int	pccard_teardown_intr(device_t dev, device_t child,
129		    struct resource *r, void *cookie);
130
131static const struct pccard_product *
132pccard_do_product_lookup(device_t bus, device_t dev,
133			 const struct pccard_product *tab, size_t ent_size,
134			 pccard_product_match_fn matchfn);
135
136
137static int
138pccard_ccr_read(struct pccard_function *pf, int ccr)
139{
140	return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
141	    pf->pf_ccr_offset + ccr));
142}
143
144static void
145pccard_ccr_write(struct pccard_function *pf, int ccr, int val)
146{
147	if ((pf->ccr_mask) & (1 << (ccr / 2))) {
148		bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
149		    pf->pf_ccr_offset + ccr, val);
150	}
151}
152
153static int
154pccard_set_default_descr(device_t dev)
155{
156	const char *vendorstr, *prodstr;
157	uint32_t vendor, prod;
158	char *str;
159
160	if (pccard_get_vendor_str(dev, &vendorstr))
161		return (0);
162	if (pccard_get_product_str(dev, &prodstr))
163		return (0);
164	if (vendorstr != NULL && prodstr != NULL) {
165		str = malloc(strlen(vendorstr) + strlen(prodstr) + 2, M_DEVBUF,
166		    M_WAITOK);
167		sprintf(str, "%s %s", vendorstr, prodstr);
168		device_set_desc_copy(dev, str);
169		free(str, M_DEVBUF);
170	} else {
171		if (pccard_get_vendor(dev, &vendor))
172			return (0);
173		if (pccard_get_product(dev, &prod))
174			return (0);
175		str = malloc(100, M_DEVBUF, M_WAITOK);
176		snprintf(str, 100, "vendor=0x%x product=0x%x", vendor, prod);
177		device_set_desc_copy(dev, str);
178		free(str, M_DEVBUF);
179	}
180	return (0);
181}
182
183static int
184pccard_attach_card(device_t dev)
185{
186	struct pccard_softc *sc = PCCARD_SOFTC(dev);
187	struct pccard_function *pf;
188	struct pccard_ivar *ivar;
189	device_t child;
190	int i;
191
192	/*
193	 * this is here so that when socket_enable calls gettype, trt happens
194	 */
195	STAILQ_INIT(&sc->card.pf_head);
196
197	DEVPRINTF((dev, "chip_socket_enable\n"));
198	POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
199
200	DEVPRINTF((dev, "read_cis\n"));
201	pccard_read_cis(sc);
202
203	DEVPRINTF((dev, "check_cis_quirks\n"));
204	pccard_check_cis_quirks(dev);
205
206	/*
207	 * bail now if the card has no functions, or if there was an error in
208	 * the cis.
209	 */
210
211	if (sc->card.error) {
212		device_printf(dev, "CARD ERROR!\n");
213		return (1);
214	}
215	if (STAILQ_EMPTY(&sc->card.pf_head)) {
216		device_printf(dev, "Card has no functions!\n");
217		return (1);
218	}
219
220	if (bootverbose || pccard_debug)
221		pccard_print_cis(dev);
222
223	DEVPRINTF((dev, "functions scanning\n"));
224	i = -1;
225	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
226		i++;
227		if (STAILQ_EMPTY(&pf->cfe_head)) {
228			device_printf(dev,
229			    "Function %d has no config entries.!\n", i);
230			continue;
231		}
232		pf->sc = sc;
233		pf->cfe = NULL;
234		pf->dev = NULL;
235	}
236	DEVPRINTF((dev, "Card has %d functions. pccard_mfc is %d\n", i + 1,
237	    pccard_mfc(sc)));
238
239	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
240		if (STAILQ_EMPTY(&pf->cfe_head))
241			continue;
242		/*
243		 * In NetBSD, the drivers are responsible for activating
244		 * each function of a card.  I think that in FreeBSD we
245		 * want to activate them enough for the usual bus_*_resource
246		 * routines will do the right thing.  This many mean a
247		 * departure from the current NetBSD model.
248		 *
249		 * This seems to work well in practice for most cards.
250		 * However, there are two cases that are problematic.
251		 * If a driver wishes to pick and chose which config
252		 * entry to use, then this method falls down.  These
253		 * are usually older cards.  In addition, there are
254		 * some cards that have multiple hardware units on the
255		 * cards, but presents only one CIS chain.  These cards
256		 * are combination cards, but only one of these units
257		 * can be on at a time.
258		 */
259		ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF,
260		    M_WAITOK | M_ZERO);
261		resource_list_init(&ivar->resources);
262		child = device_add_child(dev, NULL, -1);
263		device_set_ivars(child, ivar);
264		ivar->pf = pf;
265		pf->dev = child;
266		/*
267		 * XXX We might want to move the next three lines into
268		 * XXX the pccard interface layer.  For the moment, this
269		 * XXX is OK, but some drivers want to pick the config
270		 * XXX entry to use as well as some address tweaks (mostly
271		 * XXX due to bugs in decode logic that makes some
272		 * XXX addresses illegal or broken).
273		 */
274		pccard_function_init(pf);
275		if (sc->sc_enabled_count == 0)
276			POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
277		if (pccard_function_enable(pf) == 0 &&
278		    pccard_set_default_descr(child) == 0 &&
279		    device_probe_and_attach(child) == 0) {
280			DEVPRINTF((sc->dev, "function %d CCR at %d "
281			    "offset %x mask %x: "
282			    "%x %x %x %x, %x %x %x %x, %x\n",
283			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
284			    pf->ccr_mask, pccard_ccr_read(pf, 0x00),
285			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
286			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
287			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
288			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
289		} else {
290			if (pf->cfe != NULL)
291				pccard_function_disable(pf);
292		}
293	}
294	return (0);
295}
296
297static int
298pccard_detach_card(device_t dev)
299{
300	struct pccard_softc *sc = PCCARD_SOFTC(dev);
301	struct pccard_function *pf;
302	struct pccard_config_entry *cfe;
303	int state;
304
305	/*
306	 * We are running on either the PCCARD socket's event thread
307	 * or in user context detaching a device by user request.
308	 */
309	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
310		if (pf->dev == NULL)
311			continue;
312		state = device_get_state(pf->dev);
313		if (state == DS_ATTACHED || state == DS_BUSY)
314			device_detach(pf->dev);
315		if (pf->cfe != NULL)
316			pccard_function_disable(pf);
317		pccard_function_free(pf);
318		device_delete_child(dev, pf->dev);
319	}
320	if (sc->sc_enabled_count == 0)
321		POWER_DISABLE_SOCKET(device_get_parent(dev), dev);
322
323	while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) {
324		while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) {
325			STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list);
326			free(cfe, M_DEVBUF);
327		}
328		STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list);
329		free(pf, M_DEVBUF);
330	}
331	return (0);
332}
333
334static const struct pccard_product *
335pccard_do_product_lookup(device_t bus, device_t dev,
336    const struct pccard_product *tab, size_t ent_size,
337    pccard_product_match_fn matchfn)
338{
339	const struct pccard_product *ent;
340	int matches;
341	uint32_t vendor;
342	uint32_t prod;
343	const char *vendorstr;
344	const char *prodstr;
345	const char *cis3str;
346	const char *cis4str;
347
348#ifdef DIAGNOSTIC
349	if (sizeof *ent > ent_size)
350		panic("pccard_product_lookup: bogus ent_size %jd",
351		    (intmax_t) ent_size);
352#endif
353	if (pccard_get_vendor(dev, &vendor))
354		return (NULL);
355	if (pccard_get_product(dev, &prod))
356		return (NULL);
357	if (pccard_get_vendor_str(dev, &vendorstr))
358		return (NULL);
359	if (pccard_get_product_str(dev, &prodstr))
360		return (NULL);
361	if (pccard_get_cis3_str(dev, &cis3str))
362		return (NULL);
363	if (pccard_get_cis4_str(dev, &cis4str))
364		return (NULL);
365	for (ent = tab; ent->pp_vendor != 0; ent =
366	    (const struct pccard_product *) ((const char *) ent + ent_size)) {
367		matches = 1;
368		if (ent->pp_vendor == PCCARD_VENDOR_ANY &&
369		    ent->pp_product == PCCARD_PRODUCT_ANY &&
370		    ent->pp_cis[0] == NULL &&
371		    ent->pp_cis[1] == NULL) {
372			if (ent->pp_name)
373				device_printf(dev,
374				    "Total wildcard entry ignored for %s\n",
375				    ent->pp_name);
376			continue;
377		}
378		if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY &&
379		    vendor != ent->pp_vendor)
380			matches = 0;
381		if (matches && ent->pp_product != PCCARD_PRODUCT_ANY &&
382		    prod != ent->pp_product)
383			matches = 0;
384		if (matches && ent->pp_cis[0] &&
385		    (vendorstr == NULL ||
386		    strcmp(ent->pp_cis[0], vendorstr) != 0))
387			matches = 0;
388		if (matches && ent->pp_cis[1] &&
389		    (prodstr == NULL ||
390		    strcmp(ent->pp_cis[1], prodstr) != 0))
391			matches = 0;
392		if (matches && ent->pp_cis[2] &&
393		    (cis3str == NULL ||
394		    strcmp(ent->pp_cis[2], cis3str) != 0))
395			matches = 0;
396		if (matches && ent->pp_cis[3] &&
397		    (cis4str == NULL ||
398		    strcmp(ent->pp_cis[3], cis4str) != 0))
399			matches = 0;
400		if (matchfn != NULL)
401			matches = (*matchfn)(dev, ent, matches);
402		if (matches)
403			return (ent);
404	}
405	return (NULL);
406}
407
408/*
409 * Initialize a PCCARD function.  May be called as long as the function is
410 * disabled.
411 *
412 * Note: pccard_function_init should not keep resources allocated.  It should
413 * only set them up ala isa pnp, set the values in the rl lists, and return.
414 * Any resource held after pccard_function_init is called is a bug.  However,
415 * the bus routines to get the resources also assume that pccard_function_init
416 * does this, so they need to be fixed too.
417 */
418static void
419pccard_function_init(struct pccard_function *pf)
420{
421	struct pccard_config_entry *cfe;
422	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
423	struct resource_list *rl = &devi->resources;
424	struct resource_list_entry *rle;
425	struct resource *r = 0;
426	device_t bus;
427	u_long start, end, len;
428	int i, rid, spaces;
429
430	if (pf->pf_flags & PFF_ENABLED) {
431		printf("pccard_function_init: function is enabled");
432		return;
433	}
434	bus = device_get_parent(pf->dev);
435	/* Remember which configuration entry we are using. */
436	STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
437		if (cfe->iftype != PCCARD_IFTYPE_IO)
438			continue;
439		spaces = 0;
440		for (i = 0; i < cfe->num_iospace; i++) {
441			start = cfe->iospace[i].start;
442			if (start)
443				end = start + cfe->iospace[i].length - 1;
444			else
445				end = ~0UL;
446			DEVPRINTF((bus, "I/O rid %d start %lx end %lx\n",
447			    i, start, end));
448			rid = i;
449			len = cfe->iospace[i].length;
450			r = bus_alloc_resource(bus, SYS_RES_IOPORT, &rid,
451			    start, end, len, rman_make_alignment_flags(len));
452			if (r == NULL)
453				goto not_this_one;
454			rle = resource_list_add(rl, SYS_RES_IOPORT,
455			    rid, rman_get_start(r), rman_get_end(r),
456			    cfe->iospace[i].length);
457			if (rle == NULL)
458				panic("Cannot add resource rid %d IOPORT", rid);
459			rle->res = r;
460			spaces++;
461		}
462		for (i = 0; i < cfe->num_memspace; i++) {
463			start = cfe->memspace[i].hostaddr;
464			if (start)
465				end = start + cfe->memspace[i].length - 1;
466			else
467				end = ~0UL;
468			DEVPRINTF((bus, "Memory rid %d start %lx end %lx\n",
469			    i, start, end));
470			rid = i;
471			len = cfe->memspace[i].length;
472			r = bus_alloc_resource(bus, SYS_RES_MEMORY, &rid,
473			    start, end, len, rman_make_alignment_flags(len));
474			if (r == NULL)
475				goto not_this_one;
476			rle = resource_list_add(rl, SYS_RES_MEMORY,
477			    rid, rman_get_start(r), rman_get_end(r),
478			    cfe->memspace[i].length);
479			if (rle == NULL)
480				panic("Cannot add resource rid %d MEM", rid);
481			rle->res = r;
482			spaces++;
483		}
484		if (spaces == 0) {
485			DEVPRINTF((bus, "Neither memory nor I/O mapped\n"));
486			goto not_this_one;
487		}
488		if (cfe->irqmask) {
489			rid = 0;
490			r = bus_alloc_resource_any(bus, SYS_RES_IRQ, &rid,
491			    RF_SHAREABLE);
492			if (r == NULL)
493				goto not_this_one;
494			rle = resource_list_add(rl, SYS_RES_IRQ, rid,
495			    rman_get_start(r), rman_get_end(r), 1);
496			if (rle == NULL)
497				panic("Cannot add resource rid %d IRQ", rid);
498			rle->res = r;
499		}
500		/* If we get to here, we've allocated all we need */
501		pf->cfe = cfe;
502		break;
503	    not_this_one:;
504		DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n",
505		    cfe->number));
506		resource_list_purge(rl);
507	}
508}
509
510/*
511 * Free resources allocated by pccard_function_init(), May be called as long
512 * as the function is disabled.
513 *
514 * NOTE: This function should be unnecessary.  pccard_function_init should
515 * never keep resources initialized.
516 */
517static void
518pccard_function_free(struct pccard_function *pf)
519{
520	struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
521	struct resource_list_entry *rle;
522
523	if (pf->pf_flags & PFF_ENABLED) {
524		printf("pccard_function_init: function is enabled");
525		return;
526	}
527
528	STAILQ_FOREACH(rle, &devi->resources, link) {
529		if (rle->res) {
530			if (rman_get_device(rle->res) != pf->sc->dev)
531				device_printf(pf->sc->dev,
532				    "function_free: Resource still owned by "
533				    "child, oops. "
534				    "(type=%d, rid=%d, addr=%lx)\n",
535				    rle->type, rle->rid,
536				    rman_get_start(rle->res));
537			BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
538			    pf->sc->dev, rle->type, rle->rid, rle->res);
539			rle->res = NULL;
540		}
541	}
542	resource_list_free(&devi->resources);
543}
544
545static void
546pccard_mfc_adjust_iobase(struct pccard_function *pf, bus_addr_t addr,
547    bus_addr_t offset, bus_size_t size)
548{
549	bus_size_t iosize, tmp;
550
551	if (addr != 0) {
552		if (pf->pf_mfc_iomax == 0) {
553			pf->pf_mfc_iobase = addr + offset;
554			pf->pf_mfc_iomax = pf->pf_mfc_iobase + size;
555		} else {
556			/* this makes the assumption that nothing overlaps */
557			if (pf->pf_mfc_iobase > addr + offset)
558				pf->pf_mfc_iobase = addr + offset;
559			if (pf->pf_mfc_iomax < addr + offset + size)
560				pf->pf_mfc_iomax = addr + offset + size;
561		}
562	}
563
564	tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
565	/* round up to nearest (2^n)-1 */
566	for (iosize = 1; iosize < tmp; iosize <<= 1)
567		;
568	iosize--;
569
570	DEVPRINTF((pf->dev, "MFC: I/O base %#jx IOSIZE %#jx\n",
571	    (uintmax_t)pf->pf_mfc_iobase, (uintmax_t)(iosize + 1)));
572	pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
573	    pf->pf_mfc_iobase & 0xff);
574	pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
575	    (pf->pf_mfc_iobase >> 8) & 0xff);
576	pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
577	pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
578	pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
579}
580
581/* Enable a PCCARD function */
582static int
583pccard_function_enable(struct pccard_function *pf)
584{
585	struct pccard_function *tmp;
586	int reg;
587	device_t dev = pf->sc->dev;
588
589	if (pf->cfe == NULL) {
590		DEVPRVERBOSE((dev, "No config entry could be allocated.\n"));
591		return (ENOMEM);
592	}
593
594	/*
595	 * Increase the reference count on the socket, enabling power, if
596	 * necessary.
597	 */
598	pf->sc->sc_enabled_count++;
599
600	if (pf->pf_flags & PFF_ENABLED) {
601		/*
602		 * Don't do anything if we're already enabled.
603		 */
604		return (0);
605	}
606
607	/*
608	 * it's possible for different functions' CCRs to be in the same
609	 * underlying page.  Check for that.
610	 */
611	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
612		if ((tmp->pf_flags & PFF_ENABLED) &&
613		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
614		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
615		    (tmp->ccr_base - tmp->pf_ccr_offset +
616		    tmp->pf_ccr_realsize))) {
617			pf->pf_ccrt = tmp->pf_ccrt;
618			pf->pf_ccrh = tmp->pf_ccrh;
619			pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
620
621			/*
622			 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
623			 * tmp->ccr_base) + pf->ccr_base;
624			 */
625			/* pf->pf_ccr_offset =
626			    (tmp->pf_ccr_offset + pf->ccr_base) -
627			    tmp->ccr_base; */
628			pf->pf_ccr_window = tmp->pf_ccr_window;
629			break;
630		}
631	}
632	if (tmp == NULL) {
633		pf->ccr_rid = 0;
634		pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
635		    &pf->ccr_rid, 0, ~0, PCCARD_MEM_PAGE_SIZE, RF_ACTIVE);
636		if (!pf->ccr_res)
637			goto bad;
638		DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%x\n",
639		    rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res),
640		    pf->ccr_base));
641		CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
642		    pf->ccr_rid, PCCARD_A_MEM_ATTR);
643		CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev,
644		    pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset);
645		pf->pf_ccrt = rman_get_bustag(pf->ccr_res);
646		pf->pf_ccrh = rman_get_bushandle(pf->ccr_res);
647		pf->pf_ccr_realsize = 1;
648	}
649
650	reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX);
651	reg |= PCCARD_CCR_OPTION_LEVIREQ;
652	if (pccard_mfc(pf->sc)) {
653		reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE |
654			PCCARD_CCR_OPTION_ADDR_DECODE);
655		/* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */
656	}
657	pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
658
659	reg = 0;
660	if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0)
661		reg |= PCCARD_CCR_STATUS_IOIS8;
662	if (pf->cfe->flags & PCCARD_CFE_AUDIO)
663		reg |= PCCARD_CCR_STATUS_AUDIO;
664	pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg);
665
666	pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0);
667
668	if (pccard_mfc(pf->sc))
669		pccard_mfc_adjust_iobase(pf, 0, 0, 0);
670
671#ifdef PCCARDDEBUG
672	if (pccard_debug) {
673		STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
674			device_printf(tmp->sc->dev,
675			    "function %d CCR at %d offset %x: "
676			    "%x %x %x %x, %x %x %x %x, %x\n",
677			    tmp->number, tmp->pf_ccr_window,
678			    tmp->pf_ccr_offset,
679			    pccard_ccr_read(tmp, 0x00),
680			    pccard_ccr_read(tmp, 0x02),
681			    pccard_ccr_read(tmp, 0x04),
682			    pccard_ccr_read(tmp, 0x06),
683			    pccard_ccr_read(tmp, 0x0A),
684			    pccard_ccr_read(tmp, 0x0C),
685			    pccard_ccr_read(tmp, 0x0E),
686			    pccard_ccr_read(tmp, 0x10),
687			    pccard_ccr_read(tmp, 0x12));
688		}
689	}
690#endif
691	pf->pf_flags |= PFF_ENABLED;
692	return (0);
693
694 bad:
695	/*
696	 * Decrement the reference count, and power down the socket, if
697	 * necessary.
698	 */
699	pf->sc->sc_enabled_count--;
700	DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count));
701
702	return (1);
703}
704
705/* Disable PCCARD function. */
706static void
707pccard_function_disable(struct pccard_function *pf)
708{
709	struct pccard_function *tmp;
710	device_t dev = pf->sc->dev;
711
712	if (pf->cfe == NULL)
713		panic("pccard_function_disable: function not initialized");
714
715	if ((pf->pf_flags & PFF_ENABLED) == 0) {
716		/*
717		 * Don't do anything if we're already disabled.
718		 */
719		return;
720	}
721
722	if (pf->intr_handler != NULL) {
723		struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
724		struct resource_list_entry *rle =
725		    resource_list_find(&devi->resources, SYS_RES_IRQ, 0);
726		if (rle == NULL)
727			panic("Can't disable an interrupt with no IRQ res\n");
728		BUS_TEARDOWN_INTR(dev, pf->dev, rle->res,
729		    pf->intr_handler_cookie);
730	}
731
732	/*
733	 * it's possible for different functions' CCRs to be in the same
734	 * underlying page.  Check for that.  Note we mark us as disabled
735	 * first to avoid matching ourself.
736	 */
737
738	pf->pf_flags &= ~PFF_ENABLED;
739	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
740		if ((tmp->pf_flags & PFF_ENABLED) &&
741		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
742		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
743		    (tmp->ccr_base - tmp->pf_ccr_offset +
744		    tmp->pf_ccr_realsize)))
745			break;
746	}
747
748	/* Not used by anyone else; unmap the CCR. */
749	if (tmp == NULL) {
750		bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid,
751		    pf->ccr_res);
752		pf->ccr_res = NULL;
753	}
754
755	/*
756	 * Decrement the reference count, and power down the socket, if
757	 * necessary.
758	 */
759	pf->sc->sc_enabled_count--;
760}
761
762/*
763 * simulate the old "probe" routine.  In the new world order, the driver
764 * needs to grab devices while in the old they were assigned to the device by
765 * the pccardd process.  These symbols are exported to the upper layers.
766 */
767static int
768pccard_compat_do_probe(device_t bus, device_t dev)
769{
770	return (CARD_COMPAT_MATCH(dev));
771}
772
773static int
774pccard_compat_do_attach(device_t bus, device_t dev)
775{
776	int err;
777
778	err = CARD_COMPAT_PROBE(dev);
779	if (err <= 0)
780		err = CARD_COMPAT_ATTACH(dev);
781	return (err);
782}
783
784#define PCCARD_NPORT	2
785#define PCCARD_NMEM	5
786#define PCCARD_NIRQ	1
787#define PCCARD_NDRQ	0
788
789static int
790pccard_add_children(device_t dev, int busno)
791{
792	/* Call parent to scan for any current children */
793	return (0);
794}
795
796static int
797pccard_probe(device_t dev)
798{
799	device_set_desc(dev, "16-bit PCCard bus");
800	return (pccard_add_children(dev, device_get_unit(dev)));
801}
802
803static int
804pccard_attach(device_t dev)
805{
806	struct pccard_softc *sc = PCCARD_SOFTC(dev);
807	int err;
808
809	sc->dev = dev;
810	sc->sc_enabled_count = 0;
811	if ((err = pccard_device_create(sc)) != 0)
812		return  (err);
813	return (bus_generic_attach(dev));
814}
815
816static int
817pccard_detach(device_t dev)
818{
819	pccard_detach_card(dev);
820	pccard_device_destroy(device_get_softc(dev));
821	return (0);
822}
823
824static int
825pccard_suspend(device_t self)
826{
827	pccard_detach_card(self);
828	return (0);
829}
830
831static
832int
833pccard_resume(device_t self)
834{
835	return (0);
836}
837
838static void
839pccard_print_resources(struct resource_list *rl, const char *name, int type,
840    int count, const char *format)
841{
842	struct resource_list_entry *rle;
843	int printed;
844	int i;
845
846	printed = 0;
847	for (i = 0; i < count; i++) {
848		rle = resource_list_find(rl, type, i);
849		if (rle != NULL) {
850			if (printed == 0)
851				printf(" %s ", name);
852			else if (printed > 0)
853				printf(",");
854			printed++;
855			printf(format, rle->start);
856			if (rle->count > 1) {
857				printf("-");
858				printf(format, rle->start + rle->count - 1);
859			}
860		} else if (i > 3) {
861			/* check the first few regardless */
862			break;
863		}
864	}
865}
866
867static int
868pccard_print_child(device_t dev, device_t child)
869{
870	struct pccard_ivar *devi = PCCARD_IVAR(child);
871	struct resource_list *rl = &devi->resources;
872	int retval = 0;
873
874	retval += bus_print_child_header(dev, child);
875	retval += printf(" at");
876
877	if (devi != NULL) {
878		pccard_print_resources(rl, "port", SYS_RES_IOPORT,
879		    PCCARD_NPORT, "%#lx");
880		pccard_print_resources(rl, "iomem", SYS_RES_MEMORY,
881		    PCCARD_NMEM, "%#lx");
882		pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ,
883		    "%ld");
884		pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ,
885		    "%ld");
886		retval += printf(" function %d config %d", devi->pf->number,
887		    devi->pf->cfe->number);
888	}
889
890	retval += bus_print_child_footer(dev, child);
891
892	return (retval);
893}
894
895static int
896pccard_set_resource(device_t dev, device_t child, int type, int rid,
897    u_long start, u_long count)
898{
899	struct pccard_ivar *devi = PCCARD_IVAR(child);
900	struct resource_list *rl = &devi->resources;
901
902	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
903	    && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
904		return (EINVAL);
905	if (rid < 0)
906		return (EINVAL);
907	if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT)
908		return (EINVAL);
909	if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM)
910		return (EINVAL);
911	if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ)
912		return (EINVAL);
913	if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ)
914		return (EINVAL);
915
916	resource_list_add(rl, type, rid, start, start + count - 1, count);
917	if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev,
918	    type, &rid, start, start + count - 1, count, 0))
919		return 0;
920	else
921		return ENOMEM;
922}
923
924static int
925pccard_get_resource(device_t dev, device_t child, int type, int rid,
926    u_long *startp, u_long *countp)
927{
928	struct pccard_ivar *devi = PCCARD_IVAR(child);
929	struct resource_list *rl = &devi->resources;
930	struct resource_list_entry *rle;
931
932	rle = resource_list_find(rl, type, rid);
933	if (rle == NULL)
934		return (ENOENT);
935
936	if (startp != NULL)
937		*startp = rle->start;
938	if (countp != NULL)
939		*countp = rle->count;
940
941	return (0);
942}
943
944static void
945pccard_delete_resource(device_t dev, device_t child, int type, int rid)
946{
947	struct pccard_ivar *devi = PCCARD_IVAR(child);
948	struct resource_list *rl = &devi->resources;
949	resource_list_delete(rl, type, rid);
950}
951
952static int
953pccard_set_res_flags(device_t dev, device_t child, int type, int rid,
954    uint32_t flags)
955{
956	return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type,
957	    rid, flags));
958}
959
960static int
961pccard_set_memory_offset(device_t dev, device_t child, int rid,
962    uint32_t offset, uint32_t *deltap)
963
964{
965	return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid,
966	    offset, deltap));
967}
968
969static void
970pccard_probe_nomatch(device_t bus, device_t child)
971{
972	struct pccard_ivar *devi = PCCARD_IVAR(child);
973	struct pccard_function *pf = devi->pf;
974	struct pccard_softc *sc = PCCARD_SOFTC(bus);
975	int i;
976
977	device_printf(bus, "<unknown card>");
978	printf(" (manufacturer=0x%04x, product=0x%04x, function_type=%d) "
979	    "at function %d\n", sc->card.manufacturer, sc->card.product,
980	    pf->function, pf->number);
981	device_printf(bus, "   CIS info: ");
982	for (i = 0; sc->card.cis1_info[i] != NULL && i < 4; i++)
983		printf("%s%s", i > 0 ? ", " : "", sc->card.cis1_info[i]);
984	printf("\n");
985	return;
986}
987
988static int
989pccard_child_location_str(device_t bus, device_t child, char *buf,
990    size_t buflen)
991{
992	struct pccard_ivar *devi = PCCARD_IVAR(child);
993	struct pccard_function *pf = devi->pf;
994
995	snprintf(buf, buflen, "function=%d", pf->number);
996	return (0);
997}
998
999/* XXX Maybe this should be in subr_bus? */
1000static void
1001pccard_safe_quote(char *dst, const char *src, size_t len)
1002{
1003	char *walker = dst, *ep = dst + len - 1;
1004
1005	if (len == 0)
1006		return;
1007	while (walker < ep)
1008	{
1009		if (*src == '"') {
1010			if (ep - walker < 2)
1011				break;
1012			*walker++ = '\\';
1013		}
1014		*walker++ = *src++;
1015	}
1016	*walker = '\0';
1017}
1018
1019static int
1020pccard_child_pnpinfo_str(device_t bus, device_t child, char *buf,
1021    size_t buflen)
1022{
1023	struct pccard_ivar *devi = PCCARD_IVAR(child);
1024	struct pccard_function *pf = devi->pf;
1025	struct pccard_softc *sc = PCCARD_SOFTC(bus);
1026	char cis0[128], cis1[128];
1027
1028	pccard_safe_quote(cis0, sc->card.cis1_info[0], sizeof(cis0));
1029	pccard_safe_quote(cis1, sc->card.cis1_info[1], sizeof(cis1));
1030	snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x "
1031	    "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d",
1032	    sc->card.manufacturer, sc->card.product, cis0, cis1, pf->function);
1033	return (0);
1034}
1035
1036static int
1037pccard_read_ivar(device_t bus, device_t child, int which, u_char *result)
1038{
1039	struct pccard_ivar *devi = PCCARD_IVAR(child);
1040	struct pccard_function *pf = devi->pf;
1041	struct pccard_softc *sc = PCCARD_SOFTC(bus);
1042
1043	if (!pf)
1044		panic("No pccard function pointer");
1045	switch (which) {
1046	default:
1047		return (EINVAL);
1048	case PCCARD_IVAR_ETHADDR:
1049		bcopy(pf->pf_funce_lan_nid, result, ETHER_ADDR_LEN);
1050		break;
1051	case PCCARD_IVAR_VENDOR:
1052		*(uint32_t *)result = sc->card.manufacturer;
1053		break;
1054	case PCCARD_IVAR_PRODUCT:
1055		*(uint32_t *)result = sc->card.product;
1056		break;
1057	case PCCARD_IVAR_PRODEXT:
1058		*(uint16_t *)result = sc->card.prodext;
1059		break;
1060	case PCCARD_IVAR_FUNCTION:
1061		*(uint32_t *)result = pf->function;
1062		break;
1063	case PCCARD_IVAR_FUNCTION_NUMBER:
1064		*(uint32_t *)result = pf->number;
1065		break;
1066	case PCCARD_IVAR_VENDOR_STR:
1067		*(const char **)result = sc->card.cis1_info[0];
1068		break;
1069	case PCCARD_IVAR_PRODUCT_STR:
1070		*(const char **)result = sc->card.cis1_info[1];
1071		break;
1072	case PCCARD_IVAR_CIS3_STR:
1073		*(const char **)result = sc->card.cis1_info[2];
1074		break;
1075	case PCCARD_IVAR_CIS4_STR:
1076		*(const char **)result = sc->card.cis1_info[3];
1077		break;
1078	}
1079	return (0);
1080}
1081
1082static void
1083pccard_driver_added(device_t dev, driver_t *driver)
1084{
1085	struct pccard_softc *sc = PCCARD_SOFTC(dev);
1086	struct pccard_function *pf;
1087	device_t child;
1088
1089	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
1090		if (STAILQ_EMPTY(&pf->cfe_head))
1091			continue;
1092		child = pf->dev;
1093		if (device_get_state(child) != DS_NOTPRESENT)
1094			continue;
1095		if (pccard_function_enable(pf) == 0 &&
1096		    device_probe_and_attach(child) == 0) {
1097			DEVPRINTF((sc->dev, "function %d CCR at %d "
1098			    "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
1099			    pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
1100			    pccard_ccr_read(pf, 0x00),
1101			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
1102			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
1103			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
1104			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
1105		} else {
1106			if (pf->cfe != NULL)
1107				pccard_function_disable(pf);
1108		}
1109	}
1110	return;
1111}
1112
1113static struct resource *
1114pccard_alloc_resource(device_t dev, device_t child, int type, int *rid,
1115    u_long start, u_long end, u_long count, u_int flags)
1116{
1117	struct pccard_ivar *dinfo;
1118	struct resource_list_entry *rle = 0;
1119	int passthrough = (device_get_parent(child) != dev);
1120	int isdefault = (start == 0 && end == ~0UL && count == 1);
1121	struct resource *r = NULL;
1122
1123	/* XXX I'm no longer sure this is right */
1124	if (passthrough) {
1125		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
1126		    type, rid, start, end, count, flags));
1127	}
1128
1129	dinfo = device_get_ivars(child);
1130	rle = resource_list_find(&dinfo->resources, type, *rid);
1131
1132	if (rle == NULL && isdefault)
1133		return (NULL);	/* no resource of that type/rid */
1134	if (rle == NULL || rle->res == NULL) {
1135		/* XXX Need to adjust flags */
1136		r = bus_alloc_resource(dev, type, rid, start, end,
1137		  count, flags);
1138		if (r == NULL)
1139		    goto bad;
1140		resource_list_add(&dinfo->resources, type, *rid,
1141		  rman_get_start(r), rman_get_end(r), count);
1142		rle = resource_list_find(&dinfo->resources, type, *rid);
1143		if (!rle)
1144		    goto bad;
1145		rle->res = r;
1146	}
1147	/*
1148	 * If dev doesn't own the device, then we can't give this device
1149	 * out.
1150	 */
1151	if (rman_get_device(rle->res) != dev)
1152		return (NULL);
1153	rman_set_device(rle->res, child);
1154	if (flags & RF_ACTIVE)
1155		BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, rle->res);
1156	return (rle->res);
1157bad:;
1158	device_printf(dev, "WARNING: Resource not reserved by pccard\n");
1159	return (NULL);
1160}
1161
1162static int
1163pccard_release_resource(device_t dev, device_t child, int type, int rid,
1164    struct resource *r)
1165{
1166	struct pccard_ivar *dinfo;
1167	int passthrough = (device_get_parent(child) != dev);
1168	struct resource_list_entry *rle = 0;
1169
1170	if (passthrough)
1171		return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
1172		    type, rid, r);
1173
1174	dinfo = device_get_ivars(child);
1175
1176	rle = resource_list_find(&dinfo->resources, type, rid);
1177
1178	if (!rle) {
1179		device_printf(dev, "Allocated resource not found, "
1180		    "%d %x %lx %lx\n",
1181		    type, rid, rman_get_start(r), rman_get_size(r));
1182		return ENOENT;
1183	}
1184	if (!rle->res) {
1185		device_printf(dev, "Allocated resource not recorded\n");
1186		return ENOENT;
1187	}
1188	/*
1189	 * Deactivate the resource (since it is being released), and
1190	 * assign it to the bus.
1191	 */
1192	BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, rle->res);
1193	rman_set_device(rle->res, dev);
1194	return (0);
1195}
1196
1197static void
1198pccard_child_detached(device_t parent, device_t dev)
1199{
1200	struct pccard_ivar *ivar = PCCARD_IVAR(dev);
1201	struct pccard_function *pf = ivar->pf;
1202
1203	pccard_function_disable(pf);
1204}
1205
1206static void
1207pccard_intr(void *arg)
1208{
1209	struct pccard_function *pf = (struct pccard_function*) arg;
1210	int reg;
1211	int doisr = 1;
1212
1213	/*
1214	 * MFC cards know if they interrupted, so we have to ack the
1215	 * interrupt and call the ISR.  Non-MFC cards don't have these
1216	 * bits, so they always get called.  Many non-MFC cards have
1217	 * this bit set always upon read, but some do not.
1218	 *
1219	 * We always ack the interrupt, even if there's no ISR
1220	 * for the card.  This is done on the theory that acking
1221	 * the interrupt will pacify the card enough to keep an
1222	 * interrupt storm from happening.  Of course this won't
1223	 * help in the non-MFC case.
1224	 *
1225	 * This has no impact for MPSAFEness of the client drivers.
1226	 * We register this with whatever flags the intr_handler
1227	 * was registered with.  All these functions are MPSAFE.
1228	 */
1229	if (pccard_mfc(pf->sc)) {
1230		reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
1231		if (reg & PCCARD_CCR_STATUS_INTR)
1232			pccard_ccr_write(pf, PCCARD_CCR_STATUS,
1233			    reg & ~PCCARD_CCR_STATUS_INTR);
1234		else
1235			doisr = 0;
1236	}
1237	if (pf->intr_handler != NULL && doisr)
1238		pf->intr_handler(pf->intr_handler_arg);
1239}
1240
1241static int
1242pccard_setup_intr(device_t dev, device_t child, struct resource *irq,
1243    int flags, driver_intr_t *intr, void *arg, void **cookiep)
1244{
1245	struct pccard_softc *sc = PCCARD_SOFTC(dev);
1246	struct pccard_ivar *ivar = PCCARD_IVAR(child);
1247	struct pccard_function *pf = ivar->pf;
1248	int err;
1249
1250	if (pf->intr_handler != NULL)
1251		panic("Only one interrupt handler per function allowed");
1252	err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr,
1253	    pf, cookiep);
1254	if (err != 0)
1255		return (err);
1256	pf->intr_handler = intr;
1257	pf->intr_handler_arg = arg;
1258	pf->intr_handler_cookie = *cookiep;
1259	if (pccard_mfc(sc)) {
1260		pccard_ccr_write(pf, PCCARD_CCR_OPTION,
1261		    pccard_ccr_read(pf, PCCARD_CCR_OPTION) |
1262		    PCCARD_CCR_OPTION_IREQ_ENABLE);
1263	}
1264	return (0);
1265}
1266
1267static int
1268pccard_teardown_intr(device_t dev, device_t child, struct resource *r,
1269    void *cookie)
1270{
1271	struct pccard_softc *sc = PCCARD_SOFTC(dev);
1272	struct pccard_ivar *ivar = PCCARD_IVAR(child);
1273	struct pccard_function *pf = ivar->pf;
1274	int ret;
1275
1276	if (pccard_mfc(sc)) {
1277		pccard_ccr_write(pf, PCCARD_CCR_OPTION,
1278		    pccard_ccr_read(pf, PCCARD_CCR_OPTION) &
1279		    ~PCCARD_CCR_OPTION_IREQ_ENABLE);
1280	}
1281	ret = bus_generic_teardown_intr(dev, child, r, cookie);
1282	if (ret == 0) {
1283		pf->intr_handler = NULL;
1284		pf->intr_handler_arg = NULL;
1285		pf->intr_handler_cookie = NULL;
1286	}
1287
1288	return (ret);
1289}
1290
1291static int
1292pccard_activate_resource(device_t brdev, device_t child, int type, int rid,
1293    struct resource *r)
1294{
1295	struct pccard_ivar *ivar = PCCARD_IVAR(child);
1296	struct pccard_function *pf = ivar->pf;
1297
1298	switch(type) {
1299	case SYS_RES_IOPORT:
1300		/*
1301		 * We need to adjust IOBASE[01] and IOSIZE if we're an MFC
1302		 * card.
1303		 */
1304		if (pccard_mfc(pf->sc))
1305			pccard_mfc_adjust_iobase(pf, rman_get_start(r), 0,
1306			    rman_get_size(r));
1307		break;
1308	default:
1309		break;
1310	}
1311	return (bus_generic_activate_resource(brdev, child, type, rid, r));
1312}
1313
1314static int
1315pccard_deactivate_resource(device_t brdev, device_t child, int type,
1316    int rid, struct resource *r)
1317{
1318	/* XXX undo pccard_activate_resource? XXX */
1319	return (bus_generic_deactivate_resource(brdev, child, type, rid, r));
1320}
1321
1322static int
1323pccard_attr_read_impl(device_t brdev, device_t child, uint32_t offset,
1324    uint8_t *val)
1325{
1326	struct pccard_ivar *devi = PCCARD_IVAR(child);
1327	struct pccard_function *pf = devi->pf;
1328
1329	/*
1330	 * Optimization.  Most of the time, devices want to access
1331	 * the same page of the attribute memory that the CCR is in.
1332	 * We take advantage of this fact here.
1333	 */
1334	if (offset / PCCARD_MEM_PAGE_SIZE ==
1335	    pf->ccr_base / PCCARD_MEM_PAGE_SIZE)
1336		*val = bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
1337		    offset % PCCARD_MEM_PAGE_SIZE);
1338	else {
1339		CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, offset,
1340		    &offset);
1341		*val = bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, offset);
1342		CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, pf->ccr_base,
1343		    &offset);
1344	}
1345	return 0;
1346}
1347
1348static int
1349pccard_attr_write_impl(device_t brdev, device_t child, uint32_t offset,
1350    uint8_t val)
1351{
1352	struct pccard_ivar *devi = PCCARD_IVAR(child);
1353	struct pccard_function *pf = devi->pf;
1354
1355	/*
1356	 * Optimization.  Most of the time, devices want to access
1357	 * the same page of the attribute memory that the CCR is in.
1358	 * We take advantage of this fact here.
1359	 */
1360	if (offset / PCCARD_MEM_PAGE_SIZE ==
1361	    pf->ccr_base / PCCARD_MEM_PAGE_SIZE)
1362		bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
1363		    offset % PCCARD_MEM_PAGE_SIZE, val);
1364	else {
1365		CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, offset,
1366		    &offset);
1367		bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, offset, val);
1368		CARD_SET_MEMORY_OFFSET(brdev, child, pf->ccr_rid, pf->ccr_base,
1369		    &offset);
1370	}
1371
1372	return 0;
1373}
1374
1375static int
1376pccard_ccr_read_impl(device_t brdev, device_t child, uint32_t offset,
1377    uint8_t *val)
1378{
1379	struct pccard_ivar *devi = PCCARD_IVAR(child);
1380
1381	*val = pccard_ccr_read(devi->pf, offset);
1382	device_printf(child, "ccr_read of %#x (%#x) is %#x\n", offset,
1383	  devi->pf->pf_ccr_offset, *val);
1384	return 0;
1385}
1386
1387static int
1388pccard_ccr_write_impl(device_t brdev, device_t child, uint32_t offset,
1389    uint8_t val)
1390{
1391	struct pccard_ivar *devi = PCCARD_IVAR(child);
1392	struct pccard_function *pf = devi->pf;
1393
1394	/*
1395	 * Can't use pccard_ccr_write since client drivers may access
1396	 * registers not contained in the 'mask' if they are non-standard.
1397	 */
1398	device_printf(child, "ccr_write of %#x to %#x (%#x)\n", val, offset,
1399	  devi->pf->pf_ccr_offset);
1400	bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, pf->pf_ccr_offset + offset,
1401	    val);
1402	return 0;
1403}
1404
1405
1406static device_method_t pccard_methods[] = {
1407	/* Device interface */
1408	DEVMETHOD(device_probe,		pccard_probe),
1409	DEVMETHOD(device_attach,	pccard_attach),
1410	DEVMETHOD(device_detach,	pccard_detach),
1411	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
1412	DEVMETHOD(device_suspend,	pccard_suspend),
1413	DEVMETHOD(device_resume,	pccard_resume),
1414
1415	/* Bus interface */
1416	DEVMETHOD(bus_print_child,	pccard_print_child),
1417	DEVMETHOD(bus_driver_added,	pccard_driver_added),
1418	DEVMETHOD(bus_child_detached,	pccard_child_detached),
1419	DEVMETHOD(bus_alloc_resource,	pccard_alloc_resource),
1420	DEVMETHOD(bus_release_resource,	pccard_release_resource),
1421	DEVMETHOD(bus_activate_resource, pccard_activate_resource),
1422	DEVMETHOD(bus_deactivate_resource, pccard_deactivate_resource),
1423	DEVMETHOD(bus_setup_intr,	pccard_setup_intr),
1424	DEVMETHOD(bus_teardown_intr,	pccard_teardown_intr),
1425	DEVMETHOD(bus_set_resource,	pccard_set_resource),
1426	DEVMETHOD(bus_get_resource,	pccard_get_resource),
1427	DEVMETHOD(bus_delete_resource,	pccard_delete_resource),
1428	DEVMETHOD(bus_probe_nomatch,	pccard_probe_nomatch),
1429	DEVMETHOD(bus_read_ivar,	pccard_read_ivar),
1430	DEVMETHOD(bus_child_pnpinfo_str, pccard_child_pnpinfo_str),
1431	DEVMETHOD(bus_child_location_str, pccard_child_location_str),
1432
1433	/* Card Interface */
1434	DEVMETHOD(card_set_res_flags,	pccard_set_res_flags),
1435	DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset),
1436	DEVMETHOD(card_attach_card,	pccard_attach_card),
1437	DEVMETHOD(card_detach_card,	pccard_detach_card),
1438	DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup),
1439	DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe),
1440	DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach),
1441	DEVMETHOD(card_cis_scan,	pccard_scan_cis),
1442	DEVMETHOD(card_attr_read,	pccard_attr_read_impl),
1443	DEVMETHOD(card_attr_write,	pccard_attr_write_impl),
1444	DEVMETHOD(card_ccr_read,	pccard_ccr_read_impl),
1445	DEVMETHOD(card_ccr_write,	pccard_ccr_write_impl),
1446
1447	{ 0, 0 }
1448};
1449
1450static driver_t pccard_driver = {
1451	"pccard",
1452	pccard_methods,
1453	sizeof(struct pccard_softc)
1454};
1455
1456devclass_t	pccard_devclass;
1457
1458/* Maybe we need to have a slot device? */
1459DRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
1460DRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0);
1461MODULE_VERSION(pccard, 1);
1462