]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/pc98/pc98/canbus.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / 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$
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
39 #include <machine/bus.h>
40 #include <machine/resource.h>
41 #include <sys/rman.h>
42
43 #include <pc98/pc98/canbus.h>
44 #include <pc98/pc98/canbusvars.h>
45 #include "canbus_if.h"
46
47
48 #define CANBE_IO_DELAY_TIME 5000
49
50
51 static MALLOC_DEFINE(M_CANBUSDEV, "canbusdev", "CanBe device");
52 struct canbus_device {
53         struct resource_list cbdev_resources;
54 };
55
56 /* canbus softc */
57 struct canbus_softc {
58         int io_delay_time;                      /* CanBe I/O delay time */
59
60         struct sysctl_ctx_list canbus_sysctl_ctx;
61                                                 /* dynamic sysctl tree */
62
63         /* index register */
64         int index_id;                           /* index ID */
65         struct resource *index_res;             /* index resource */
66         bus_space_tag_t index_tag;              /* index tag */
67         bus_space_handle_t index_handle;        /* index handle */
68
69         /* data register */
70         int data_id;                            /* data ID */
71         struct resource *data_res;              /* data resource */
72         bus_space_tag_t data_tag;               /* data tag */
73         bus_space_handle_t data_handle;         /* data handle */
74 };
75
76
77 /* Device interface methods */
78 static void     canbus_identify(driver_t *, device_t);
79 static int      canbus_probe(device_t);
80 static int      canbus_attach(device_t);
81 static int      canbus_detach(device_t);
82
83 /* Bus interface methods */
84 static int      canbus_print_child(device_t, device_t);
85 static device_t canbus_add_child(device_t, u_int, const char *, int);
86 static struct resource *        canbus_alloc_resource(
87     device_t, device_t, int, int *, u_long, u_long, u_long, u_int);
88 static int      canbus_activate_resource(
89     device_t, device_t, int, int, struct resource *);
90 static int      canbus_deactivate_resource(
91     device_t, device_t, int, int, struct resource *);
92 static int      canbus_release_resource(
93     device_t, device_t, int, int, struct resource *);
94 static int      canbus_set_resource (
95     device_t, device_t, int, int, u_long, u_long);
96 static void     canbus_delete_resource(device_t, device_t, int, int);
97
98 /* canbus local function */
99 static void     set_ioresource(device_t dev);
100 static void     delete_ioresource(device_t dev);
101 static int      alloc_ioresource(device_t);
102 static void     release_ioresource(device_t);
103 static int      print_all_resources(device_t);
104
105 static device_method_t canbus_methods[] = { 
106         /* Device interface */
107         DEVMETHOD(device_identify,      canbus_identify),
108         DEVMETHOD(device_probe,         canbus_probe),
109         DEVMETHOD(device_attach,        canbus_attach),
110         DEVMETHOD(device_detach,        canbus_detach),
111
112         /* Bus interface */
113         DEVMETHOD(bus_print_child,      canbus_print_child),
114         DEVMETHOD(bus_add_child,        canbus_add_child),
115         DEVMETHOD(bus_alloc_resource,   canbus_alloc_resource),
116         DEVMETHOD(bus_activate_resource,        canbus_activate_resource),
117         DEVMETHOD(bus_deactivate_resource,      canbus_deactivate_resource),
118         DEVMETHOD(bus_release_resource, canbus_release_resource),
119         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
120         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
121         DEVMETHOD(bus_set_resource,     canbus_set_resource),
122         DEVMETHOD(bus_delete_resource,  canbus_delete_resource),
123
124         /* CanBe interface */
125         DEVMETHOD(canbus_read,          canbus_read),
126         DEVMETHOD(canbus_write,         canbus_write),
127         DEVMETHOD(canbus_write_multi,   canbus_write_multi),
128
129         {0, 0}
130 };
131
132 static driver_t canbus_driver = {
133         "canbus",
134         canbus_methods,
135         sizeof(struct canbus_softc),
136 };
137
138 devclass_t canbus_devclass;
139 DRIVER_MODULE(canbus, nexus, canbus_driver, canbus_devclass, 0, 0);
140 MODULE_VERSION(canbus, 1);
141
142
143 static void
144 canbus_identify(driver_t *drv, device_t parent)
145 {
146         if (device_find_child(parent, "canbus", 0) == NULL) {
147                 if (BUS_ADD_CHILD(parent, 33, "canbus", 0) == NULL)
148                         device_printf(parent, "canbus cannot attach\n");
149         }
150 }
151
152
153 static int
154 canbus_probe(device_t dev)
155 {
156         u_int8_t flag;
157
158         set_ioresource(dev);
159         if(alloc_ioresource(dev))
160                 return (ENXIO);
161         flag = canbus_read(dev, NULL, CANBE_SOUND_INTR_ADDR);
162         release_ioresource(dev);
163
164         if (bootverbose)
165                 device_printf(dev, "probe flag = 0x%x\n", flag);
166
167         if (flag != CANBE_SOUND_INTR_VAL0 && flag != CANBE_SOUND_INTR_VAL1 &&
168             flag != CANBE_SOUND_INTR_VAL2 && flag != CANBE_SOUND_INTR_VAL3) {
169                 device_printf(dev, "Device Not Found\n");
170                 return (ENXIO);
171         }
172         device_set_desc(dev, "CanBe I/O Bus");
173
174         return (0);     
175 }
176
177 static int
178 canbus_attach(device_t dev)
179 {
180         struct canbus_softc *sc = device_get_softc(dev);
181         struct sysctl_oid *canbus_sysctl_tree;
182
183         sc->io_delay_time = CANBE_IO_DELAY_TIME;
184
185         /* I/O resource setup */
186         if(alloc_ioresource(dev))
187                 return (ENXIO);
188
189         /* Dynamic sysctl tree setup */
190         sysctl_ctx_init(&sc->canbus_sysctl_ctx);
191         canbus_sysctl_tree = SYSCTL_ADD_NODE(&sc->canbus_sysctl_ctx,
192             SYSCTL_STATIC_CHILDREN(/* tree top */), OID_AUTO,
193             "canbus", CTLFLAG_RD, 0, "CanBe I/O Bus");
194         SYSCTL_ADD_INT(&sc->canbus_sysctl_ctx,
195             SYSCTL_CHILDREN(canbus_sysctl_tree), OID_AUTO, "io_delay_time",
196             CTLFLAG_RW, &sc->io_delay_time, 0, "CanBe Bus I/O delay time");
197
198         bus_generic_probe(dev);
199         bus_generic_attach(dev);
200
201         return (0);
202 }
203
204
205 static int
206 canbus_detach(device_t dev)
207 {
208         struct canbus_softc *sc = device_get_softc(dev);
209
210         /* I/O resource free */
211         release_ioresource(dev);
212         delete_ioresource(dev);
213
214         /* Dynamic sysctl tree destroy */
215         if (sysctl_ctx_free(&sc->canbus_sysctl_ctx)) {
216                 device_printf(dev,
217                     "can't free this context - other oids depend on it\n");
218                 return (ENOTEMPTY);
219         }
220
221         return (0);
222 }
223
224
225 static int
226 canbus_print_child(device_t dev, device_t child)
227 {
228         int     retval = 0;
229
230         retval += bus_print_child_header(dev, child);
231         retval += print_all_resources(child);
232         retval += bus_print_child_footer(dev, child);
233
234         return (retval);
235 }
236
237 static device_t
238 canbus_add_child(device_t bus, u_int order, const char *name, int unit)
239 {
240         device_t child;
241         struct canbus_device *cbdev;
242
243         child = device_add_child_ordered(bus, order, name, unit);
244
245         cbdev = malloc(
246             sizeof(struct canbus_device), M_CANBUSDEV, M_NOWAIT | M_ZERO);
247         if (!cbdev)
248                 return (0);
249
250         resource_list_init(&cbdev->cbdev_resources);
251         device_set_ivars(child, cbdev);
252
253         return (child);
254 }
255
256 static struct resource *
257 canbus_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
264 static int
265 canbus_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
272 static int
273 canbus_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
280 static int
281 canbus_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
288 static int
289 canbus_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
301 static void
302 canbus_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
312 u_int8_t
313 canbus_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
321 void
322 canbus_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
330 void
331 canbus_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
345 void
346 canbus_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  */
361 static void
362 set_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  */
378 static void
379 delete_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  */
390 static int
391 alloc_ioresource(device_t dev)
392 {
393         struct canbus_softc *sc = device_get_softc(dev);
394
395         sc->index_res = bus_alloc_resource_any(
396             dev, SYS_RES_IOPORT, &sc->index_id, RF_ACTIVE);
397         sc->data_res = bus_alloc_resource_any(
398             dev, SYS_RES_IOPORT, &sc->data_id, 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  */
415 static void
416 release_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
425 static int
426 print_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 (STAILQ_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 }