FreeBSD/Linux Kernel Cross Reference
sys/pc98/pc98/canbus.c
1 /*-
2 * Copyright (c) 2000 KIYOHARA Takashi <kiyohara@kk.iij4u.ne.jp>
3 * Copyright (c) 2000 Takanori Watanabe <takawata@jp.FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: releng/6.0/sys/pc98/pc98/canbus.c 143866 2005-03-20 05:22:57Z nyan $
28 */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/module.h>
36 #include <sys/sysctl.h>
37
38 #include <machine/clock.h>
39
40 #include <machine/bus.h>
41 #include <machine/resource.h>
42 #include <sys/rman.h>
43
44 #include <pc98/pc98/canbus.h>
45 #include <pc98/pc98/canbusvars.h>
46 #include "canbus_if.h"
47
48
49 #define CANBE_IO_DELAY_TIME 5000
50
51
52 static MALLOC_DEFINE(M_CANBUSDEV, "canbusdev", "CanBe device");
53 struct canbus_device {
54 struct resource_list cbdev_resources;
55 };
56
57 /* canbus softc */
58 struct canbus_softc {
59 int io_delay_time; /* CanBe I/O delay time */
60
61 struct sysctl_ctx_list canbus_sysctl_ctx;
62 /* dynamic sysctl tree */
63
64 /* index register */
65 int index_id; /* index ID */
66 struct resource *index_res; /* index resouce */
67 bus_space_tag_t index_tag; /* index tag */
68 bus_space_handle_t index_handle; /* index handle */
69
70 /* data register */
71 int data_id; /* data ID */
72 struct resource *data_res; /* data resouce */
73 bus_space_tag_t data_tag; /* data tag */
74 bus_space_handle_t data_handle; /* data handle */
75 };
76
77
78 /* Device interface methods */
79 static void canbus_identify(driver_t *, device_t);
80 static int canbus_probe(device_t);
81 static int canbus_attach(device_t);
82 static int canbus_detach(device_t);
83
84 /* Bus interface methods */
85 static int canbus_print_child(device_t, device_t);
86 static device_t canbus_add_child(device_t, int, const char *, int);
87 static struct resource * canbus_alloc_resource(
88 device_t, device_t, int, int *, u_long, u_long, u_long, u_int);
89 static int canbus_activate_resource(
90 device_t, device_t, int, int, struct resource *);
91 static int canbus_deactivate_resource(
92 device_t, device_t, int, int, struct resource *);
93 static int canbus_release_resource(
94 device_t, device_t, int, int, struct resource *);
95 static int canbus_set_resource (
96 device_t, device_t, int, int, u_long, u_long);
97 static void canbus_delete_resource(device_t, device_t, int, int);
98
99 /* canbus local function */
100 static void set_ioresource(device_t dev);
101 static void delete_ioresource(device_t dev);
102 static int alloc_ioresource(device_t);
103 static void release_ioresource(device_t);
104 static int print_all_resources(device_t);
105
106 static device_method_t canbus_methods[] = {
107 /* Device interface */
108 DEVMETHOD(device_identify, canbus_identify),
109 DEVMETHOD(device_probe, canbus_probe),
110 DEVMETHOD(device_attach, canbus_attach),
111 DEVMETHOD(device_detach, canbus_detach),
112
113 /* Bus interface */
114 DEVMETHOD(bus_print_child, canbus_print_child),
115 DEVMETHOD(bus_add_child, canbus_add_child),
116 DEVMETHOD(bus_alloc_resource, canbus_alloc_resource),
117 DEVMETHOD(bus_activate_resource, canbus_activate_resource),
118 DEVMETHOD(bus_deactivate_resource, canbus_deactivate_resource),
119 DEVMETHOD(bus_release_resource, canbus_release_resource),
120 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
121 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
122 DEVMETHOD(bus_set_resource, canbus_set_resource),
123 DEVMETHOD(bus_delete_resource, canbus_delete_resource),
124
125 /* CanBe interface */
126 DEVMETHOD(canbus_read, canbus_read),
127 DEVMETHOD(canbus_write, canbus_write),
128 DEVMETHOD(canbus_write_multi, canbus_write_multi),
129
130 {0, 0}
131 };
132
133 static driver_t canbus_driver = {
134 "canbus",
135 canbus_methods,
136 sizeof(struct canbus_softc),
137 };
138
139 devclass_t canbus_devclass;
140 DRIVER_MODULE(canbus, nexus, canbus_driver, canbus_devclass, 0, 0);
141 MODULE_VERSION(canbus, 1);
142
143
144 static void
145 canbus_identify(driver_t *drv, device_t parent)
146 {
147 if (device_find_child(parent, "canbus", 0) == NULL) {
148 if (BUS_ADD_CHILD(parent, 33, "canbus", 0) == NULL)
149 device_printf(parent, "canbus cannot attach\n");
150 }
151 }
152
153
154 static int
155 canbus_probe(device_t dev)
156 {
157 u_int8_t flag;
158
159 set_ioresource(dev);
160 if(alloc_ioresource(dev))
161 return (ENXIO);
162 flag = canbus_read(dev, NULL, CANBE_SOUND_INTR_ADDR);
163 release_ioresource(dev);
164
165 if (bootverbose)
166 device_printf(dev, "probe flag = 0x%x\n", flag);
167
168 if (flag != CANBE_SOUND_INTR_VAL0 && flag != CANBE_SOUND_INTR_VAL1 &&
169 flag != CANBE_SOUND_INTR_VAL2 && flag != CANBE_SOUND_INTR_VAL3) {
170 device_printf(dev, "Device Not Found\n");
171 return (ENXIO);
172 }
173 device_set_desc(dev, "CanBe I/O Bus");
174
175 return (0);
176 }
177
178 static int
179 canbus_attach(device_t dev)
180 {
181 struct canbus_softc *sc = device_get_softc(dev);
182 struct sysctl_oid *canbus_sysctl_tree;
183
184 sc->io_delay_time = CANBE_IO_DELAY_TIME;
185
186 /* I/O resource setup */
187 if(alloc_ioresource(dev))
188 return (ENXIO);
189
190 /* Dynamic sysctl tree setup */
191 sysctl_ctx_init(&sc->canbus_sysctl_ctx);
192 canbus_sysctl_tree = SYSCTL_ADD_NODE(&sc->canbus_sysctl_ctx,
193 SYSCTL_STATIC_CHILDREN(/* tree top */), OID_AUTO,
194 "canbus", CTLFLAG_RD, 0, "CanBe I/O Bus");
195 SYSCTL_ADD_INT(&sc->canbus_sysctl_ctx,
196 SYSCTL_CHILDREN(canbus_sysctl_tree), OID_AUTO, "io_delay_time",
197 CTLFLAG_RW, &sc->io_delay_time, 0, "CanBe Bus I/O delay time");
198
199 bus_generic_probe(dev);
200 bus_generic_attach(dev);
201
202 return (0);
203 }
204
205
206 static int
207 canbus_detach(device_t dev)
208 {
209 struct canbus_softc *sc = device_get_softc(dev);
210
211 /* I/O resource free */
212 release_ioresource(dev);
213 delete_ioresource(dev);
214
215 /* Dynamic sysctl tree destroy */
216 if (sysctl_ctx_free(&sc->canbus_sysctl_ctx)) {
217 device_printf(dev,
218 "can't free this context - other oids depend on it\n");
219 return (ENOTEMPTY);
220 }
221
222 return (0);
223 }
224
225
226 static int
227 canbus_print_child(device_t dev, device_t child)
228 {
229 int retval = 0;
230
231 retval += bus_print_child_header(dev, child);
232 retval += print_all_resources(child);
233 retval += bus_print_child_footer(dev, child);
234
235 return (retval);
236 }
237
238 static device_t
239 canbus_add_child(device_t bus, int order, const char *name, int unit)
240 {
241 device_t child;
242 struct canbus_device *cbdev;
243
244 child = device_add_child_ordered(bus, order, name, unit);
245
246 cbdev = malloc(
247 sizeof(struct canbus_device), M_CANBUSDEV, M_NOWAIT | M_ZERO);
248 if (!cbdev)
249 return (0);
250
251 resource_list_init(&cbdev->cbdev_resources);
252 device_set_ivars(child, cbdev);
253
254 return (child);
255 }
256
257 static struct resource *
258 canbus_alloc_resource(device_t dev, device_t child, int type,
259 int *rid, u_long start, u_long end, u_long count, u_int flags)
260 {
261 return (BUS_ALLOC_RESOURCE(device_get_parent(dev),
262 child, type, rid, start, end, count, flags));
263 }
264
265 static int
266 canbus_activate_resource(
267 device_t dev, device_t child, int type, int rid, struct resource *res)
268 {
269 return (BUS_ACTIVATE_RESOURCE(
270 device_get_parent(dev), child, type, rid, res));
271 }
272
273 static int
274 canbus_deactivate_resource(
275 device_t dev, device_t child, int type, int rid, struct resource *res)
276 {
277 return (BUS_DEACTIVATE_RESOURCE(
278 device_get_parent(dev), child, type, rid, res));
279 }
280
281 static int
282 canbus_release_resource(
283 device_t dev, device_t child, int type, int rid, struct resource *res)
284 {
285 return (BUS_RELEASE_RESOURCE(
286 device_get_parent(dev), child, type, rid, res));
287 }
288
289 static int
290 canbus_set_resource (
291 device_t dev, device_t child, int type, int rid, u_long start, u_long count)
292 {
293 struct canbus_device *cbdev =
294 (struct canbus_device *)device_get_ivars(child);
295 struct resource_list *rl = &cbdev->cbdev_resources;
296
297 resource_list_add(rl, type, rid, start, (start + count - 1), count);
298
299 return (0);
300 }
301
302 static void
303 canbus_delete_resource(device_t dev, device_t child, int type, int rid)
304 {
305 struct canbus_device *cbdev =
306 (struct canbus_device *)device_get_ivars(child);
307 struct resource_list *rl = &cbdev->cbdev_resources;
308
309 resource_list_delete(rl, type, rid);
310 }
311
312
313 u_int8_t
314 canbus_read(device_t dev, device_t child, int reg)
315 {
316 struct canbus_softc *sc = device_get_softc(dev);
317
318 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
319 return (bus_space_read_1(sc->data_tag, sc->data_handle, 0));
320 }
321
322 void
323 canbus_write(device_t dev, device_t child, int reg, u_int8_t val)
324 {
325 struct canbus_softc *sc = device_get_softc(dev);
326
327 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
328 bus_space_write_1(sc->data_tag, sc->data_handle, 0, val);
329 }
330
331 void
332 canbus_write_multi(device_t dev,
333 device_t child, int reg, const int count, const u_int8_t *vals)
334 {
335 struct canbus_softc *sc = device_get_softc(dev);
336 int i;
337
338 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
339
340 for (i = 0; i < count; i ++) {
341 bus_space_write_1(sc->data_tag, sc->data_handle, 0, vals[i]);
342 DELAY(sc->io_delay_time);
343 }
344 }
345
346 void
347 canbus_delay(device_t dev, device_t child)
348 {
349 struct canbus_softc *sc = device_get_softc(dev);
350
351 DELAY(sc->io_delay_time);
352 }
353
354
355 /*
356 * canbus local function.
357 */
358
359 /*
360 * CanBe I/O resource set function
361 */
362 static void
363 set_ioresource(device_t dev)
364 {
365 struct canbus_softc *sc = device_get_softc(dev);
366
367 sc->index_id = 0;
368 sc->data_id = 1;
369
370 bus_set_resource(
371 dev, SYS_RES_IOPORT, sc->index_id, CANBE_IOPORT_INDEX, 1);
372 bus_set_resource(
373 dev, SYS_RES_IOPORT, sc->data_id, CANBE_IOPORT_DATA, 1);
374 }
375
376 /*
377 * CanBe I/O resource delete function
378 */
379 static void
380 delete_ioresource(device_t dev)
381 {
382 struct canbus_softc *sc = device_get_softc(dev);
383
384 bus_delete_resource(dev, SYS_RES_IOPORT, sc->index_id);
385 bus_delete_resource(dev, SYS_RES_IOPORT, sc->data_id);
386 }
387
388 /*
389 * CanBe I/O resource alloc function
390 */
391 static int
392 alloc_ioresource(device_t dev)
393 {
394 struct canbus_softc *sc = device_get_softc(dev);
395
396 sc->index_res = bus_alloc_resource_any(
397 dev, SYS_RES_IOPORT, &sc->index_id, RF_ACTIVE);
398 sc->data_res = bus_alloc_resource_any(
399 dev, SYS_RES_IOPORT, &sc->data_id, RF_ACTIVE);
400 if (sc->index_res == NULL || sc->data_res == NULL) {
401 device_printf(dev, "could not map I/O\n");
402 return (ENXIO);
403 }
404
405 sc->index_tag = rman_get_bustag(sc->index_res);
406 sc->index_handle = rman_get_bushandle(sc->index_res);
407 sc->data_tag = rman_get_bustag(sc->data_res);
408 sc->data_handle = rman_get_bushandle(sc->data_res);
409
410 return (0);
411 }
412
413 /*
414 * CanBe I/O resource release function
415 */
416 static void
417 release_ioresource(device_t dev)
418 {
419 struct canbus_softc *sc = device_get_softc(dev);
420
421 bus_release_resource(dev, SYS_RES_IOPORT, sc->index_id, sc->index_res);
422 bus_release_resource(dev, SYS_RES_IOPORT, sc->data_id, sc->data_res);
423 }
424
425
426 static int
427 print_all_resources(device_t dev)
428 {
429 struct canbus_device *cbdev =
430 (struct canbus_device *)device_get_ivars(dev);
431 struct resource_list *rl = &cbdev->cbdev_resources;
432 int retval = 0;
433
434 if (STAILQ_FIRST(rl))
435 retval += printf(" at");
436
437 retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
438 retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
439 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
440
441 return retval;
442 }
Cache object: eb948a19c0dc2e5b1765f90a2740f7d7
|