1/*
2 */
3
4#include <sys/cdefs.h>
5__FBSDID("$FreeBSD$");
6
7#include <sys/param.h>
8#include <sys/systm.h>
9#include <sys/kernel.h>
10#include <sys/module.h>
11#include <sys/conf.h>
12#include <sys/fcntl.h>
13#include <sys/bio.h>
14#include <sys/cdio.h>
15#include <sys/bus.h>
16
17#include <sys/lock.h>
18#include <sys/mutex.h>
19
20#include <machine/bus.h>
21#include <machine/resource.h>
22#include <sys/rman.h>
23
24#include <isa/isavar.h>
25
26#include <dev/mcd/mcdreg.h>
27#include <dev/mcd/mcdvar.h>
28
29static int	mcd_isa_probe	(device_t);
30static int	mcd_isa_attach	(device_t);
31static int	mcd_isa_detach	(device_t);
32
33static int	mcd_alloc_resources	(device_t);
34static void	mcd_release_resources	(device_t);
35
36static int
37mcd_isa_probe (device_t dev)
38{
39	struct mcd_softc *	sc;
40	int			error;
41
42	/* No pnp support */
43	if (isa_get_vendorid(dev))
44		return (ENXIO);
45
46	/* IO port must be configured. */
47	if (bus_get_resource_start(dev, SYS_RES_IOPORT, 0) == 0)
48		return (ENXIO);
49
50	sc = device_get_softc(dev);
51	sc->dev = dev;
52	sc->port_rid = 0;
53	sc->port_type = SYS_RES_IOPORT;
54	error = mcd_alloc_resources(dev);
55	if (error)
56		goto fail;
57
58	error = mcd_probe(sc);
59	if (error) {
60		device_printf(dev, "Probe failed.\n");
61		goto fail;
62	}
63
64	device_set_desc(dev, sc->data.name);
65
66fail:
67	mcd_release_resources(dev);
68	return (error);
69}
70
71static int
72mcd_isa_attach (device_t dev)
73{
74	struct mcd_softc *	sc;
75	int			error;
76
77	sc = device_get_softc(dev);
78	error = 0;
79
80	sc->dev = dev;
81	sc->port_rid = 0;
82	sc->port_type = SYS_RES_IOPORT;
83	error = mcd_alloc_resources(dev);
84	if (error)
85		goto fail;
86
87	error = mcd_probe(sc);
88	if (error) {
89		device_printf(dev, "Re-Probe failed.\n");
90		goto fail;
91	}
92
93	error = mcd_attach(sc);
94	if (error) {
95		device_printf(dev, "Attach failed.\n");
96		goto fail;
97	}
98
99	return (0);
100fail:
101	mcd_release_resources(dev);
102	return (error);
103}
104
105static int
106mcd_isa_detach (device_t dev)
107{
108	struct mcd_softc *	sc;
109	int			error;
110
111	sc = device_get_softc(dev);
112	error = 0;
113
114	destroy_dev(sc->mcd_dev_t);
115
116	mcd_release_resources(dev);
117
118	return (error);
119}
120
121static int
122mcd_alloc_resources (device_t dev)
123{
124	struct mcd_softc *	sc;
125	int			error;
126
127	sc = device_get_softc(dev);
128	error = 0;
129
130	if (sc->port_type) {
131		sc->port = bus_alloc_resource_any(dev, sc->port_type,
132				&sc->port_rid, RF_ACTIVE);
133		if (sc->port == NULL) {
134			device_printf(dev, "Unable to allocate PORT resource.\n");
135			error = ENOMEM;
136			goto bad;
137		}
138		sc->port_bst = rman_get_bustag(sc->port);
139		sc->port_bsh = rman_get_bushandle(sc->port);
140	}
141
142	if (sc->irq_type) {
143		sc->irq = bus_alloc_resource_any(dev, sc->irq_type,
144				&sc->irq_rid, RF_ACTIVE);
145		if (sc->irq == NULL) {
146			device_printf(dev, "Unable to allocate IRQ resource.\n");
147			error = ENOMEM;
148			goto bad;
149		}
150	}
151
152	if (sc->drq_type) {
153		sc->drq = bus_alloc_resource_any(dev, sc->drq_type,
154				&sc->drq_rid, RF_ACTIVE);
155		if (sc->drq == NULL) {
156			device_printf(dev, "Unable to allocate DRQ resource.\n");
157			error = ENOMEM;
158			goto bad;
159		}
160	}
161
162	mtx_init(&sc->mtx, device_get_nameunit(dev),
163		"Interrupt lock", MTX_DEF | MTX_RECURSE);
164
165bad:
166	return (error);
167}
168
169static void
170mcd_release_resources (device_t dev)
171{
172	struct mcd_softc *	sc;
173
174	sc = device_get_softc(dev);
175
176	if (sc->irq_ih)
177		bus_teardown_intr(dev, sc->irq, sc->irq_ih);
178	if (sc->port) {
179		bus_release_resource(dev, sc->port_type, sc->port_rid, sc->port);
180		sc->port_bst = 0;
181		sc->port_bsh = 0;
182	}
183	if (sc->irq)
184		bus_release_resource(dev, sc->irq_type, sc->irq_rid, sc->irq);
185	if (sc->drq)
186		bus_release_resource(dev, sc->drq_type, sc->drq_rid, sc->drq);
187
188	if (mtx_initialized(&sc->mtx) != 0)
189		mtx_destroy(&sc->mtx);
190
191	return;
192}
193
194static device_method_t mcd_isa_methods[] = {
195	DEVMETHOD(device_probe,         mcd_isa_probe),
196	DEVMETHOD(device_attach,        mcd_isa_attach),
197	DEVMETHOD(device_detach,        mcd_isa_detach),
198
199	{ 0, 0 }
200};
201
202static driver_t mcd_isa_driver = {
203	"mcd",
204	mcd_isa_methods,
205	sizeof(struct mcd_softc)
206};
207
208static devclass_t	mcd_devclass;
209
210DRIVER_MODULE(mcd, isa, mcd_isa_driver, mcd_devclass, NULL, 0);
211