Fix two serious bugs in the IP demux code. First, if ip_mport() m_pullup()'s
[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.4 2004/03/12 03:23:53 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_INTWAIT | M_ZERO);
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(
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  */
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 (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 }