pccard.c revision 55500
1170530Ssam/*	$NetBSD: pcmcia.c,v 1.13 1998/12/24 04:51:59 marc Exp $	*/
2186904Ssam/* $FreeBSD: head/sys/dev/pccard/pccard.c 55500 2000-01-06 07:30:28Z imp $ */
3170530Ssam
4170530Ssam/*
5170530Ssam * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
6170530Ssam *
7170530Ssam * Redistribution and use in source and binary forms, with or without
8170530Ssam * modification, are permitted provided that the following conditions
9170530Ssam * are met:
10170530Ssam * 1. Redistributions of source code must retain the above copyright
11170530Ssam *    notice, this list of conditions and the following disclaimer.
12170530Ssam * 2. Redistributions in binary form must reproduce the above copyright
13170530Ssam *    notice, this list of conditions and the following disclaimer in the
14170530Ssam *    documentation and/or other materials provided with the distribution.
15170530Ssam * 3. All advertising materials mentioning features or use of this software
16170530Ssam *    must display the following acknowledgement:
17170530Ssam *	This product includes software developed by Marc Horowitz.
18170530Ssam * 4. The name of the author may not be used to endorse or promote products
19170530Ssam *    derived from this software without specific prior written permission.
20170530Ssam *
21170530Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22170530Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23170530Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24170530Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25170530Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26170530Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27170530Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28170530Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29170530Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30170530Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31170530Ssam */
32178354Ssam
33178354Ssam#include <sys/param.h>
34170530Ssam#include <sys/systm.h>
35191746Sthompsa#include <sys/malloc.h>
36170530Ssam#include <sys/module.h>
37170530Ssam#include <sys/kernel.h>
38191746Sthompsa#include <sys/queue.h>
39170530Ssam#include <sys/types.h>
40170530Ssam
41170530Ssam#include <sys/bus.h>
42170530Ssam#include <machine/bus.h>
43170530Ssam#include <sys/rman.h>
44170530Ssam#include <machine/resource.h>
45170530Ssam
46178354Ssam#include <dev/pccard/pccardreg.h>
47178354Ssam#include <dev/pccard/pccardchip.h>
48186904Ssam#include <dev/pccard/pccardvar.h>
49186904Ssam
50186904Ssam#include "power_if.h"
51195618Srpaulo
52195618Srpaulo#define PCCARDDEBUG
53195618Srpaulo
54170530Ssam#ifdef PCCARDDEBUG
55170530Ssamint	pccard_debug = 1;
56170530Ssam#define	DPRINTF(arg) if (pccard_debug) printf arg
57170530Ssam#define	DEVPRINTF(arg) if (pccard_debug) device_printf arg
58170530Ssamint	pccardintr_debug = 0;
59170530Ssam/* this is done this way to avoid doing lots of conditionals
60170530Ssam   at interrupt level.  */
61170530Ssam#define PCCARD_CARD_INTR (pccardintr_debug?pccard_card_intrdebug:pccard_card_intr)
62170530Ssam#else
63170530Ssam#define	DPRINTF(arg)
64170530Ssam#define	DEVPRINTF(arg)
65170530Ssam#define PCCARD_CARD_INTR (pccard_card_intr)
66170530Ssam#endif
67170530Ssam
68170530Ssam#ifdef PCCARDVERBOSE
69170530Ssamint	pccard_verbose = 1;
70170530Ssam#else
71170530Ssamint	pccard_verbose = 0;
72170530Ssam#endif
73170530Ssam
74170530Ssamint	pccard_print(void *, const char *);
75170530Ssam
76170530Ssamint pccard_card_intr(void *);
77170530Ssam#ifdef PCCARDDEBUG
78170530Ssamint pccard_card_intrdebug(void *);
79170530Ssam#endif
80170530Ssam
81170530Ssam/* XXX Shouldn't be touching hardware, that's a layering violation */
82184302Ssam/* XXX imp */
83170530Ssamint
84170530Ssampccard_ccr_read(pf, ccr)
85170530Ssam	struct pccard_function *pf;
86170530Ssam	int ccr;
87170530Ssam{
88178354Ssam	return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
89170530Ssam	    pf->pf_ccr_offset + ccr));
90170530Ssam}
91170530Ssam
92170530Ssamvoid
93170530Ssampccard_ccr_write(pf, ccr, val)
94170530Ssam	struct pccard_function *pf;
95170530Ssam	int ccr;
96186107Ssam	int val;
97186107Ssam{
98186107Ssam
99170530Ssam	if ((pf->ccr_mask) & (1 << (ccr / 2))) {
100206617Srpaulo		bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
101170530Ssam		    pf->pf_ccr_offset + ccr, val);
102170530Ssam	}
103178354Ssam}
104178354Ssam
105178354Ssamint
106170530Ssampccard_card_attach(device_t dev)
107178354Ssam{
108186107Ssam	struct pccard_softc *sc = (struct pccard_softc *)
109170530Ssam	    device_get_softc(dev);
110170530Ssam	struct pccard_function *pf;
111170530Ssam	int attached;
112171409Ssam
113171409Ssam	DEVPRINTF((dev, "pccard_card_attach\n"));
114171409Ssam	/*
115171409Ssam	 * this is here so that when socket_enable calls gettype, trt happens
116171409Ssam	 */
117171409Ssam	STAILQ_INIT(&sc->card.pf_head);
118195618Srpaulo
119195618Srpaulo	DEVPRINTF((dev, "chip_socket_enable\n"));
120195618Srpaulo	POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
121195618Srpaulo
122195618Srpaulo	DEVPRINTF((dev, "read_cis\n"));
123195618Srpaulo	pccard_read_cis(sc);
124195618Srpaulo
125195618Srpaulo	DEVPRINTF((dev, "chip_socket_disable\n"));
126195618Srpaulo	POWER_DISABLE_SOCKET(device_get_parent(dev), dev);
127195618Srpaulo
128195618Srpaulo	DEVPRINTF((dev, "check_cis_quirks\n"));
129195618Srpaulo	pccard_check_cis_quirks(dev);
130195618Srpaulo
131195618Srpaulo	/*
132195618Srpaulo	 * bail now if the card has no functions, or if there was an error in
133195618Srpaulo	 * the cis.
134195618Srpaulo	 */
135178354Ssam
136170530Ssam	if (sc->card.error)
137178354Ssam		return (1);
138170530Ssam	if (STAILQ_EMPTY(&sc->card.pf_head))
139178354Ssam		return (1);
140178354Ssam
141178354Ssam	if (pccard_verbose)
142178354Ssam		pccard_print_cis(dev);
143178354Ssam
144178354Ssam	attached = 0;
145170530Ssam
146170530Ssam	DEVPRINTF((dev, "functions scanning\n"));
147195618Srpaulo	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
148195618Srpaulo		if (STAILQ_EMPTY(&pf->cfe_head))
149195618Srpaulo			continue;
150195618Srpaulo
151170530Ssam#ifdef DIAGNOSTIC
152170530Ssam		if (pf->child != NULL) {
153170530Ssam			device_printf(sc->dev,
154170530Ssam			    "%s still attached to function %d!\n",
155170530Ssam			    device_get_name(pf->child), pf->number);
156170530Ssam			panic("pccard_card_attach");
157170530Ssam		}
158170530Ssam#endif
159170530Ssam		pf->sc = sc;
160186302Ssam		pf->child = NULL;
161170530Ssam		pf->cfe = NULL;
162170530Ssam		pf->ih_fct = NULL;
163170530Ssam		pf->ih_arg = NULL;
164206617Srpaulo	}
165170530Ssam
166170530Ssam	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
167170530Ssam		if (STAILQ_EMPTY(&pf->cfe_head))
168170530Ssam			continue;
169170530Ssam
170170530Ssam#if XXX
171170530Ssam		if (attach_child()) {
172170530Ssam			attached++;
173170530Ssam
174170530Ssam			DEVPRINTF((sc->dev, "function %d CCR at %d "
175170530Ssam			     "offset %lx: %x %x %x %x, %x %x %x %x, %x\n",
176170530Ssam			     pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
177170530Ssam			     pccard_ccr_read(pf, 0x00),
178170530Ssam			pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
179170530Ssam			pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
180170530Ssam			pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
181170530Ssam			pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
182206617Srpaulo		}
183170530Ssam#endif
184186302Ssam	}
185170530Ssam
186170530Ssam	return (attached ? 0 : 1);
187170530Ssam}
188170530Ssam
189170530Ssamvoid
190170530Ssampccard_card_detach(device_t dev, int flags)
191170530Ssam{
192170530Ssam	struct pccard_softc *sc = (struct pccard_softc *)
193170530Ssam	    device_get_softc(dev);
194170530Ssam	struct pccard_function *pf;
195170530Ssam#if XXX
196170530Ssam	int error;
197170530Ssam#endif
198170530Ssam
199206617Srpaulo	/*
200170530Ssam	 * We are running on either the PCCARD socket's event thread
201206617Srpaulo	 * or in user context detaching a device by user request.
202170530Ssam	 */
203170530Ssam	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
204170530Ssam		if (STAILQ_FIRST(&pf->cfe_head) == NULL)
205170530Ssam			continue;
206170530Ssam		if (pf->child == NULL)
207170530Ssam			continue;
208170530Ssam		DEVPRINTF((sc->dev, "detaching %s (function %d)\n",
209170530Ssam		    device_get_name(pf->child), pf->number));
210170530Ssam#if XXX
211170530Ssam		if ((error = config_detach(pf->child, flags)) != 0) {
212170530Ssam			device_printf(sc->dev,
213170530Ssam			    "error %d detaching %s (function %d)\n",
214170530Ssam			    error, device_get_name(pf->child), pf->number);
215170530Ssam		} else
216170530Ssam			pf->child = NULL;
217178354Ssam#endif
218186302Ssam	}
219170530Ssam}
220178354Ssam
221170530Ssamvoid
222170530Ssampccard_card_deactivate(device_t dev)
223170530Ssam{
224170530Ssam	struct pccard_softc *sc = (struct pccard_softc *)
225170530Ssam	    device_get_softc(dev);
226170530Ssam	struct pccard_function *pf;
227170530Ssam
228170530Ssam	/*
229170530Ssam	 * We're in the chip's card removal interrupt handler.
230170530Ssam	 * Deactivate the child driver.  The PCCARD socket's
231192468Ssam	 * event thread will run later to finish the detach.
232170530Ssam	 */
233170530Ssam	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
234170530Ssam		if (STAILQ_FIRST(&pf->cfe_head) == NULL)
235170530Ssam			continue;
236170530Ssam		if (pf->child == NULL)
237170530Ssam			continue;
238170530Ssam		DEVPRINTF((sc->dev, "deactivating %s (function %d)\n",
239178354Ssam		    device_get_name(pf->child), pf->number));
240178354Ssam#if XXX
241170530Ssam		config_deactivate(pf->child);
242170530Ssam#endif
243178354Ssam	}
244170530Ssam}
245170530Ssam
246170530Ssamint
247206617Srpaulopccard_card_gettype(device_t dev)
248170530Ssam{
249170530Ssam	struct pccard_softc *sc = (struct pccard_softc *)
250170530Ssam	    device_get_softc(dev);
251186302Ssam	struct pccard_function *pf;
252170530Ssam
253170530Ssam	/*
254206617Srpaulo	 * set the iftype to memory if this card has no functions (not yet
255170530Ssam	 * probed), or only one function, and that is not initialized yet or
256170530Ssam	 * that is memory.
257178354Ssam	 */
258178354Ssam	pf = STAILQ_FIRST(&sc->card.pf_head);
259170530Ssam	if (pf == NULL ||
260170530Ssam	    (STAILQ_NEXT(pf, pf_list) == NULL &&
261170530Ssam	    (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY)))
262170530Ssam		return (PCCARD_IFTYPE_MEMORY);
263170530Ssam	else
264170530Ssam		return (PCCARD_IFTYPE_IO);
265170530Ssam}
266170530Ssam
267170530Ssam/*
268170530Ssam * Initialize a PCCARD function.  May be called as long as the function is
269170530Ssam * disabled.
270170530Ssam */
271170530Ssamvoid
272170530Ssampccard_function_init(pf, cfe)
273178354Ssam	struct pccard_function *pf;
274170530Ssam	struct pccard_config_entry *cfe;
275170530Ssam{
276170530Ssam	if (pf->pf_flags & PFF_ENABLED)
277170530Ssam		panic("pccard_function_init: function is enabled");
278170530Ssam
279178354Ssam	/* Remember which configuration entry we are using. */
280173368Ssam	pf->cfe = cfe;
281173368Ssam}
282173368Ssam
283173368Ssam/* Enable a PCCARD function */
284173368Ssamint
285173368Ssampccard_function_enable(pf)
286178354Ssam	struct pccard_function *pf;
287178354Ssam{
288173368Ssam	struct pccard_function *tmp;
289173368Ssam	int reg;
290170530Ssam
291170530Ssam	if (pf->cfe == NULL)
292170530Ssam		panic("pccard_function_enable: function not initialized");
293195618Srpaulo
294195618Srpaulo	/*
295195618Srpaulo	 * Increase the reference count on the socket, enabling power, if
296195618Srpaulo	 * necessary.
297173368Ssam	 */
298173368Ssam	if (pf->sc->sc_enabled_count++ == 0)
299173368Ssam		POWER_ENABLE_SOCKET(device_get_parent(pf->sc->dev),
300178354Ssam		    pf->sc->dev);
301173368Ssam	DEVPRINTF((pf->sc->dev, "++enabled_count = %d\n",
302178354Ssam	    pf->sc->sc_enabled_count));
303173862Ssam
304173368Ssam	if (pf->pf_flags & PFF_ENABLED) {
305173862Ssam		/*
306178354Ssam		 * Don't do anything if we're already enabled.
307178354Ssam		 */
308178354Ssam		return (0);
309173368Ssam	}
310178354Ssam
311178354Ssam	/*
312173956Ssam	 * it's possible for different functions' CCRs to be in the same
313173956Ssam	 * underlying page.  Check for that.
314173956Ssam	 */
315173862Ssam
316178354Ssam	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
317173862Ssam		if ((tmp->pf_flags & PFF_ENABLED) &&
318173862Ssam		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
319178354Ssam		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
320170530Ssam		     (tmp->ccr_base - tmp->pf_ccr_offset +
321170530Ssam		      tmp->pf_ccr_realsize))) {
322170530Ssam			pf->pf_ccrt = tmp->pf_ccrt;
323170530Ssam			pf->pf_ccrh = tmp->pf_ccrh;
324170530Ssam			pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
325170530Ssam
326170530Ssam			/*
327170530Ssam			 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
328170530Ssam			 * tmp->ccr_base) + pf->ccr_base;
329178354Ssam			 */
330178354Ssam			pf->pf_ccr_offset =
331178354Ssam			    (tmp->pf_ccr_offset + pf->ccr_base) -
332178354Ssam			    tmp->ccr_base;
333178354Ssam			pf->pf_ccr_window = tmp->pf_ccr_window;
334178354Ssam			break;
335178354Ssam		}
336178354Ssam	}
337178354Ssam
338178354Ssam	if (tmp == NULL) {
339178354Ssam		if (pccard_mem_alloc(pf, PCCARD_CCR_SIZE, &pf->pf_pcmh))
340178354Ssam			goto bad;
341178354Ssam
342178354Ssam		if (pccard_mem_map(pf, PCCARD_MEM_ATTR, pf->ccr_base,
343178354Ssam		    PCCARD_CCR_SIZE, &pf->pf_pcmh, &pf->pf_ccr_offset,
344178354Ssam		    &pf->pf_ccr_window)) {
345178354Ssam			pccard_mem_free(pf, &pf->pf_pcmh);
346178354Ssam			goto bad;
347178354Ssam		}
348178354Ssam	}
349178354Ssam
350178354Ssam	reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX);
351178354Ssam	reg |= PCCARD_CCR_OPTION_LEVIREQ;
352178354Ssam	if (pccard_mfc(pf->sc)) {
353178354Ssam		reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE |
354178354Ssam			PCCARD_CCR_OPTION_ADDR_DECODE);
355178354Ssam		if (pf->ih_fct)
356178354Ssam			reg |= PCCARD_CCR_OPTION_IREQ_ENABLE;
357170530Ssam
358170530Ssam	}
359170530Ssam	pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
360170530Ssam
361178354Ssam	reg = 0;
362170530Ssam
363170530Ssam	if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0)
364170530Ssam		reg |= PCCARD_CCR_STATUS_IOIS8;
365170530Ssam	if (pf->cfe->flags & PCCARD_CFE_AUDIO)
366170530Ssam		reg |= PCCARD_CCR_STATUS_AUDIO;
367170530Ssam	pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg);
368170530Ssam
369186107Ssam	pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0);
370178354Ssam
371178354Ssam	if (pccard_mfc(pf->sc)) {
372178354Ssam		long tmp, iosize;
373206617Srpaulo
374170530Ssam		tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
375170530Ssam		/* round up to nearest (2^n)-1 */
376170530Ssam		for (iosize = 1; iosize < tmp; iosize <<= 1)
377170530Ssam			;
378170530Ssam		iosize--;
379178354Ssam
380170530Ssam		pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
381170530Ssam				 pf->pf_mfc_iobase & 0xff);
382170530Ssam		pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
383170530Ssam				 (pf->pf_mfc_iobase >> 8) & 0xff);
384170530Ssam		pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
385170530Ssam		pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
386170530Ssam
387170530Ssam		pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
388170530Ssam	}
389170530Ssam
390170530Ssam#ifdef PCCARDDEBUG
391178354Ssam	if (pccard_debug) {
392170530Ssam		STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
393178354Ssam			device_printf(tmp->sc->dev,
394178354Ssam			    "function %d CCR at %d offset %x: "
395178354Ssam			    "%x %x %x %x, %x %x %x %x, %x\n",
396170530Ssam			    tmp->number, tmp->pf_ccr_window,
397170530Ssam			    tmp->pf_ccr_offset,
398170530Ssam			    pccard_ccr_read(tmp, 0x00),
399170530Ssam			    pccard_ccr_read(tmp, 0x02),
400170530Ssam			    pccard_ccr_read(tmp, 0x04),
401170530Ssam			    pccard_ccr_read(tmp, 0x06),
402170530Ssam			    pccard_ccr_read(tmp, 0x0A),
403170530Ssam			    pccard_ccr_read(tmp, 0x0C),
404170530Ssam			    pccard_ccr_read(tmp, 0x0E),
405170530Ssam			    pccard_ccr_read(tmp, 0x10),
406170530Ssam			    pccard_ccr_read(tmp, 0x12));
407170530Ssam		}
408170530Ssam	}
409170530Ssam#endif
410170530Ssam
411187991Ssam	pf->pf_flags |= PFF_ENABLED;
412170530Ssam	return (0);
413170530Ssam
414170530Ssam bad:
415170530Ssam	/*
416187991Ssam	 * Decrement the reference count, and power down the socket, if
417170530Ssam	 * necessary.
418170530Ssam	 */
419170530Ssam	if (--pf->sc->sc_enabled_count == 0)
420170530Ssam		POWER_DISABLE_SOCKET(device_get_parent(pf->sc->dev),
421188777Ssam		    pf->sc->dev);
422170530Ssam	DEVPRINTF((pf->sc->dev, "--enabled_count = %d\n",
423188777Ssam		 pf->sc->sc_enabled_count));
424188777Ssam
425188777Ssam	return (1);
426188777Ssam}
427188777Ssam
428188777Ssam/* Disable PCCARD function. */
429188777Ssamvoid
430188777Ssampccard_function_disable(pf)
431188777Ssam	struct pccard_function *pf;
432188782Ssam{
433188782Ssam	struct pccard_function *tmp;
434188777Ssam
435188777Ssam	if (pf->cfe == NULL)
436188777Ssam		panic("pccard_function_enable: function not initialized");
437170530Ssam
438170530Ssam	if ((pf->pf_flags & PFF_ENABLED) == 0) {
439170530Ssam		/*
440178354Ssam		 * Don't do anything if we're already disabled.
441170530Ssam		 */
442170530Ssam		return;
443170530Ssam	}
444170530Ssam
445178354Ssam	/*
446170530Ssam	 * it's possible for different functions' CCRs to be in the same
447170530Ssam	 * underlying page.  Check for that.  Note we mark us as disabled
448170530Ssam	 * first to avoid matching ourself.
449170530Ssam	 */
450170530Ssam
451170530Ssam	pf->pf_flags &= ~PFF_ENABLED;
452170530Ssam	STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
453170530Ssam		if ((tmp->pf_flags & PFF_ENABLED) &&
454170530Ssam		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
455170530Ssam		    ((pf->ccr_base + PCCARD_CCR_SIZE) <=
456170530Ssam		(tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize)))
457178354Ssam			break;
458170530Ssam	}
459170530Ssam
460170530Ssam	/* Not used by anyone else; unmap the CCR. */
461170530Ssam	if (tmp == NULL) {
462178354Ssam		pccard_mem_unmap(pf, pf->pf_ccr_window);
463170530Ssam		pccard_mem_free(pf, &pf->pf_pcmh);
464178354Ssam	}
465178354Ssam
466178354Ssam	/*
467170530Ssam	 * Decrement the reference count, and power down the socket, if
468170530Ssam	 * necessary.
469170530Ssam	 */
470170530Ssam	if (--pf->sc->sc_enabled_count == 0)
471170530Ssam		POWER_DISABLE_SOCKET(device_get_parent(pf->sc->dev),
472170530Ssam		    pf->sc->dev);
473170530Ssam	DEVPRINTF((pf->sc->dev, "--enabled_count = %d\n",
474170530Ssam	    pf->sc->sc_enabled_count));
475170530Ssam}
476170530Ssam
477170530Ssamint
478170530Ssampccard_io_map(pf, width, offset, size, pcihp, windowp)
479170530Ssam	struct pccard_function *pf;
480170530Ssam	int width;
481170530Ssam	bus_addr_t offset;
482170530Ssam	bus_size_t size;
483170530Ssam	struct pccard_io_handle *pcihp;
484170530Ssam	int *windowp;
485170530Ssam{
486170530Ssam	int reg;
487170530Ssam
488170530Ssam	if (pccard_chip_io_map(pf->sc->pct, pf->sc->pch,
489170530Ssam	    width, offset, size, pcihp, windowp))
490170530Ssam		return (1);
491170530Ssam
492189377Ssam	/*
493189377Ssam	 * XXX in the multifunction multi-iospace-per-function case, this
494189377Ssam	 * needs to cooperate with io_alloc to make sure that the spaces
495189377Ssam	 * don't overlap, and that the ccr's are set correctly
496189377Ssam	 */
497189377Ssam
498189377Ssam	if (pccard_mfc(pf->sc)) {
499189377Ssam		long tmp, iosize;
500189377Ssam
501189377Ssam		if (pf->pf_mfc_iomax == 0) {
502189377Ssam			pf->pf_mfc_iobase = pcihp->addr + offset;
503189377Ssam			pf->pf_mfc_iomax = pf->pf_mfc_iobase + size;
504176653Ssam		} else {
505178354Ssam			/* this makes the assumption that nothing overlaps */
506176653Ssam			if (pf->pf_mfc_iobase > pcihp->addr + offset)
507176653Ssam				pf->pf_mfc_iobase = pcihp->addr + offset;
508178354Ssam			if (pf->pf_mfc_iomax < pcihp->addr + offset + size)
509176653Ssam				pf->pf_mfc_iomax = pcihp->addr + offset + size;
510176653Ssam		}
511176653Ssam
512176653Ssam		tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
513176653Ssam		/* round up to nearest (2^n)-1 */
514176653Ssam		for (iosize = 1; iosize >= tmp; iosize <<= 1)
515176653Ssam			;
516176653Ssam		iosize--;
517176653Ssam
518176653Ssam		pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
519176653Ssam				 pf->pf_mfc_iobase & 0xff);
520176653Ssam		pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
521176653Ssam				 (pf->pf_mfc_iobase >> 8) & 0xff);
522176653Ssam		pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
523176653Ssam		pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
524176653Ssam
525176653Ssam		pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
526176653Ssam
527176653Ssam		reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION);
528176653Ssam		reg |= PCCARD_CCR_OPTION_ADDR_DECODE;
529176653Ssam		pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
530178354Ssam	}
531178354Ssam	return (0);
532176653Ssam}
533176653Ssam
534176653Ssamvoid
535176653Ssampccard_io_unmap(pf, window)
536176653Ssam	struct pccard_function *pf;
537178354Ssam	int window;
538176653Ssam{
539176653Ssam
540176653Ssam	pccard_chip_io_unmap(pf->sc->pct, pf->sc->pch, window);
541176653Ssam
542176653Ssam	/* XXX Anything for multi-function cards? */
543176653Ssam}
544176653Ssam
545176653Ssamvoid *
546176653Ssampccard_intr_establish(pf, ipl, ih_fct, ih_arg)
547176653Ssam	struct pccard_function *pf;
548176653Ssam	int ipl;
549176653Ssam	int (*ih_fct)(void *);
550176653Ssam	void *ih_arg;
551176653Ssam{
552189377Ssam	void *ret;
553189377Ssam
554189377Ssam	/* behave differently if this is a multifunction card */
555189377Ssam
556189377Ssam	if (pccard_mfc(pf->sc)) {
557189377Ssam		int s, ihcnt, hiipl, reg;
558189377Ssam		struct pccard_function *pf2;
559189377Ssam
560189377Ssam		/*
561189377Ssam		 * mask all the ipl's which are already used by this card,
562189377Ssam		 * and find the highest ipl number (lowest priority)
563189377Ssam		 */
564189377Ssam
565189377Ssam		ihcnt = 0;
566189377Ssam		s = 0;		/* this is only here to keep the compiler
567176653Ssam				   happy */
568176653Ssam		hiipl = 0;	/* this is only here to keep the compiler
569178354Ssam				   happy */
570178354Ssam
571178354Ssam		STAILQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
572170530Ssam			if (pf2->ih_fct) {
573170530Ssam				DEVPRINTF((pf2->sc->dev,
574170530Ssam				    "function %d has ih_fct %p\n",
575170530Ssam				    pf2->number, pf2->ih_fct));
576170530Ssam
577170530Ssam				if (ihcnt == 0) {
578170530Ssam					hiipl = pf2->ih_ipl;
579170530Ssam				} else {
580170530Ssam					if (pf2->ih_ipl > hiipl)
581170530Ssam						hiipl = pf2->ih_ipl;
582178354Ssam				}
583170530Ssam
584178354Ssam				ihcnt++;
585170530Ssam			}
586170530Ssam		}
587170530Ssam
588170530Ssam		/*
589178354Ssam		 * establish the real interrupt, changing the ipl if
590170530Ssam		 * necessary
591170530Ssam		 */
592170530Ssam
593170530Ssam		if (ihcnt == 0) {
594170530Ssam#ifdef DIAGNOSTIC
595178354Ssam			if (pf->sc->ih != NULL)
596170530Ssam				panic("card has intr handler, but no function does");
597170530Ssam#endif
598170530Ssam			s = splhigh();
599170530Ssam
600170530Ssam			/* set up the handler for the new function */
601170530Ssam
602170530Ssam			pf->ih_fct = ih_fct;
603170530Ssam			pf->ih_arg = ih_arg;
604170530Ssam			pf->ih_ipl = ipl;
605170530Ssam
606170530Ssam			pf->sc->ih = pccard_chip_intr_establish(pf->sc->pct,
607170530Ssam			    pf->sc->pch, pf, ipl, PCCARD_CARD_INTR, pf->sc);
608170530Ssam			splx(s);
609170530Ssam		} else if (ipl > hiipl) {
610178354Ssam#ifdef DIAGNOSTIC
611170530Ssam			if (pf->sc->ih == NULL)
612170530Ssam				panic("functions have ih, but the card does not");
613170530Ssam#endif
614170530Ssam
615170530Ssam			/* XXX need #ifdef for splserial on x86 */
616170530Ssam			s = splhigh();
617170530Ssam
618170530Ssam			pccard_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
619170530Ssam						      pf->sc->ih);
620178354Ssam
621170530Ssam			/* set up the handler for the new function */
622170530Ssam			pf->ih_fct = ih_fct;
623170530Ssam			pf->ih_arg = ih_arg;
624178354Ssam			pf->ih_ipl = ipl;
625178354Ssam
626170530Ssam			pf->sc->ih = pccard_chip_intr_establish(pf->sc->pct,
627178354Ssam			    pf->sc->pch, pf, ipl, PCCARD_CARD_INTR, pf->sc);
628178354Ssam
629170530Ssam			splx(s);
630178354Ssam		} else {
631178354Ssam			s = splhigh();
632178354Ssam
633178354Ssam			/* set up the handler for the new function */
634178354Ssam
635178354Ssam			pf->ih_fct = ih_fct;
636178354Ssam			pf->ih_arg = ih_arg;
637178354Ssam			pf->ih_ipl = ipl;
638178354Ssam
639178354Ssam			splx(s);
640178354Ssam		}
641178354Ssam
642178354Ssam		ret = pf->sc->ih;
643178354Ssam
644178354Ssam		if (ret != NULL) {
645178354Ssam			reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION);
646178354Ssam			reg |= PCCARD_CCR_OPTION_IREQ_ENABLE;
647178354Ssam			pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
648178354Ssam
649178354Ssam			reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
650178354Ssam			reg |= PCCARD_CCR_STATUS_INTRACK;
651178354Ssam			pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg);
652178354Ssam		}
653178354Ssam	} else {
654178354Ssam		ret = pccard_chip_intr_establish(pf->sc->pct, pf->sc->pch,
655178354Ssam		    pf, ipl, ih_fct, ih_arg);
656178354Ssam	}
657178354Ssam
658178354Ssam	return (ret);
659178354Ssam}
660170530Ssam
661178354Ssamvoid
662170530Ssampccard_intr_disestablish(pf, ih)
663178354Ssam	struct pccard_function *pf;
664178354Ssam	void *ih;
665178354Ssam{
666178354Ssam	/* behave differently if this is a multifunction card */
667178354Ssam
668178354Ssam	if (pccard_mfc(pf->sc)) {
669178354Ssam		int s, ihcnt, hiipl;
670178354Ssam		struct pccard_function *pf2;
671178354Ssam
672178354Ssam		/*
673178354Ssam		 * mask all the ipl's which are already used by this card,
674178354Ssam		 * and find the highest ipl number (lowest priority).  Skip
675178354Ssam		 * the current function.
676178354Ssam		 */
677178354Ssam
678178354Ssam		ihcnt = 0;
679178354Ssam		s = 0;		/* this is only here to keep the compipler
680178354Ssam				   happy */
681178354Ssam		hiipl = 0;	/* this is only here to keep the compipler
682178354Ssam				   happy */
683178354Ssam
684178354Ssam		STAILQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
685178354Ssam			if (pf2 == pf)
686178354Ssam				continue;
687178354Ssam
688178354Ssam			if (pf2->ih_fct) {
689178354Ssam				if (ihcnt == 0) {
690178354Ssam					hiipl = pf2->ih_ipl;
691178354Ssam				} else {
692178354Ssam					if (pf2->ih_ipl > hiipl)
693178354Ssam						hiipl = pf2->ih_ipl;
694178354Ssam				}
695178354Ssam				ihcnt++;
696178354Ssam			}
697178354Ssam		}
698178354Ssam
699178354Ssam		/*
700178354Ssam		 * if the ih being removed is lower priority than the lowest
701170530Ssam		 * priority remaining interrupt, up the priority.
702170530Ssam		 */
703170530Ssam
704170530Ssam		/* ihcnt is the number of interrupt handlers *not* including
705170530Ssam		   the one about to be removed. */
706170530Ssam
707178354Ssam		if (ihcnt == 0) {
708178354Ssam			int reg;
709170530Ssam
710170530Ssam#ifdef DIAGNOSTIC
711178354Ssam			if (pf->sc->ih == NULL)
712170530Ssam				panic("disestablishing last function, but card has no ih");
713170530Ssam#endif
714170530Ssam			pccard_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
715170530Ssam			    pf->sc->ih);
716170530Ssam
717170530Ssam			reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION);
718170530Ssam			reg &= ~PCCARD_CCR_OPTION_IREQ_ENABLE;
719170530Ssam			pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
720170530Ssam
721170530Ssam			pf->ih_fct = NULL;
722170530Ssam			pf->ih_arg = NULL;
723178354Ssam
724170530Ssam			pf->sc->ih = NULL;
725170530Ssam		} else if (pf->ih_ipl > hiipl) {
726170530Ssam#ifdef DIAGNOSTIC
727170530Ssam			if (pf->sc->ih == NULL)
728178354Ssam				panic("changing ih ipl, but card has no ih");
729178354Ssam#endif
730178354Ssam			/* XXX need #ifdef for splserial on x86 */
731178354Ssam			s = splhigh();
732178354Ssam
733184302Ssam			pccard_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
734184302Ssam			    pf->sc->ih);
735184302Ssam			pf->sc->ih = pccard_chip_intr_establish(pf->sc->pct,
736184302Ssam			    pf->sc->pch, pf, hiipl, PCCARD_CARD_INTR, pf->sc);
737184302Ssam
738184302Ssam			/* null out the handler for this function */
739184302Ssam
740184302Ssam			pf->ih_fct = NULL;
741184302Ssam			pf->ih_arg = NULL;
742178354Ssam
743184302Ssam			splx(s);
744184302Ssam		} else {
745184302Ssam			s = splhigh();
746184302Ssam
747184302Ssam			pf->ih_fct = NULL;
748184302Ssam			pf->ih_arg = NULL;
749184302Ssam
750184302Ssam			splx(s);
751184302Ssam		}
752184302Ssam	} else {
753184302Ssam		pccard_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih);
754178354Ssam	}
755170530Ssam}
756170530Ssam
757178354Ssamint
758178354Ssampccard_card_intr(arg)
759178354Ssam	void *arg;
760178354Ssam{
761170530Ssam	struct pccard_softc *sc = arg;
762170530Ssam	struct pccard_function *pf;
763178354Ssam	int reg, ret, ret2;
764178354Ssam
765178354Ssam	ret = 0;
766178354Ssam
767178354Ssam	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
768178354Ssam		if (pf->ih_fct != NULL &&
769178354Ssam		    (pf->ccr_mask & (1 << (PCCARD_CCR_STATUS / 2)))) {
770178354Ssam			reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
771178354Ssam			if (reg & PCCARD_CCR_STATUS_INTR) {
772178354Ssam				ret2 = (*pf->ih_fct)(pf->ih_arg);
773178354Ssam				if (ret2 != 0 && ret == 0)
774178354Ssam					ret = ret2;
775178354Ssam				reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
776178354Ssam				pccard_ccr_write(pf, PCCARD_CCR_STATUS,
777178354Ssam				    reg & ~PCCARD_CCR_STATUS_INTR);
778178354Ssam			}
779178354Ssam		}
780178354Ssam	}
781170530Ssam
782170530Ssam	return (ret);
783170530Ssam}
784170530Ssam
785170530Ssam#ifdef PCCARDDEBUG
786170530Ssamint
787170530Ssampccard_card_intrdebug(arg)
788170530Ssam	void *arg;
789170530Ssam{
790170530Ssam	struct pccard_softc *sc = arg;
791170530Ssam	struct pccard_function *pf;
792170530Ssam	int reg, ret, ret2;
793170530Ssam
794170530Ssam	ret = 0;
795170530Ssam
796170530Ssam	STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
797170530Ssam		device_printf(sc->dev,
798170530Ssam		    "intr flags=%x fct=%d cor=%02x csr=%02x pin=%02x",
799170530Ssam		    pf->pf_flags, pf->number,
800170530Ssam		    pccard_ccr_read(pf, PCCARD_CCR_OPTION),
801170530Ssam		    pccard_ccr_read(pf, PCCARD_CCR_STATUS),
802170530Ssam		    pccard_ccr_read(pf, PCCARD_CCR_PIN));
803170530Ssam		if (pf->ih_fct != NULL &&
804170530Ssam		    (pf->ccr_mask & (1 << (PCCARD_CCR_STATUS / 2)))) {
805170530Ssam			reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
806170530Ssam			if (reg & PCCARD_CCR_STATUS_INTR) {
807170530Ssam				ret2 = (*pf->ih_fct)(pf->ih_arg);
808178354Ssam				if (ret2 != 0 && ret == 0)
809170530Ssam					ret = ret2;
810170530Ssam				reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
811170530Ssam				printf("; csr %02x->%02x",
812170530Ssam				    reg, reg & ~PCCARD_CCR_STATUS_INTR);
813170530Ssam				pccard_ccr_write(pf, PCCARD_CCR_STATUS,
814170530Ssam				    reg & ~PCCARD_CCR_STATUS_INTR);
815170530Ssam			}
816170530Ssam		}
817170530Ssam		printf("\n");
818170530Ssam	}
819170530Ssam
820170530Ssam	return (ret);
821170530Ssam}
822170530Ssam#endif
823170530Ssam
824170530Ssam#define PCCARD_NPORT	2
825170530Ssam#define PCCARD_NMEM	5
826170530Ssam#define PCCARD_NIRQ	1
827170530Ssam#define PCCARD_NDRQ	0
828170530Ssam
829170530Ssamstatic int
830170530Ssampccard_add_children(device_t dev, int busno)
831170530Ssam{
832170530Ssam	return 0;
833170530Ssam}
834170530Ssam
835170530Ssamstatic int
836170530Ssampccard_probe(device_t dev)
837170530Ssam{
838170530Ssam	device_set_desc(dev, "PC Card bus -- newconfig version");
839178354Ssam	return pccard_add_children(dev, device_get_unit(dev));
840178354Ssam}
841170530Ssam
842170530Ssamstatic void
843170530Ssampccard_print_resources(struct resource_list *rl, const char *name, int type,
844170530Ssam    int count, const char *format)
845170530Ssam{
846170530Ssam	struct resource_list_entry *rle;
847170530Ssam	int printed;
848170530Ssam	int i;
849178354Ssam
850170530Ssam	printed = 0;
851170530Ssam	for (i = 0; i < count; i++) {
852184302Ssam		rle = resource_list_find(rl, type, i);
853184302Ssam		if (rle) {
854170530Ssam			if (printed == 0)
855170530Ssam				printf(" %s ", name);
856170530Ssam			else if (printed > 0)
857178354Ssam				printf(",");
858170530Ssam			printed++;
859170530Ssam			printf(format, rle->start);
860178354Ssam			if (rle->count > 1) {
861170530Ssam				printf("-");
862184302Ssam				printf(format, rle->start + rle->count - 1);
863170530Ssam			}
864170530Ssam		} else if (i > 3) {
865178354Ssam			/* check the first few regardless */
866184302Ssam			break;
867170530Ssam		}
868170530Ssam	}
869170530Ssam}
870170530Ssam
871170530Ssamstatic int
872170530Ssampccard_print_child(device_t dev, device_t child)
873170530Ssam{
874170530Ssam	struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child);
875178354Ssam	struct resource_list *rl = &devi->resources;
876170530Ssam	int retval = 0;
877170530Ssam
878170530Ssam	retval += bus_print_child_header(dev, child);
879170530Ssam	retval += printf(" at");
880170530Ssam
881170530Ssam	if (devi) {
882170530Ssam		pccard_print_resources(rl, "port", SYS_RES_IOPORT,
883170530Ssam		    PCCARD_NPORT, "%#lx");
884170530Ssam		pccard_print_resources(rl, "iomem", SYS_RES_MEMORY,
885170530Ssam		    PCCARD_NMEM, "%#lx");
886170530Ssam		pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ,
887170530Ssam		    "%ld");
888170530Ssam		pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ,
889170530Ssam		    "%ld");
890170530Ssam		retval += printf(" slot %d", devi->slotnum);
891170530Ssam	}
892170530Ssam
893170530Ssam	retval += bus_print_child_footer(dev, child);
894170530Ssam
895170530Ssam	return (retval);
896170530Ssam}
897170530Ssam
898170530Ssamstatic int
899170530Ssampccard_set_resource(device_t dev, device_t child, int type, int rid,
900170530Ssam		 u_long start, u_long count)
901170530Ssam{
902170530Ssam	struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child);
903170530Ssam	struct resource_list *rl = &devi->resources;
904178354Ssam
905170530Ssam	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
906170530Ssam	    && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
907170530Ssam		return EINVAL;
908170530Ssam	if (rid < 0)
909170530Ssam		return EINVAL;
910170530Ssam	if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT)
911195618Srpaulo		return EINVAL;
912195618Srpaulo	if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM)
913195618Srpaulo		return EINVAL;
914195618Srpaulo	if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ)
915195618Srpaulo		return EINVAL;
916195618Srpaulo	if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ)
917170530Ssam		return EINVAL;
918170530Ssam
919170530Ssam	resource_list_add(rl, type, rid, start, start + count - 1, count);
920170530Ssam
921170530Ssam	return 0;
922170530Ssam}
923170530Ssam
924195618Srpaulostatic int
925170530Ssampccard_get_resource(device_t dev, device_t child, int type, int rid,
926170530Ssam    u_long *startp, u_long *countp)
927170530Ssam{
928170530Ssam	struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child);
929170530Ssam	struct resource_list *rl = &devi->resources;
930186904Ssam	struct resource_list_entry *rle;
931186904Ssam
932186904Ssam	rle = resource_list_find(rl, type, rid);
933186904Ssam	if (!rle)
934186904Ssam		return ENOENT;
935186904Ssam
936186904Ssam	if (startp)
937186904Ssam		*startp = rle->start;
938186904Ssam	if (countp)
939186904Ssam		*countp = rle->count;
940186904Ssam
941186904Ssam	return 0;
942186904Ssam}
943186904Ssam
944170530Ssamstatic void
945170530Ssampccard_delete_resource(device_t dev, device_t child, int type, int rid)
946170530Ssam{
947170530Ssam	struct pccard_ivar *devi = (struct pccard_ivar *) device_get_ivars(child);
948178354Ssam	struct resource_list *rl = &devi->resources;
949170530Ssam	resource_list_delete(rl, type, rid);
950170530Ssam}
951170530Ssam
952178354Ssamstatic device_method_t pccard_methods[] = {
953170530Ssam	/* Device interface */
954178354Ssam	DEVMETHOD(device_probe,		pccard_probe),
955178354Ssam	DEVMETHOD(device_attach,	bus_generic_attach),
956170530Ssam	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
957170530Ssam	DEVMETHOD(device_suspend,	bus_generic_suspend),
958170530Ssam	DEVMETHOD(device_resume,	bus_generic_resume),
959171409Ssam
960170530Ssam	/* Bus interface */
961170530Ssam	DEVMETHOD(bus_print_child,	pccard_print_child),
962170530Ssam	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
963170530Ssam	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
964170530Ssam	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
965170530Ssam	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
966170530Ssam	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
967178354Ssam	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
968170530Ssam	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
969178354Ssam	DEVMETHOD(bus_set_resource,	pccard_set_resource),
970171409Ssam	DEVMETHOD(bus_get_resource,	pccard_get_resource),
971178354Ssam	DEVMETHOD(bus_delete_resource,	pccard_delete_resource),
972170530Ssam
973171409Ssam	{ 0, 0 }
974186904Ssam};
975186904Ssam
976186904Ssamstatic driver_t pccard_driver = {
977186904Ssam	"pccard",
978186904Ssam	pccard_methods,
979186904Ssam	1,			/* no softc */
980186904Ssam};
981186904Ssam
982186904Ssamdevclass_t	pccard_devclass;
983186904Ssam
984186904SsamDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
985186904SsamDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0);
986186904SsamDRIVER_MODULE(pccard, pccbb, pccard_driver, pccard_devclass, 0, 0);
987186904SsamDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0);
988186904Ssam