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