Add IDs for the following:
[dragonfly.git] / sys / bus / canbus / canbus.c
CommitLineData
984263bc
MD
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: src/sys/pc98/pc98/canbus.c,v 1.3.2.1 2003/02/10 13:11:51 nyan Exp $
898d961b 28 * $DragonFly: src/sys/bus/canbus/Attic/canbus.c,v 1.4 2004/03/12 03:23:53 dillon Exp $
984263bc
MD
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/bus.h>
34#include <sys/kernel.h>
35#include <sys/malloc.h>
36#include <sys/module.h>
37#include <sys/sysctl.h>
38
39#include <machine/clock.h>
40
41#include <machine/bus.h>
42#include <machine/resource.h>
43#include <sys/rman.h>
44
1f2de5d4
MD
45#include "canbus.h"
46#include "canbusvars.h"
984263bc
MD
47#include "canbus_if.h"
48
49
50#define CANBE_IO_DELAY_TIME 5000
51
52
53static MALLOC_DEFINE(M_CANBUSDEV, "canbusdev", "CanBe device");
54struct canbus_device {
55 struct resource_list cbdev_resources;
56};
57
58/* canbus softc */
59struct canbus_softc {
60 int io_delay_time; /* CanBe I/O delay time */
61
62 struct sysctl_ctx_list canbus_sysctl_ctx;
63 /* dynamic sysctl tree */
64
65 /* index register */
66 int index_id; /* index ID */
67 struct resource *index_res; /* index resouce */
68 bus_space_tag_t index_tag; /* index tag */
69 bus_space_handle_t index_handle; /* index handle */
70
71 /* data register */
72 int data_id; /* data ID */
73 struct resource *data_res; /* data resouce */
74 bus_space_tag_t data_tag; /* data tag */
75 bus_space_handle_t data_handle; /* data handle */
76};
77
78
79/* Device interface methods */
80static void canbus_identify(driver_t *, device_t);
81static int canbus_probe(device_t);
82static int canbus_attach(device_t);
83static int canbus_detach(device_t);
84
85/* Bus interface methods */
86static int canbus_print_child(device_t, device_t);
87static device_t canbus_add_child(device_t, int, const char *, int);
88static struct resource * canbus_alloc_resource(
89 device_t, device_t, int, int *, u_long, u_long, u_long, u_int);
90static int canbus_activate_resource(
91 device_t, device_t, int, int, struct resource *);
92static int canbus_deactivate_resource(
93 device_t, device_t, int, int, struct resource *);
94static int canbus_release_resource(
95 device_t, device_t, int, int, struct resource *);
96static int canbus_set_resource (
97 device_t, device_t, int, int, u_long, u_long);
98static void canbus_delete_resource(device_t, device_t, int, int);
99
100/* canbus local function */
101static void set_ioresource(device_t dev);
102static void delete_ioresource(device_t dev);
103static int alloc_ioresource(device_t);
104static void release_ioresource(device_t);
105static int print_all_resources(device_t);
106
107static device_method_t canbus_methods[] = {
108 /* Device interface */
109 DEVMETHOD(device_identify, canbus_identify),
110 DEVMETHOD(device_probe, canbus_probe),
111 DEVMETHOD(device_attach, canbus_attach),
112 DEVMETHOD(device_detach, canbus_detach),
113
114 /* Bus interface */
115 DEVMETHOD(bus_print_child, canbus_print_child),
116 DEVMETHOD(bus_add_child, canbus_add_child),
117 DEVMETHOD(bus_alloc_resource, canbus_alloc_resource),
118 DEVMETHOD(bus_activate_resource, canbus_activate_resource),
119 DEVMETHOD(bus_deactivate_resource, canbus_deactivate_resource),
120 DEVMETHOD(bus_release_resource, canbus_release_resource),
121 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
122 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
123 DEVMETHOD(bus_set_resource, canbus_set_resource),
124 DEVMETHOD(bus_delete_resource, canbus_delete_resource),
125
126 /* CanBe interface */
127 DEVMETHOD(canbus_read, canbus_read),
128 DEVMETHOD(canbus_write, canbus_write),
129 DEVMETHOD(canbus_write_multi, canbus_write_multi),
130
131 {0, 0}
132};
133
134static driver_t canbus_driver = {
135 "canbus",
136 canbus_methods,
137 sizeof(struct canbus_softc),
138};
139
140devclass_t canbus_devclass;
141DRIVER_MODULE(canbus, nexus, canbus_driver, canbus_devclass, 0, 0);
142MODULE_VERSION(canbus, 1);
143
144
145static void
146canbus_identify(driver_t *drv, device_t parent)
147{
148 if (device_find_child(parent, "canbus", 0) == NULL) {
149 if (BUS_ADD_CHILD(parent, 33, "canbus", 0) == NULL)
150 device_printf(parent, "canbus cannot attach\n");
151 }
152}
153
154
155static int
156canbus_probe(device_t dev)
157{
158 u_int8_t flag;
159
160 set_ioresource(dev);
161 if(alloc_ioresource(dev))
162 return (ENXIO);
163 flag = canbus_read(dev, NULL, CANBE_SOUND_INTR_ADDR);
164 release_ioresource(dev);
165
166 if (bootverbose)
167 device_printf(dev, "probe flag = 0x%x\n", flag);
168
169 if (flag != CANBE_SOUND_INTR_VAL0 && flag != CANBE_SOUND_INTR_VAL1 &&
170 flag != CANBE_SOUND_INTR_VAL2 && flag != CANBE_SOUND_INTR_VAL3) {
171 device_printf(dev, "Device Not Found\n");
172 return (ENXIO);
173 }
174 device_set_desc(dev, "CanBe I/O Bus");
175
176 return (0);
177}
178
179static int
180canbus_attach(device_t dev)
181{
182 struct canbus_softc *sc = device_get_softc(dev);
183 struct sysctl_oid *canbus_sysctl_tree;
184
185 sc->io_delay_time = CANBE_IO_DELAY_TIME;
186
187 /* I/O resource setup */
188 if(alloc_ioresource(dev))
189 return (ENXIO);
190
191 /* Dynamic sysctl tree setup */
192 sysctl_ctx_init(&sc->canbus_sysctl_ctx);
193 canbus_sysctl_tree = SYSCTL_ADD_NODE(&sc->canbus_sysctl_ctx,
194 SYSCTL_STATIC_CHILDREN(/* tree top */), OID_AUTO,
195 "canbus", CTLFLAG_RD, 0, "CanBe I/O Bus");
196 SYSCTL_ADD_INT(&sc->canbus_sysctl_ctx,
197 SYSCTL_CHILDREN(canbus_sysctl_tree), OID_AUTO, "io_delay_time",
198 CTLFLAG_RW, &sc->io_delay_time, 0, "CanBe Bus I/O delay time");
199
200 bus_generic_probe(dev);
201 bus_generic_attach(dev);
202
203 return (0);
204}
205
206
207static int
208canbus_detach(device_t dev)
209{
210 struct canbus_softc *sc = device_get_softc(dev);
211
212 /* I/O resource free */
213 release_ioresource(dev);
214 delete_ioresource(dev);
215
216 /* Dynamic sysctl tree destroy */
217 if (sysctl_ctx_free(&sc->canbus_sysctl_ctx)) {
218 device_printf(dev,
219 "can't free this context - other oids depend on it\n");
220 return (ENOTEMPTY);
221 }
222
223 return (0);
224}
225
226
227static int
228canbus_print_child(device_t dev, device_t child)
229{
230 int retval = 0;
231
232 retval += bus_print_child_header(dev, child);
233 retval += print_all_resources(child);
234 retval += bus_print_child_footer(dev, child);
235
236 return (retval);
237}
238
239static device_t
240canbus_add_child(device_t bus, int order, const char *name, int unit)
241{
242 device_t child;
243 struct canbus_device *cbdev;
244
245 child = device_add_child_ordered(bus, order, name, unit);
246
247 cbdev = malloc(
898d961b 248 sizeof(struct canbus_device), M_CANBUSDEV, M_INTWAIT | M_ZERO);
984263bc
MD
249
250 resource_list_init(&cbdev->cbdev_resources);
251 device_set_ivars(child, cbdev);
252
253 return (child);
254}
255
256static struct resource *
257canbus_alloc_resource(device_t dev, device_t child, int type,
258 int *rid, u_long start, u_long end, u_long count, u_int flags)
259{
260 return (BUS_ALLOC_RESOURCE(device_get_parent(dev),
261 child, type, rid, start, end, count, flags));
262}
263
264static int
265canbus_activate_resource(
266 device_t dev, device_t child, int type, int rid, struct resource *res)
267{
268 return (BUS_ACTIVATE_RESOURCE(
269 device_get_parent(dev), child, type, rid, res));
270}
271
272static int
273canbus_deactivate_resource(
274 device_t dev, device_t child, int type, int rid, struct resource *res)
275{
276 return (BUS_DEACTIVATE_RESOURCE(
277 device_get_parent(dev), child, type, rid, res));
278}
279
280static int
281canbus_release_resource(
282 device_t dev, device_t child, int type, int rid, struct resource *res)
283{
284 return (BUS_RELEASE_RESOURCE(
285 device_get_parent(dev), child, type, rid, res));
286}
287
288static int
289canbus_set_resource (
290 device_t dev, device_t child, int type, int rid, u_long start, u_long count)
291{
292 struct canbus_device *cbdev =
293 (struct canbus_device *)device_get_ivars(child);
294 struct resource_list *rl = &cbdev->cbdev_resources;
295
296 resource_list_add(rl, type, rid, start, (start + count - 1), count);
297
298 return (0);
299}
300
301static void
302canbus_delete_resource(device_t dev, device_t child, int type, int rid)
303{
304 struct canbus_device *cbdev =
305 (struct canbus_device *)device_get_ivars(child);
306 struct resource_list *rl = &cbdev->cbdev_resources;
307
308 resource_list_delete(rl, type, rid);
309}
310
311
312u_int8_t
313canbus_read(device_t dev, device_t child, int reg)
314{
315 struct canbus_softc *sc = device_get_softc(dev);
316
317 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
318 return (bus_space_read_1(sc->data_tag, sc->data_handle, 0));
319}
320
321void
322canbus_write(device_t dev, device_t child, int reg, u_int8_t val)
323{
324 struct canbus_softc *sc = device_get_softc(dev);
325
326 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
327 bus_space_write_1(sc->data_tag, sc->data_handle, 0, val);
328}
329
330void
331canbus_write_multi(device_t dev,
332 device_t child, int reg, const int count, const u_int8_t *vals)
333{
334 struct canbus_softc *sc = device_get_softc(dev);
335 int i;
336
337 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
338
339 for (i = 0; i < count; i ++) {
340 bus_space_write_1(sc->data_tag, sc->data_handle, 0, vals[i]);
341 DELAY(sc->io_delay_time);
342 }
343}
344
345void
346canbus_delay(device_t dev, device_t child)
347{
348 struct canbus_softc *sc = device_get_softc(dev);
349
350 DELAY(sc->io_delay_time);
351}
352
353
354/*
355 * canbus local function.
356 */
357
358/*
359 * CanBe I/O resource set function
360 */
361static void
362set_ioresource(device_t dev)
363{
364 struct canbus_softc *sc = device_get_softc(dev);
365
366 sc->index_id = 0;
367 sc->data_id = 1;
368
369 bus_set_resource(
370 dev, SYS_RES_IOPORT, sc->index_id, CANBE_IOPORT_INDEX, 1);
371 bus_set_resource(
372 dev, SYS_RES_IOPORT, sc->data_id, CANBE_IOPORT_DATA, 1);
373}
374
375/*
376 * CanBe I/O resource delete function
377 */
378static void
379delete_ioresource(device_t dev)
380{
381 struct canbus_softc *sc = device_get_softc(dev);
382
383 bus_delete_resource(dev, SYS_RES_IOPORT, sc->index_id);
384 bus_delete_resource(dev, SYS_RES_IOPORT, sc->data_id);
385}
386
387/*
388 * CanBe I/O resource alloc function
389 */
390static int
391alloc_ioresource(device_t dev)
392{
393 struct canbus_softc *sc = device_get_softc(dev);
394
395 sc->index_res = bus_alloc_resource(
396 dev, SYS_RES_IOPORT, &sc->index_id, 0ul, ~0ul, 1, RF_ACTIVE);
397 sc->data_res = bus_alloc_resource(
398 dev, SYS_RES_IOPORT, &sc->data_id, 0ul, ~0ul, 1, RF_ACTIVE);
399 if (sc->index_res == NULL || sc->data_res == NULL) {
400 device_printf(dev, "could not map I/O\n");
401 return (ENXIO);
402 }
403
404 sc->index_tag = rman_get_bustag(sc->index_res);
405 sc->index_handle = rman_get_bushandle(sc->index_res);
406 sc->data_tag = rman_get_bustag(sc->data_res);
407 sc->data_handle = rman_get_bushandle(sc->data_res);
408
409 return (0);
410}
411
412/*
413 * CanBe I/O resource release function
414 */
415static void
416release_ioresource(device_t dev)
417{
418 struct canbus_softc *sc = device_get_softc(dev);
419
420 bus_release_resource(dev, SYS_RES_IOPORT, sc->index_id, sc->index_res);
421 bus_release_resource(dev, SYS_RES_IOPORT, sc->data_id, sc->data_res);
422}
423
424
425static int
426print_all_resources(device_t dev)
427{
428 struct canbus_device *cbdev =
429 (struct canbus_device *)device_get_ivars(dev);
430 struct resource_list *rl = &cbdev->cbdev_resources;
431 int retval = 0;
432
433 if (SLIST_FIRST(rl))
434 retval += printf(" at");
435
436 retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
437 retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
438 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
439
440 return retval;
441}