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
29 static int mcd_isa_probe (device_t);
30 static int mcd_isa_attach (device_t);
31 static int mcd_isa_detach (device_t);
32
33 static int mcd_alloc_resources (device_t);
34 static void mcd_release_resources (device_t);
35
36 static int
mcd_isa_probe(device_t dev)37 mcd_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
66 fail:
67 mcd_release_resources(dev);
68 return (error);
69 }
70
71 static int
mcd_isa_attach(device_t dev)72 mcd_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);
100 fail:
101 mcd_release_resources(dev);
102 return (error);
103 }
104
105 static int
mcd_isa_detach(device_t dev)106 mcd_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
121 static int
mcd_alloc_resources(device_t dev)122 mcd_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 mtx_init(&sc->mtx, "mcd", NULL, MTX_DEF);
130
131 if (sc->port_type) {
132 sc->port = bus_alloc_resource_any(dev, sc->port_type,
133 &sc->port_rid, RF_ACTIVE);
134 if (sc->port == NULL) {
135 device_printf(dev, "Unable to allocate PORT resource.\n");
136 error = ENOMEM;
137 goto bad;
138 }
139 }
140
141 if (sc->irq_type) {
142 sc->irq = bus_alloc_resource_any(dev, sc->irq_type,
143 &sc->irq_rid, RF_ACTIVE);
144 if (sc->irq == NULL) {
145 device_printf(dev, "Unable to allocate IRQ resource.\n");
146 error = ENOMEM;
147 goto bad;
148 }
149 }
150
151 if (sc->drq_type) {
152 sc->drq = bus_alloc_resource_any(dev, sc->drq_type,
153 &sc->drq_rid, RF_ACTIVE);
154 if (sc->drq == NULL) {
155 device_printf(dev, "Unable to allocate DRQ resource.\n");
156 error = ENOMEM;
157 goto bad;
158 }
159 }
160
161 bad:
162 return (error);
163 }
164
165 static void
mcd_release_resources(device_t dev)166 mcd_release_resources (device_t dev)
167 {
168 struct mcd_softc * sc;
169
170 sc = device_get_softc(dev);
171
172 if (sc->irq_ih)
173 bus_teardown_intr(dev, sc->irq, sc->irq_ih);
174 if (sc->port)
175 bus_release_resource(dev, sc->port_type, sc->port_rid, sc->port);
176 if (sc->irq)
177 bus_release_resource(dev, sc->irq_type, sc->irq_rid, sc->irq);
178 if (sc->drq)
179 bus_release_resource(dev, sc->drq_type, sc->drq_rid, sc->drq);
180
181 mtx_destroy(&sc->mtx);
182
183 return;
184 }
185
186 static device_method_t mcd_isa_methods[] = {
187 DEVMETHOD(device_probe, mcd_isa_probe),
188 DEVMETHOD(device_attach, mcd_isa_attach),
189 DEVMETHOD(device_detach, mcd_isa_detach),
190
191 { 0, 0 }
192 };
193
194 static driver_t mcd_isa_driver = {
195 "mcd",
196 mcd_isa_methods,
197 sizeof(struct mcd_softc)
198 };
199
200 static devclass_t mcd_devclass;
201
202 DRIVER_MODULE(mcd, isa, mcd_isa_driver, mcd_devclass, NULL, 0);
203