canbus.c revision 110333
1110285Snyan/*-
2110285Snyan * Copyright (c) 2000 KIYOHARA Takashi <kiyohara@kk.iij4u.ne.jp>
3110329Stakawata * Copyright (c) 2000 Takanori Watanabe <takawata@jp.FreeBSD.org>
4110333Snyan * All rights reserved.
5110285Snyan *
6110285Snyan * Redistribution and use in source and binary forms, with or without
7110285Snyan * modification, are permitted provided that the following conditions
8110285Snyan * are met:
9110285Snyan * 1. Redistributions of source code must retain the above copyright
10110285Snyan *    notice, this list of conditions and the following disclaimer.
11110285Snyan * 2. Redistributions in binary form must reproduce the above copyright
12110285Snyan *    notice, this list of conditions and the following disclaimer in the
13110285Snyan *    documentation and/or other materials provided with the distribution.
14110285Snyan *
15110285Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16110285Snyan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17110285Snyan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18110285Snyan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19110285Snyan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20110285Snyan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21110285Snyan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22110285Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23110285Snyan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24110285Snyan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25110333Snyan * SUCH DAMAGE.
26110285Snyan *
27110285Snyan * $FreeBSD: head/sys/pc98/pc98/canbus.c 110333 2003-02-04 16:17:13Z nyan $
28110285Snyan */
29110285Snyan
30110285Snyan#include <sys/param.h>
31110285Snyan#include <sys/systm.h>
32110285Snyan#include <sys/bus.h>
33110285Snyan#include <sys/kernel.h>
34110285Snyan#include <sys/malloc.h>
35110285Snyan#include <sys/module.h>
36110285Snyan#include <sys/sysctl.h>
37110285Snyan
38110285Snyan#include <machine/clock.h>
39110285Snyan
40110285Snyan#include <machine/bus.h>
41110285Snyan#include <machine/resource.h>
42110285Snyan#include <sys/rman.h>
43110285Snyan
44110285Snyan#include <pc98/pc98/canbus.h>
45110285Snyan#include <pc98/pc98/canbusvars.h>
46110285Snyan#include "canbus_if.h"
47110285Snyan
48110285Snyan
49110285Snyan#define CANBE_IO_DELAY_TIME 5000
50110285Snyan
51110285Snyan
52110285Snyanstatic MALLOC_DEFINE(M_CANBUSDEV, "canbusdev", "CanBe device");
53110285Snyanstruct canbus_device {
54110285Snyan	struct resource_list cbdev_resources;
55110285Snyan};
56110285Snyan
57110285Snyan/* canbus softc */
58110285Snyanstruct canbus_softc {
59110285Snyan	int io_delay_time;			/* CanBe I/O delay time */
60110285Snyan
61110285Snyan	struct sysctl_ctx_list canbus_sysctl_ctx;
62110285Snyan						/* dynamic sysctl tree */
63110285Snyan
64110285Snyan	/* index register */
65110285Snyan	int index_id;				/* index ID */
66110285Snyan	struct resource *index_res;		/* index resouce */
67110285Snyan	bus_space_tag_t index_tag;		/* index tag */
68110285Snyan	bus_space_handle_t index_handle;	/* index handle */
69110285Snyan
70110285Snyan	/* data register */
71110285Snyan	int data_id;				/* data ID */
72110285Snyan	struct resource *data_res;		/* data resouce */
73110285Snyan	bus_space_tag_t data_tag;		/* data tag */
74110285Snyan	bus_space_handle_t data_handle;		/* data handle */
75110285Snyan};
76110285Snyan
77110285Snyan
78110285Snyan/* Device interface methods */
79110285Snyanstatic void	canbus_identify(driver_t *, device_t);
80110285Snyanstatic int	canbus_probe(device_t);
81110285Snyanstatic int	canbus_attach(device_t);
82110285Snyanstatic int	canbus_detach(device_t);
83110285Snyan
84110285Snyan/* Bus interface methods */
85110285Snyanstatic int	canbus_print_child(device_t, device_t);
86110285Snyanstatic device_t	canbus_add_child(device_t, int, const char *, int);
87110285Snyanstatic struct resource *	canbus_alloc_resource(
88110285Snyan    device_t, device_t, int, int *, u_long, u_long, u_long, u_int);
89110285Snyanstatic int	canbus_activate_resource(
90110285Snyan    device_t, device_t, int, int, struct resource *);
91110285Snyanstatic int	canbus_deactivate_resource(
92110285Snyan    device_t, device_t, int, int, struct resource *);
93110285Snyanstatic int	canbus_release_resource(
94110285Snyan    device_t, device_t, int, int, struct resource *);
95110285Snyanstatic int	canbus_set_resource (
96110285Snyan    device_t, device_t, int, int, u_long, u_long);
97110285Snyanstatic void	canbus_delete_resource(device_t, device_t, int, int);
98110285Snyan
99110285Snyan/* canbus local function */
100110285Snyanstatic void	set_ioresource(device_t dev);
101110285Snyanstatic void	delete_ioresource(device_t dev);
102110285Snyanstatic int	alloc_ioresource(device_t);
103110285Snyanstatic void	release_ioresource(device_t);
104110285Snyanstatic int	print_all_resources(device_t);
105110285Snyan
106110285Snyanstatic device_method_t canbus_methods[] = {
107110285Snyan	/* Device interface */
108110285Snyan	DEVMETHOD(device_identify,	canbus_identify),
109110285Snyan	DEVMETHOD(device_probe,		canbus_probe),
110110285Snyan	DEVMETHOD(device_attach,	canbus_attach),
111110285Snyan	DEVMETHOD(device_detach,	canbus_detach),
112110285Snyan
113110285Snyan	/* Bus interface */
114110285Snyan	DEVMETHOD(bus_print_child,	canbus_print_child),
115110285Snyan	DEVMETHOD(bus_add_child,	canbus_add_child),
116110285Snyan	DEVMETHOD(bus_alloc_resource,	canbus_alloc_resource),
117110285Snyan	DEVMETHOD(bus_activate_resource,	canbus_activate_resource),
118110285Snyan	DEVMETHOD(bus_deactivate_resource,	canbus_deactivate_resource),
119110285Snyan	DEVMETHOD(bus_release_resource,	canbus_release_resource),
120110285Snyan	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
121110285Snyan	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
122110285Snyan	DEVMETHOD(bus_set_resource,	canbus_set_resource),
123110285Snyan	DEVMETHOD(bus_delete_resource,	canbus_delete_resource),
124110285Snyan
125110285Snyan	/* CanBe interface */
126110285Snyan	DEVMETHOD(canbus_read,		canbus_read),
127110285Snyan	DEVMETHOD(canbus_write,		canbus_write),
128110285Snyan	DEVMETHOD(canbus_write_multi,	canbus_write_multi),
129110285Snyan
130110285Snyan	{0, 0}
131110285Snyan};
132110285Snyan
133110285Snyanstatic driver_t canbus_driver = {
134110285Snyan	"canbus",
135110285Snyan	canbus_methods,
136110285Snyan	sizeof(struct canbus_softc),
137110285Snyan};
138110285Snyan
139110285Snyandevclass_t canbus_devclass;
140110285SnyanDRIVER_MODULE(canbus, nexus, canbus_driver, canbus_devclass, 0, 0);
141110285SnyanMODULE_VERSION(canbus, 1);
142110285Snyan
143110285Snyan
144110285Snyanstatic void
145110285Snyancanbus_identify(driver_t *drv, device_t parent)
146110285Snyan{
147110285Snyan	if (device_find_child(parent, "canbus", 0) == NULL) {
148110285Snyan		if (BUS_ADD_CHILD(parent, 33, "canbus", 0) == NULL)
149110285Snyan			device_printf(parent, "canbus cannot attach\n");
150110285Snyan	}
151110285Snyan}
152110285Snyan
153110285Snyan
154110285Snyanstatic int
155110285Snyancanbus_probe(device_t dev)
156110285Snyan{
157110285Snyan	u_int8_t flag;
158110285Snyan
159110285Snyan	set_ioresource(dev);
160110285Snyan	if(alloc_ioresource(dev))
161110285Snyan		return (ENXIO);
162110285Snyan	flag = canbus_read(dev, NULL, CANBE_SOUND_INTR_ADDR);
163110285Snyan	release_ioresource(dev);
164110285Snyan
165110285Snyan	if (bootverbose)
166110285Snyan		device_printf(dev, "probe flag = 0x%x\n", flag);
167110285Snyan
168110285Snyan	if (flag != CANBE_SOUND_INTR_VAL0 && flag != CANBE_SOUND_INTR_VAL1 &&
169110285Snyan	    flag != CANBE_SOUND_INTR_VAL2 && flag != CANBE_SOUND_INTR_VAL3) {
170110285Snyan		device_printf(dev, "Device Not Found\n");
171110285Snyan		return (ENXIO);
172110285Snyan	}
173110285Snyan	device_set_desc(dev, "CanBe I/O Bus");
174110285Snyan
175110285Snyan	return (0);
176110285Snyan}
177110285Snyan
178110285Snyanstatic int
179110285Snyancanbus_attach(device_t dev)
180110285Snyan{
181110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
182110285Snyan	struct sysctl_oid *canbus_sysctl_tree;
183110285Snyan
184110285Snyan	sc->io_delay_time = CANBE_IO_DELAY_TIME;
185110285Snyan
186110285Snyan	/* I/O resource setup */
187110285Snyan	if(alloc_ioresource(dev))
188110285Snyan		return (ENXIO);
189110285Snyan
190110285Snyan	/* Dynamic sysctl tree setup */
191110285Snyan	sysctl_ctx_init(&sc->canbus_sysctl_ctx);
192110285Snyan	canbus_sysctl_tree = SYSCTL_ADD_NODE(&sc->canbus_sysctl_ctx,
193110285Snyan	    SYSCTL_STATIC_CHILDREN(/* tree top */), OID_AUTO,
194110285Snyan	    "canbus", CTLFLAG_RD, 0, "CanBe I/O Bus");
195110285Snyan	SYSCTL_ADD_INT(&sc->canbus_sysctl_ctx,
196110285Snyan	    SYSCTL_CHILDREN(canbus_sysctl_tree), OID_AUTO, "io_delay_time",
197110285Snyan	    CTLFLAG_RW, &sc->io_delay_time, 0, "CanBe Bus I/O delay time");
198110285Snyan
199110285Snyan	bus_generic_probe(dev);
200110285Snyan	bus_generic_attach(dev);
201110285Snyan
202110285Snyan	return (0);
203110285Snyan}
204110285Snyan
205110285Snyan
206110285Snyanstatic int
207110285Snyancanbus_detach(device_t dev)
208110285Snyan{
209110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
210110285Snyan
211110285Snyan	/* I/O resource free */
212110285Snyan	release_ioresource(dev);
213110285Snyan	delete_ioresource(dev);
214110285Snyan
215110285Snyan	/* Dynamic sysctl tree destroy */
216110285Snyan	if (sysctl_ctx_free(&sc->canbus_sysctl_ctx)) {
217110285Snyan		device_printf(dev,
218110285Snyan		    "can't free this context - other oids depend on it\n");
219110285Snyan		return (ENOTEMPTY);
220110285Snyan	}
221110285Snyan
222110285Snyan	return (0);
223110285Snyan}
224110285Snyan
225110285Snyan
226110285Snyanstatic int
227110285Snyancanbus_print_child(device_t dev, device_t child)
228110285Snyan{
229110285Snyan	int     retval = 0;
230110285Snyan
231110285Snyan	retval += bus_print_child_header(dev, child);
232110285Snyan	retval += print_all_resources(child);
233110285Snyan	retval += bus_print_child_footer(dev, child);
234110285Snyan
235110285Snyan	return (retval);
236110285Snyan}
237110285Snyan
238110285Snyanstatic device_t
239110285Snyancanbus_add_child(device_t bus, int order, const char *name, int unit)
240110285Snyan{
241110285Snyan	device_t child;
242110285Snyan	struct canbus_device *cbdev;
243110285Snyan
244110285Snyan	child = device_add_child_ordered(bus, order, name, unit);
245110285Snyan
246110285Snyan	cbdev = malloc(
247110285Snyan	    sizeof(struct canbus_device), M_CANBUSDEV, M_NOWAIT | M_ZERO);
248110285Snyan	if (!cbdev)
249110285Snyan		return (0);
250110285Snyan
251110285Snyan	resource_list_init(&cbdev->cbdev_resources);
252110285Snyan	device_set_ivars(child, cbdev);
253110285Snyan
254110285Snyan	return (child);
255110285Snyan}
256110285Snyan
257110285Snyanstatic struct resource *
258110285Snyancanbus_alloc_resource(device_t dev, device_t child, int type,
259110285Snyan    int *rid, u_long start, u_long end, u_long count, u_int flags)
260110285Snyan{
261110285Snyan	return (BUS_ALLOC_RESOURCE(device_get_parent(dev),
262110285Snyan	    child, type, rid, start, end, count, flags));
263110285Snyan}
264110285Snyan
265110285Snyanstatic int
266110285Snyancanbus_activate_resource(
267110285Snyan    device_t dev, device_t child, int type, int rid, struct resource *res)
268110285Snyan{
269110285Snyan	return (BUS_ACTIVATE_RESOURCE(
270110285Snyan	    device_get_parent(dev), child, type, rid, res));
271110285Snyan}
272110285Snyan
273110285Snyanstatic int
274110285Snyancanbus_deactivate_resource(
275110285Snyan    device_t dev, device_t child, int type, int rid, struct resource *res)
276110285Snyan{
277110285Snyan	return (BUS_DEACTIVATE_RESOURCE(
278110285Snyan	    device_get_parent(dev), child, type, rid, res));
279110285Snyan}
280110285Snyan
281110285Snyanstatic int
282110285Snyancanbus_release_resource(
283110285Snyan    device_t dev, device_t child, int type, int rid, struct resource *res)
284110285Snyan{
285110285Snyan	return (BUS_RELEASE_RESOURCE(
286110285Snyan	    device_get_parent(dev), child, type, rid, res));
287110285Snyan}
288110285Snyan
289110285Snyanstatic int
290110285Snyancanbus_set_resource (
291110285Snyan    device_t dev, device_t child, int type, int rid, u_long start, u_long count)
292110285Snyan{
293110285Snyan	struct  canbus_device *cbdev =
294110285Snyan	    (struct canbus_device *)device_get_ivars(child);
295110285Snyan	struct resource_list *rl = &cbdev->cbdev_resources;
296110285Snyan
297110285Snyan	resource_list_add(rl, type, rid, start, (start + count - 1), count);
298110285Snyan
299110285Snyan	return (0);
300110285Snyan}
301110285Snyan
302110285Snyanstatic void
303110285Snyancanbus_delete_resource(device_t dev, device_t child, int type, int rid)
304110285Snyan{
305110285Snyan        struct  canbus_device *cbdev =
306110285Snyan	    (struct canbus_device *)device_get_ivars(child);
307110285Snyan        struct resource_list *rl = &cbdev->cbdev_resources;
308110285Snyan
309110285Snyan        resource_list_delete(rl, type, rid);
310110285Snyan}
311110285Snyan
312110285Snyan
313110285Snyanu_int8_t
314110285Snyancanbus_read(device_t dev, device_t child, int reg)
315110285Snyan{
316110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
317110285Snyan
318110285Snyan	bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
319110285Snyan	return (bus_space_read_1(sc->data_tag, sc->data_handle, 0));
320110285Snyan}
321110285Snyan
322110285Snyanvoid
323110285Snyancanbus_write(device_t dev, device_t child, int reg, u_int8_t val)
324110285Snyan{
325110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
326110285Snyan
327110285Snyan	bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
328110285Snyan	bus_space_write_1(sc->data_tag, sc->data_handle, 0, val);
329110285Snyan}
330110285Snyan
331110285Snyanvoid
332110285Snyancanbus_write_multi(device_t dev,
333110285Snyan    device_t child, int reg, const int count, const u_int8_t *vals)
334110285Snyan{
335110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
336110285Snyan	int i;
337110285Snyan
338110285Snyan	bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
339110285Snyan
340110285Snyan	for (i = 0; i < count; i ++) {
341110285Snyan		bus_space_write_1(sc->data_tag, sc->data_handle, 0, vals[i]);
342110285Snyan		DELAY(sc->io_delay_time);
343110285Snyan	}
344110285Snyan}
345110285Snyan
346110285Snyanvoid
347110285Snyancanbus_delay(device_t dev, device_t child)
348110285Snyan{
349110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
350110285Snyan
351110285Snyan	DELAY(sc->io_delay_time);
352110285Snyan}
353110285Snyan
354110285Snyan
355110285Snyan/*
356110285Snyan * canbus local function.
357110285Snyan */
358110285Snyan
359110285Snyan/*
360110285Snyan * CanBe I/O resource set function
361110285Snyan */
362110285Snyanstatic void
363110285Snyanset_ioresource(device_t dev)
364110285Snyan{
365110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
366110285Snyan
367110285Snyan	sc->index_id = 0;
368110285Snyan	sc->data_id = 1;
369110285Snyan
370110285Snyan	bus_set_resource(
371110285Snyan	    dev, SYS_RES_IOPORT, sc->index_id, CANBE_IOPORT_INDEX, 1);
372110285Snyan	bus_set_resource(
373110285Snyan	    dev, SYS_RES_IOPORT, sc->data_id, CANBE_IOPORT_DATA, 1);
374110285Snyan}
375110285Snyan
376110285Snyan/*
377110285Snyan * CanBe I/O resource delete function
378110285Snyan */
379110285Snyanstatic void
380110285Snyandelete_ioresource(device_t dev)
381110285Snyan{
382110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
383110285Snyan
384110285Snyan	bus_delete_resource(dev, SYS_RES_IOPORT, sc->index_id);
385110285Snyan	bus_delete_resource(dev, SYS_RES_IOPORT, sc->data_id);
386110285Snyan}
387110285Snyan
388110285Snyan/*
389110285Snyan * CanBe I/O resource alloc function
390110285Snyan */
391110285Snyanstatic int
392110285Snyanalloc_ioresource(device_t dev)
393110285Snyan{
394110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
395110285Snyan
396110285Snyan	sc->index_res = bus_alloc_resource(
397110285Snyan	    dev, SYS_RES_IOPORT, &sc->index_id, 0ul, ~0ul, 1, RF_ACTIVE);
398110285Snyan	sc->data_res = bus_alloc_resource(
399110285Snyan	    dev, SYS_RES_IOPORT, &sc->data_id, 0ul, ~0ul, 1, RF_ACTIVE);
400110285Snyan	if (sc->index_res == NULL || sc->data_res == NULL) {
401110285Snyan		device_printf(dev, "could not map I/O\n");
402110285Snyan		return (ENXIO);
403110285Snyan	}
404110285Snyan
405110285Snyan	sc->index_tag = rman_get_bustag(sc->index_res);
406110285Snyan	sc->index_handle = rman_get_bushandle(sc->index_res);
407110285Snyan	sc->data_tag = rman_get_bustag(sc->data_res);
408110285Snyan	sc->data_handle = rman_get_bushandle(sc->data_res);
409110285Snyan
410110285Snyan	return (0);
411110285Snyan}
412110285Snyan
413110285Snyan/*
414110285Snyan * CanBe I/O resource release function
415110285Snyan */
416110285Snyanstatic void
417110285Snyanrelease_ioresource(device_t dev)
418110285Snyan{
419110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
420110285Snyan
421110285Snyan	bus_release_resource(dev, SYS_RES_IOPORT, sc->index_id, sc->index_res);
422110285Snyan	bus_release_resource(dev, SYS_RES_IOPORT, sc->data_id, sc->data_res);
423110285Snyan}
424110285Snyan
425110285Snyan
426110285Snyanstatic int
427110285Snyanprint_all_resources(device_t dev)
428110285Snyan{
429110285Snyan	struct  canbus_device *cbdev =
430110285Snyan	    (struct canbus_device *)device_get_ivars(dev);
431110285Snyan	struct resource_list *rl = &cbdev->cbdev_resources;
432110285Snyan	int retval = 0;
433110285Snyan
434110285Snyan	if (SLIST_FIRST(rl))
435110285Snyan		retval += printf(" at");
436110285Snyan
437110285Snyan	retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
438110285Snyan	retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
439110285Snyan	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
440110285Snyan
441110285Snyan	return retval;
442110285Snyan}
443