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: releng/11.0/sys/dev/pccbb/pccbb_isa.c 277234 2015-01-16 06:19:39Z imp $");
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
54261790Sjhb#include <dev/pci/pcivar.h>
55261790Sjhb#include <dev/pci/pcib_private.h>
56261790Sjhb
57133553Simp#include <dev/pccard/pccardreg.h>
58133553Simp#include <dev/pccard/pccardvar.h>
59133553Simp
60133553Simp#include <dev/exca/excareg.h>
61133553Simp#include <dev/exca/excavar.h>
62133553Simp
63133553Simp#include <dev/pccbb/pccbbreg.h>
64133553Simp#include <dev/pccbb/pccbbvar.h>
65133553Simp
66133553Simp#include "power_if.h"
67133553Simp#include "card_if.h"
68133553Simp
69133553Simp/*****************************************************************************
70133553Simp * Configurable parameters.
71133553Simp *****************************************************************************/
72133553Simp
73133553Simp/* sysctl vars */
74227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, pcic, CTLFLAG_RD, 0, "PCIC parameters");
75133553Simp
76133553Simpstatic int isa_intr_mask = EXCA_INT_MASK_ALLOWED;
77267992ShselaskySYSCTL_INT(_hw_pcic, OID_AUTO, intr_mask, CTLFLAG_RDTUN, &isa_intr_mask, 0,
78133553Simp    "Mask of allowable interrupts for this laptop.  The default is generally\n\
79133553Simpcorrect, but some laptops do not route all the IRQ pins to the bridge to\n\
80133553Simpsave wires.  Sometimes you need a more restrictive mask because some of the\n\
81133553Simphardware in your laptop may not have a driver so its IRQ might not be\n\
82133553Simpallocated.");
83133553Simp
84151308Simp/*
85151308Simp * CL-PD6722's VSENSE method
86151308Simp *     0: NO VSENSE (assume a 5.0V card always)
87151308Simp *     1: 6710's method (default)
88151308Simp *     2: 6729's method
89151308Simp */
90151308Simpint pcic_pd6722_vsense = 1;
91151308SimpSYSCTL_INT(_hw_pcic, OID_AUTO, pd6722_vsense, CTLFLAG_RDTUN,
92151308Simp    &pcic_pd6722_vsense, 1,
93151308Simp    "Select CL-PD6722's VSENSE method.  VSENSE is used to determine the\n\
94151308Simpvolatage of inserted cards.  The CL-PD6722 has two methods to determine the\n\
95151308Simpvoltage of the card.  0 means assume a 5.0V card and do not check.  1 means\n\
96151308Simpuse the same method that the CL-PD6710 uses (default).  2 means use the\n\
97151308Simpsame method as the CL-PD6729.  2 is documented in the datasheet as being\n\
98151308Simpthe correct way, but 1 seems to give better results on more laptops.");
99151308Simp
100133553Simp/*****************************************************************************
101133553Simp * End of configurable parameters.
102133553Simp *****************************************************************************/
103133553Simp
104133553Simp#define	DPRINTF(x) do { if (cbb_debug) printf x; } while (0)
105133553Simp#define	DEVPRINTF(x) do { if (cbb_debug) device_printf x; } while (0)
106133553Simp
107151308Simp/* XXX Not sure that PNP0E03 should be claimed, except maybe on pc98 */
108133553Simpstatic struct isa_pnp_id pcic_ids[] = {
109133553Simp	{EXCA_PNP_ACTIONTEC,		NULL},		/* AEI0218 */
110133553Simp	{EXCA_PNP_IBM3765,		NULL},		/* IBM3765 */
111133553Simp	{EXCA_PNP_82365,		NULL},		/* PNP0E00 */
112133553Simp	{EXCA_PNP_CL_PD6720,		NULL},		/* PNP0E01 */
113133553Simp	{EXCA_PNP_VLSI_82C146,		NULL},		/* PNP0E02 */
114133553Simp	{EXCA_PNP_82365_CARDBUS,	NULL},		/* PNP0E03 */
115133553Simp	{EXCA_PNP_SCM_SWAPBOX,		NULL},		/* SCM0469 */
116151308Simp	{EXCA_NEC_PC9801_102,		NULL},		/* NEC8091 */
117151308Simp	{EXCA_NEC_PC9821RA_E01,         NULL},          /* NEC8121 */
118133553Simp	{0}
119133553Simp};
120133553Simp
121133553Simp/************************************************************************/
122133553Simp/* Probe/Attach								*/
123133553Simp/************************************************************************/
124133553Simp
125151308Simpstatic int
126151308Simpcbb_isa_activate(device_t dev)
127151308Simp{
128151308Simp	struct cbb_softc *sc = device_get_softc(dev);
129133553Simp	struct resource *res;
130133553Simp	int rid;
131133553Simp	int i;
132133553Simp
133133553Simp	/* A little bogus, but go ahead and get the irq for CSC events */
134133553Simp	rid = 0;
135133553Simp	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
136133553Simp	if (res == NULL) {
137133553Simp		/*
138133553Simp		 * No IRQ specified, find one.  This can be due to the PnP
139133553Simp		 * data not specifying any IRQ, or the default kernel not
140133553Simp		 * assinging an IRQ.
141133553Simp		 */
142151308Simp		for (i = 0; i < 16 && res == NULL; i++) {
143133553Simp			if (((1 << i) & isa_intr_mask) == 0)
144133553Simp				continue;
145133553Simp			res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, i, i,
146133553Simp			    1, RF_ACTIVE);
147133553Simp		}
148133553Simp	}
149151308Simp	if (res == NULL)
150151308Simp		return (ENXIO);
151151308Simp	sc->irq_res = res;
152151308Simp	rid = 0;
153151308Simp	res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
154133553Simp	if (res == NULL) {
155151308Simp		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
156151308Simp		sc->irq_res = NULL;
157151308Simp		device_printf(dev, "Cannot allocate I/O\n");
158133553Simp		return (ENOMEM);
159133553Simp	}
160151457Simp	sc->bst = rman_get_bustag(res);
161151457Simp	sc->bsh = rman_get_bushandle(res);
162151308Simp	sc->base_res = res;
163151308Simp	return (0);
164133553Simp}
165133553Simp
166133553Simpstatic void
167133553Simpcbb_isa_deactivate(device_t dev)
168133553Simp{
169151308Simp	struct cbb_softc *sc = device_get_softc(dev);
170151308Simp
171151308Simp	if (sc->irq_res)
172151308Simp		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
173151308Simp	sc->irq_res = NULL;
174151308Simp	if (sc->base_res)
175151308Simp		bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->base_res);
176151308Simp	sc->base_res = NULL;
177133553Simp}
178133553Simp
179133553Simpstatic int
180133553Simpcbb_isa_probe(device_t dev)
181133553Simp{
182133553Simp	int error;
183133553Simp	struct cbb_softc *sc = device_get_softc(dev);
184133553Simp
185133553Simp	/* Check isapnp ids */
186133553Simp	error = ISA_PNP_PROBE(device_get_parent(dev), dev, pcic_ids);
187133553Simp	if (error != 0 && error != ENOENT)
188133553Simp		return (error);
189133553Simp
190133553Simp	error = cbb_isa_activate(dev);
191133553Simp	if (error != 0)
192133553Simp		return (error);
193133553Simp
194133553Simp	/* Check to make sure that we have actual hardware */
195133553Simp	error = exca_probe_slots(dev, &sc->exca[0], sc->bst, sc->bsh);
196133553Simp	cbb_isa_deactivate(dev);
197133553Simp	return (error);
198133553Simp}
199133553Simp
200133553Simpstatic int
201133553Simpcbb_isa_attach(device_t dev)
202133553Simp{
203133553Simp	return (ENOMEM);
204133553Simp}
205133553Simp
206277234Simpstatic int
207277234Simpcbb_isa_suspend(device_t dev)
208277234Simp{
209277234Simp	return (0);
210277234Simp}
211277234Simp
212277234Simpstatic int
213277234Simpcbb_isa_resume(device_t dev)
214277234Simp{
215277234Simp	return (0);
216277234Simp}
217277234Simp
218133553Simpstatic device_method_t cbb_methods[] = {
219133553Simp	/* Device interface */
220133553Simp	DEVMETHOD(device_probe,			cbb_isa_probe),
221133553Simp	DEVMETHOD(device_attach,		cbb_isa_attach),
222133553Simp	DEVMETHOD(device_detach,		cbb_detach),
223277234Simp	DEVMETHOD(device_suspend,		cbb_isa_suspend),
224277234Simp	DEVMETHOD(device_resume,		cbb_isa_resume),
225133553Simp
226133553Simp	/* bus methods */
227133553Simp	DEVMETHOD(bus_read_ivar,		cbb_read_ivar),
228133553Simp	DEVMETHOD(bus_write_ivar,		cbb_write_ivar),
229133553Simp	DEVMETHOD(bus_alloc_resource,		cbb_alloc_resource),
230133553Simp	DEVMETHOD(bus_release_resource,		cbb_release_resource),
231133553Simp	DEVMETHOD(bus_activate_resource,	cbb_activate_resource),
232133553Simp	DEVMETHOD(bus_deactivate_resource,	cbb_deactivate_resource),
233133553Simp	DEVMETHOD(bus_driver_added,		cbb_driver_added),
234133553Simp	DEVMETHOD(bus_child_detached,		cbb_child_detached),
235133553Simp	DEVMETHOD(bus_setup_intr,		cbb_setup_intr),
236133553Simp	DEVMETHOD(bus_teardown_intr,		cbb_teardown_intr),
237133553Simp	DEVMETHOD(bus_child_present,		cbb_child_present),
238133553Simp
239133553Simp	/* 16-bit card interface */
240133553Simp	DEVMETHOD(card_set_res_flags,		cbb_pcic_set_res_flags),
241133553Simp	DEVMETHOD(card_set_memory_offset,	cbb_pcic_set_memory_offset),
242133553Simp
243133553Simp	/* power interface */
244133553Simp	DEVMETHOD(power_enable_socket,		cbb_power_enable_socket),
245133553Simp	DEVMETHOD(power_disable_socket,		cbb_power_disable_socket),
246133553Simp
247227843Smarius	DEVMETHOD_END
248133553Simp};
249133553Simp
250133553Simpstatic driver_t cbb_isa_driver = {
251133553Simp	"cbb",
252133553Simp	cbb_methods,
253133553Simp	sizeof(struct cbb_softc)
254133553Simp};
255133553Simp
256133553SimpDRIVER_MODULE(cbb, isa, cbb_isa_driver, cbb_devclass, 0, 0);
257133553SimpMODULE_DEPEND(cbb, exca, 1, 1, 1);
258