1139749Simp/*-
2133553Simp * Copyright (c) 2002-2004 M. Warner Losh.
3133553Simp * All rights reserved.
4133553Simp *
5133553Simp * Redistribution and use in source and binary forms, with or without
6133553Simp * modification, are permitted provided that the following conditions
7133553Simp * are met:
8133553Simp * 1. Redistributions of source code must retain the above copyright
9140035Simp *    notice, this list of conditions and the following disclaimer.
10133553Simp * 2. Redistributions in binary form must reproduce the above copyright
11140035Simp *    notice, this list of conditions and the following disclaimer in the
12140035Simp *    documentation and/or other materials provided with the distribution.
13133553Simp *
14133553Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15133553Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16133553Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17140035Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18140035Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19133553Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20133553Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21133553Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22133553Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23133553Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24133553Simp * SUCH DAMAGE.
25133553Simp */
26133553Simp
27133553Simp/*
28133553Simp * Driver for ISA to PCMCIA bridges compliant with the Intel ExCA
29133553Simp * specification.
30133553Simp */
31133553Simp
32133553Simp#include <sys/cdefs.h>
33133553Simp__FBSDID("$FreeBSD$");
34133553Simp
35133553Simp#include <sys/param.h>
36133553Simp#include <sys/systm.h>
37133553Simp#include <sys/proc.h>
38133553Simp#include <sys/condvar.h>
39133553Simp#include <sys/errno.h>
40133553Simp#include <sys/kernel.h>
41133553Simp#include <sys/lock.h>
42133553Simp#include <sys/malloc.h>
43133553Simp#include <sys/module.h>
44133553Simp#include <sys/mutex.h>
45133553Simp#include <sys/sysctl.h>
46133553Simp#include <sys/kthread.h>
47133553Simp#include <sys/bus.h>
48133553Simp#include <machine/bus.h>
49133553Simp#include <sys/rman.h>
50133553Simp#include <machine/resource.h>
51133553Simp
52133553Simp#include <isa/isavar.h>
53133553Simp
54133553Simp#include <dev/pccard/pccardreg.h>
55133553Simp#include <dev/pccard/pccardvar.h>
56133553Simp
57133553Simp#include <dev/exca/excareg.h>
58133553Simp#include <dev/exca/excavar.h>
59133553Simp
60133553Simp#include <dev/pccbb/pccbbreg.h>
61133553Simp#include <dev/pccbb/pccbbvar.h>
62133553Simp
63133553Simp#include "power_if.h"
64133553Simp#include "card_if.h"
65133553Simp
66133553Simp/*****************************************************************************
67133553Simp * Configurable parameters.
68133553Simp *****************************************************************************/
69133553Simp
70133553Simp/* sysctl vars */
71248085Smariusstatic SYSCTL_NODE(_hw, OID_AUTO, pcic, CTLFLAG_RD, 0, "PCIC parameters");
72133553Simp
73133553Simpstatic int isa_intr_mask = EXCA_INT_MASK_ALLOWED;
74133553SimpTUNABLE_INT("hw.cbb.intr_mask", &isa_intr_mask);
75133553SimpSYSCTL_INT(_hw_pcic, OID_AUTO, intr_mask, CTLFLAG_RD, &isa_intr_mask, 0,
76133553Simp    "Mask of allowable interrupts for this laptop.  The default is generally\n\
77133553Simpcorrect, but some laptops do not route all the IRQ pins to the bridge to\n\
78133553Simpsave wires.  Sometimes you need a more restrictive mask because some of the\n\
79133553Simphardware in your laptop may not have a driver so its IRQ might not be\n\
80133553Simpallocated.");
81133553Simp
82151308Simp/*
83151308Simp * CL-PD6722's VSENSE method
84151308Simp *     0: NO VSENSE (assume a 5.0V card always)
85151308Simp *     1: 6710's method (default)
86151308Simp *     2: 6729's method
87151308Simp */
88151308Simpint pcic_pd6722_vsense = 1;
89151308SimpTUNABLE_INT("hw.pcic.pd6722_vsense", &pcic_pd6722_vsense);
90151308SimpSYSCTL_INT(_hw_pcic, OID_AUTO, pd6722_vsense, CTLFLAG_RDTUN,
91151308Simp    &pcic_pd6722_vsense, 1,
92151308Simp    "Select CL-PD6722's VSENSE method.  VSENSE is used to determine the\n\
93151308Simpvolatage of inserted cards.  The CL-PD6722 has two methods to determine the\n\
94151308Simpvoltage of the card.  0 means assume a 5.0V card and do not check.  1 means\n\
95151308Simpuse the same method that the CL-PD6710 uses (default).  2 means use the\n\
96151308Simpsame method as the CL-PD6729.  2 is documented in the datasheet as being\n\
97151308Simpthe correct way, but 1 seems to give better results on more laptops.");
98151308Simp
99133553Simp/*****************************************************************************
100133553Simp * End of configurable parameters.
101133553Simp *****************************************************************************/
102133553Simp
103133553Simp#define	DPRINTF(x) do { if (cbb_debug) printf x; } while (0)
104133553Simp#define	DEVPRINTF(x) do { if (cbb_debug) device_printf x; } while (0)
105133553Simp
106151308Simp/* XXX Not sure that PNP0E03 should be claimed, except maybe on pc98 */
107133553Simpstatic struct isa_pnp_id pcic_ids[] = {
108133553Simp	{EXCA_PNP_ACTIONTEC,		NULL},		/* AEI0218 */
109133553Simp	{EXCA_PNP_IBM3765,		NULL},		/* IBM3765 */
110133553Simp	{EXCA_PNP_82365,		NULL},		/* PNP0E00 */
111133553Simp	{EXCA_PNP_CL_PD6720,		NULL},		/* PNP0E01 */
112133553Simp	{EXCA_PNP_VLSI_82C146,		NULL},		/* PNP0E02 */
113133553Simp	{EXCA_PNP_82365_CARDBUS,	NULL},		/* PNP0E03 */
114133553Simp	{EXCA_PNP_SCM_SWAPBOX,		NULL},		/* SCM0469 */
115151308Simp	{EXCA_NEC_PC9801_102,		NULL},		/* NEC8091 */
116151308Simp	{EXCA_NEC_PC9821RA_E01,         NULL},          /* NEC8121 */
117133553Simp	{0}
118133553Simp};
119133553Simp
120133553Simp/************************************************************************/
121133553Simp/* Probe/Attach								*/
122133553Simp/************************************************************************/
123133553Simp
124151308Simpstatic int
125151308Simpcbb_isa_activate(device_t dev)
126151308Simp{
127151308Simp	struct cbb_softc *sc = device_get_softc(dev);
128133553Simp	struct resource *res;
129133553Simp	int rid;
130133553Simp	int i;
131133553Simp
132133553Simp	/* A little bogus, but go ahead and get the irq for CSC events */
133133553Simp	rid = 0;
134133553Simp	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
135133553Simp	if (res == NULL) {
136133553Simp		/*
137133553Simp		 * No IRQ specified, find one.  This can be due to the PnP
138133553Simp		 * data not specifying any IRQ, or the default kernel not
139133553Simp		 * assinging an IRQ.
140133553Simp		 */
141151308Simp		for (i = 0; i < 16 && res == NULL; i++) {
142133553Simp			if (((1 << i) & isa_intr_mask) == 0)
143133553Simp				continue;
144133553Simp			res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, i, i,
145133553Simp			    1, RF_ACTIVE);
146133553Simp		}
147133553Simp	}
148151308Simp	if (res == NULL)
149151308Simp		return (ENXIO);
150151308Simp	sc->irq_res = res;
151151308Simp	rid = 0;
152151308Simp	res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
153133553Simp	if (res == NULL) {
154151308Simp		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
155151308Simp		sc->irq_res = NULL;
156151308Simp		device_printf(dev, "Cannot allocate I/O\n");
157133553Simp		return (ENOMEM);
158133553Simp	}
159151457Simp	sc->bst = rman_get_bustag(res);
160151457Simp	sc->bsh = rman_get_bushandle(res);
161151308Simp	sc->base_res = res;
162151308Simp	return (0);
163133553Simp}
164133553Simp
165133553Simpstatic void
166133553Simpcbb_isa_deactivate(device_t dev)
167133553Simp{
168151308Simp	struct cbb_softc *sc = device_get_softc(dev);
169151308Simp
170151308Simp	if (sc->irq_res)
171151308Simp		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
172151308Simp	sc->irq_res = NULL;
173151308Simp	if (sc->base_res)
174151308Simp		bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->base_res);
175151308Simp	sc->base_res = NULL;
176133553Simp}
177133553Simp
178133553Simpstatic int
179133553Simpcbb_isa_probe(device_t dev)
180133553Simp{
181133553Simp	int error;
182133553Simp	struct cbb_softc *sc = device_get_softc(dev);
183133553Simp
184133553Simp	/* Check isapnp ids */
185133553Simp	error = ISA_PNP_PROBE(device_get_parent(dev), dev, pcic_ids);
186133553Simp	if (error != 0 && error != ENOENT)
187133553Simp		return (error);
188133553Simp
189133553Simp	error = cbb_isa_activate(dev);
190133553Simp	if (error != 0)
191133553Simp		return (error);
192133553Simp
193133553Simp	/* Check to make sure that we have actual hardware */
194133553Simp	error = exca_probe_slots(dev, &sc->exca[0], sc->bst, sc->bsh);
195133553Simp	cbb_isa_deactivate(dev);
196133553Simp	return (error);
197133553Simp}
198133553Simp
199133553Simpstatic int
200133553Simpcbb_isa_attach(device_t dev)
201133553Simp{
202133553Simp	return (ENOMEM);
203133553Simp}
204133553Simp
205133553Simpstatic device_method_t cbb_methods[] = {
206133553Simp	/* Device interface */
207133553Simp	DEVMETHOD(device_probe,			cbb_isa_probe),
208133553Simp	DEVMETHOD(device_attach,		cbb_isa_attach),
209133553Simp	DEVMETHOD(device_detach,		cbb_detach),
210133553Simp	DEVMETHOD(device_suspend,		cbb_suspend),
211133553Simp	DEVMETHOD(device_resume,		cbb_resume),
212133553Simp
213133553Simp	/* bus methods */
214133553Simp	DEVMETHOD(bus_read_ivar,		cbb_read_ivar),
215133553Simp	DEVMETHOD(bus_write_ivar,		cbb_write_ivar),
216133553Simp	DEVMETHOD(bus_alloc_resource,		cbb_alloc_resource),
217133553Simp	DEVMETHOD(bus_release_resource,		cbb_release_resource),
218133553Simp	DEVMETHOD(bus_activate_resource,	cbb_activate_resource),
219133553Simp	DEVMETHOD(bus_deactivate_resource,	cbb_deactivate_resource),
220133553Simp	DEVMETHOD(bus_driver_added,		cbb_driver_added),
221133553Simp	DEVMETHOD(bus_child_detached,		cbb_child_detached),
222133553Simp	DEVMETHOD(bus_setup_intr,		cbb_setup_intr),
223133553Simp	DEVMETHOD(bus_teardown_intr,		cbb_teardown_intr),
224133553Simp	DEVMETHOD(bus_child_present,		cbb_child_present),
225133553Simp
226133553Simp	/* 16-bit card interface */
227133553Simp	DEVMETHOD(card_set_res_flags,		cbb_pcic_set_res_flags),
228133553Simp	DEVMETHOD(card_set_memory_offset,	cbb_pcic_set_memory_offset),
229133553Simp
230133553Simp	/* power interface */
231133553Simp	DEVMETHOD(power_enable_socket,		cbb_power_enable_socket),
232133553Simp	DEVMETHOD(power_disable_socket,		cbb_power_disable_socket),
233133553Simp
234229093Shselasky	DEVMETHOD_END
235133553Simp};
236133553Simp
237133553Simpstatic driver_t cbb_isa_driver = {
238133553Simp	"cbb",
239133553Simp	cbb_methods,
240133553Simp	sizeof(struct cbb_softc)
241133553Simp};
242133553Simp
243133553SimpDRIVER_MODULE(cbb, isa, cbb_isa_driver, cbb_devclass, 0, 0);
244133553SimpMODULE_DEPEND(cbb, exca, 1, 1, 1);
245