binutils214 stage 2/4.
[dragonfly.git] / sys / bus / canbus / 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: src/sys/pc98/pc98/canbus.c,v 1.3.2.1 2003/02/10 13:11:51 nyan Exp $
28  * $DragonFly: src/sys/bus/canbus/Attic/canbus.c,v 1.3 2003/08/07 21:16:45 dillon Exp $
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
45 #include "canbus.h"
46 #include "canbusvars.h"
47 #include "canbus_if.h"
48
49
50 #define CANBE_IO_DELAY_TIME 5000
51
52
53 static MALLOC_DEFINE(M_CANBUSDEV, "canbusdev", "CanBe device");
54 struct canbus_device {
55         struct resource_list cbdev_resources;
56 };
57
58 /* canbus softc */
59 struct 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 */
80 static void     canbus_identify(driver_t *, device_t);
81 static int      canbus_probe(device_t);
82 static int      canbus_attach(device_t);
83 static int      canbus_detach(device_t);
84
85 /* Bus interface methods */
86 static int      canbus_print_child(device_t, device_t);
87 static device_t canbus_add_child(device_t, int, const char *, int);
88 static struct resource *        canbus_alloc_resource(
89     device_t, device_t, int, int *, u_long, u_long, u_long, u_int);
90 static int      canbus_activate_resource(
91     device_t, device_t, int, int, struct resource *);
92 static int      canbus_deactivate_resource(
93     device_t, device_t, int, int, struct resource *);
94 static int      canbus_release_resource(
95     device_t, device_t, int, int, struct resource *);
96 static int      canbus_set_resource (
97     device_t, device_t, int, int, u_long, u_long);
98 static void     canbus_delete_resource(device_t, device_t, int, int);
99
100 /* canbus local function */
101 static void     set_ioresource(device_t dev);
102 static void     delete_ioresource(device_t dev);
103 static int      alloc_ioresource(device_t);
104 static void     release_ioresource(device_t);
105 static int      print_all_resources(device_t);
106
107 static 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
134 static driver_t canbus_driver = {
135         "canbus",
136         canbus_methods,
137         sizeof(struct canbus_softc),
138 };
139
140 devclass_t canbus_devclass;
141 DRIVER_MODULE(canbus, nexus, canbus_driver, canbus_devclass, 0, 0);
142 MODULE_VERSION(canbus, 1);
143
144
145 static void
146 canbus_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
155 static int
156 canbus_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
179 static int
180 canbus_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
207 static int
208 canbus_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
227 static int
228 canbus_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
239 static device_t
240 canbus_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(
248             sizeof(struct canbus_device), M_CANBUSDEV, M_NOWAIT | M_ZERO);
249         if (!cbdev)
250                 return (0);
251
252         resource_list_init(&cbdev->cbdev_resources);
253         device_set_ivars(child, cbdev);
254
255         return (child);
256 }
257
258 static struct resource *
259 canbus_alloc_resource(device_t dev, device_t child, int type,
260     int *rid, u_long start, u_long end, u_long count, u_int flags)
261 {
262         return (BUS_ALLOC_RESOURCE(device_get_parent(dev),
263             child, type, rid, start, end, count, flags));
264 }
265
266 static int
267 canbus_activate_resource(
268     device_t dev, device_t child, int type, int rid, struct resource *res)
269 {
270         return (BUS_ACTIVATE_RESOURCE(
271             device_get_parent(dev), child, type, rid, res));
272 }
273
274 static int
275 canbus_deactivate_resource(
276     device_t dev, device_t child, int type, int rid, struct resource *res)
277 {
278         return (BUS_DEACTIVATE_RESOURCE(
279             device_get_parent(dev), child, type, rid, res));
280 }
281
282 static int
283 canbus_release_resource(
284     device_t dev, device_t child, int type, int rid, struct resource *res)
285 {
286         return (BUS_RELEASE_RESOURCE(
287             device_get_parent(dev), child, type, rid, res));
288 }
289
290 static int
291 canbus_set_resource (
292     device_t dev, device_t child, int type, int rid, u_long start, u_long count)
293 {
294         struct  canbus_device *cbdev =
295             (struct canbus_device *)device_get_ivars(child);
296         struct resource_list *rl = &cbdev->cbdev_resources;
297
298         resource_list_add(rl, type, rid, start, (start + count - 1), count);
299
300         return (0);
301 }
302
303 static void
304 canbus_delete_resource(device_t dev, device_t child, int type, int rid)
305 {
306         struct  canbus_device *cbdev =
307             (struct canbus_device *)device_get_ivars(child);
308         struct resource_list *rl = &cbdev->cbdev_resources;
309
310         resource_list_delete(rl, type, rid);
311 }
312
313
314 u_int8_t
315 canbus_read(device_t dev, device_t child, int reg)
316 {
317         struct canbus_softc *sc = device_get_softc(dev);
318
319         bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
320         return (bus_space_read_1(sc->data_tag, sc->data_handle, 0));
321 }
322
323 void
324 canbus_write(device_t dev, device_t child, int reg, u_int8_t val)
325 {
326         struct canbus_softc *sc = device_get_softc(dev);
327
328         bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
329         bus_space_write_1(sc->data_tag, sc->data_handle, 0, val);
330 }
331
332 void
333 canbus_write_multi(device_t dev,
334     device_t child, int reg, const int count, const u_int8_t *vals)
335 {
336         struct canbus_softc *sc = device_get_softc(dev);
337         int i;
338
339         bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
340
341         for (i = 0; i < count; i ++) {
342                 bus_space_write_1(sc->data_tag, sc->data_handle, 0, vals[i]);
343                 DELAY(sc->io_delay_time);
344         }
345 }
346
347 void
348 canbus_delay(device_t dev, device_t child)
349 {
350         struct canbus_softc *sc = device_get_softc(dev);
351
352         DELAY(sc->io_delay_time);
353 }
354
355
356 /*
357  * canbus local function.
358  */
359
360 /*
361  * CanBe I/O resource set function
362  */
363 static void
364 set_ioresource(device_t dev)
365 {
366         struct canbus_softc *sc = device_get_softc(dev);
367
368         sc->index_id = 0;
369         sc->data_id = 1;
370
371         bus_set_resource(
372             dev, SYS_RES_IOPORT, sc->index_id, CANBE_IOPORT_INDEX, 1);
373         bus_set_resource(
374             dev, SYS_RES_IOPORT, sc->data_id, CANBE_IOPORT_DATA, 1);
375 }
376
377 /*
378  * CanBe I/O resource delete function
379  */
380 static void
381 delete_ioresource(device_t dev)
382 {
383         struct canbus_softc *sc = device_get_softc(dev);
384
385         bus_delete_resource(dev, SYS_RES_IOPORT, sc->index_id);
386         bus_delete_resource(dev, SYS_RES_IOPORT, sc->data_id);
387 }
388
389 /*
390  * CanBe I/O resource alloc function
391  */
392 static int
393 alloc_ioresource(device_t dev)
394 {
395         struct canbus_softc *sc = device_get_softc(dev);
396
397         sc->index_res = bus_alloc_resource(
398             dev, SYS_RES_IOPORT, &sc->index_id, 0ul, ~0ul, 1, RF_ACTIVE);
399         sc->data_res = bus_alloc_resource(
400             dev, SYS_RES_IOPORT, &sc->data_id, 0ul, ~0ul, 1, RF_ACTIVE);
401         if (sc->index_res == NULL || sc->data_res == NULL) {
402                 device_printf(dev, "could not map I/O\n");
403                 return (ENXIO);
404         }
405
406         sc->index_tag = rman_get_bustag(sc->index_res);
407         sc->index_handle = rman_get_bushandle(sc->index_res);
408         sc->data_tag = rman_get_bustag(sc->data_res);
409         sc->data_handle = rman_get_bushandle(sc->data_res);
410
411         return (0);
412 }
413
414 /*
415  * CanBe I/O resource release function
416  */
417 static void
418 release_ioresource(device_t dev)
419 {
420         struct canbus_softc *sc = device_get_softc(dev);
421
422         bus_release_resource(dev, SYS_RES_IOPORT, sc->index_id, sc->index_res);
423         bus_release_resource(dev, SYS_RES_IOPORT, sc->data_id, sc->data_res);
424 }
425
426
427 static int
428 print_all_resources(device_t dev)
429 {
430         struct  canbus_device *cbdev =
431             (struct canbus_device *)device_get_ivars(dev);
432         struct resource_list *rl = &cbdev->cbdev_resources;
433         int retval = 0;
434
435         if (SLIST_FIRST(rl))
436                 retval += printf(" at");
437
438         retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
439         retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
440         retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
441
442         return retval;
443 }