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$
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
39110285Snyan#include <machine/bus.h>
40110285Snyan#include <machine/resource.h>
41110285Snyan#include <sys/rman.h>
42110285Snyan
43110285Snyan#include <pc98/pc98/canbus.h>
44110285Snyan#include <pc98/pc98/canbusvars.h>
45110285Snyan#include "canbus_if.h"
46110285Snyan
47110285Snyan
48110285Snyan#define CANBE_IO_DELAY_TIME 5000
49110285Snyan
50110285Snyan
51110285Snyanstatic MALLOC_DEFINE(M_CANBUSDEV, "canbusdev", "CanBe device");
52110285Snyanstruct canbus_device {
53110285Snyan	struct resource_list cbdev_resources;
54110285Snyan};
55110285Snyan
56110285Snyan/* canbus softc */
57110285Snyanstruct canbus_softc {
58110285Snyan	int io_delay_time;			/* CanBe I/O delay time */
59110285Snyan
60110285Snyan	struct sysctl_ctx_list canbus_sysctl_ctx;
61110285Snyan						/* dynamic sysctl tree */
62110285Snyan
63110285Snyan	/* index register */
64110285Snyan	int index_id;				/* index ID */
65249586Sgabor	struct resource *index_res;		/* index resource */
66110285Snyan	bus_space_tag_t index_tag;		/* index tag */
67110285Snyan	bus_space_handle_t index_handle;	/* index handle */
68110285Snyan
69110285Snyan	/* data register */
70110285Snyan	int data_id;				/* data ID */
71249586Sgabor	struct resource *data_res;		/* data resource */
72110285Snyan	bus_space_tag_t data_tag;		/* data tag */
73110285Snyan	bus_space_handle_t data_handle;		/* data handle */
74110285Snyan};
75110285Snyan
76110285Snyan
77110285Snyan/* Device interface methods */
78110285Snyanstatic void	canbus_identify(driver_t *, device_t);
79110285Snyanstatic int	canbus_probe(device_t);
80110285Snyanstatic int	canbus_attach(device_t);
81110285Snyanstatic int	canbus_detach(device_t);
82110285Snyan
83110285Snyan/* Bus interface methods */
84110285Snyanstatic int	canbus_print_child(device_t, device_t);
85212413Savgstatic device_t	canbus_add_child(device_t, u_int, const char *, int);
86110285Snyanstatic struct resource *	canbus_alloc_resource(
87294883Sjhibbits    device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int);
88110285Snyanstatic int	canbus_activate_resource(
89110285Snyan    device_t, device_t, int, int, struct resource *);
90110285Snyanstatic int	canbus_deactivate_resource(
91110285Snyan    device_t, device_t, int, int, struct resource *);
92110285Snyanstatic int	canbus_release_resource(
93110285Snyan    device_t, device_t, int, int, struct resource *);
94110285Snyanstatic int	canbus_set_resource (
95294883Sjhibbits    device_t, device_t, int, int, rman_res_t, rman_res_t);
96110285Snyanstatic void	canbus_delete_resource(device_t, device_t, int, int);
97110285Snyan
98110285Snyan/* canbus local function */
99110285Snyanstatic void	set_ioresource(device_t dev);
100110285Snyanstatic void	delete_ioresource(device_t dev);
101110285Snyanstatic int	alloc_ioresource(device_t);
102110285Snyanstatic void	release_ioresource(device_t);
103110285Snyanstatic int	print_all_resources(device_t);
104110285Snyan
105110285Snyanstatic device_method_t canbus_methods[] = {
106110285Snyan	/* Device interface */
107110285Snyan	DEVMETHOD(device_identify,	canbus_identify),
108110285Snyan	DEVMETHOD(device_probe,		canbus_probe),
109110285Snyan	DEVMETHOD(device_attach,	canbus_attach),
110110285Snyan	DEVMETHOD(device_detach,	canbus_detach),
111110285Snyan
112110285Snyan	/* Bus interface */
113110285Snyan	DEVMETHOD(bus_print_child,	canbus_print_child),
114110285Snyan	DEVMETHOD(bus_add_child,	canbus_add_child),
115110285Snyan	DEVMETHOD(bus_alloc_resource,	canbus_alloc_resource),
116110285Snyan	DEVMETHOD(bus_activate_resource,	canbus_activate_resource),
117110285Snyan	DEVMETHOD(bus_deactivate_resource,	canbus_deactivate_resource),
118110285Snyan	DEVMETHOD(bus_release_resource,	canbus_release_resource),
119110285Snyan	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
120110285Snyan	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
121110285Snyan	DEVMETHOD(bus_set_resource,	canbus_set_resource),
122110285Snyan	DEVMETHOD(bus_delete_resource,	canbus_delete_resource),
123110285Snyan
124110285Snyan	/* CanBe interface */
125110285Snyan	DEVMETHOD(canbus_read,		canbus_read),
126110285Snyan	DEVMETHOD(canbus_write,		canbus_write),
127110285Snyan	DEVMETHOD(canbus_write_multi,	canbus_write_multi),
128110285Snyan
129110285Snyan	{0, 0}
130110285Snyan};
131110285Snyan
132110285Snyanstatic driver_t canbus_driver = {
133110285Snyan	"canbus",
134110285Snyan	canbus_methods,
135110285Snyan	sizeof(struct canbus_softc),
136110285Snyan};
137110285Snyan
138110285Snyandevclass_t canbus_devclass;
139110285SnyanDRIVER_MODULE(canbus, nexus, canbus_driver, canbus_devclass, 0, 0);
140110285SnyanMODULE_VERSION(canbus, 1);
141110285Snyan
142110285Snyan
143110285Snyanstatic void
144110285Snyancanbus_identify(driver_t *drv, device_t parent)
145110285Snyan{
146110285Snyan	if (device_find_child(parent, "canbus", 0) == NULL) {
147110285Snyan		if (BUS_ADD_CHILD(parent, 33, "canbus", 0) == NULL)
148110285Snyan			device_printf(parent, "canbus cannot attach\n");
149110285Snyan	}
150110285Snyan}
151110285Snyan
152110285Snyan
153110285Snyanstatic int
154110285Snyancanbus_probe(device_t dev)
155110285Snyan{
156110285Snyan	u_int8_t flag;
157110285Snyan
158110285Snyan	set_ioresource(dev);
159110285Snyan	if(alloc_ioresource(dev))
160110285Snyan		return (ENXIO);
161110285Snyan	flag = canbus_read(dev, NULL, CANBE_SOUND_INTR_ADDR);
162110285Snyan	release_ioresource(dev);
163110285Snyan
164110285Snyan	if (bootverbose)
165110285Snyan		device_printf(dev, "probe flag = 0x%x\n", flag);
166110285Snyan
167110285Snyan	if (flag != CANBE_SOUND_INTR_VAL0 && flag != CANBE_SOUND_INTR_VAL1 &&
168110285Snyan	    flag != CANBE_SOUND_INTR_VAL2 && flag != CANBE_SOUND_INTR_VAL3) {
169110285Snyan		device_printf(dev, "Device Not Found\n");
170110285Snyan		return (ENXIO);
171110285Snyan	}
172110285Snyan	device_set_desc(dev, "CanBe I/O Bus");
173110285Snyan
174110285Snyan	return (0);
175110285Snyan}
176110285Snyan
177110285Snyanstatic int
178110285Snyancanbus_attach(device_t dev)
179110285Snyan{
180110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
181110285Snyan	struct sysctl_oid *canbus_sysctl_tree;
182110285Snyan
183110285Snyan	sc->io_delay_time = CANBE_IO_DELAY_TIME;
184110285Snyan
185110285Snyan	/* I/O resource setup */
186110285Snyan	if(alloc_ioresource(dev))
187110285Snyan		return (ENXIO);
188110285Snyan
189110285Snyan	/* Dynamic sysctl tree setup */
190110285Snyan	sysctl_ctx_init(&sc->canbus_sysctl_ctx);
191268005Shselasky	canbus_sysctl_tree = SYSCTL_ADD_ROOT_NODE(&sc->canbus_sysctl_ctx,
192268005Shselasky	    OID_AUTO, "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
237212413Savgcanbus_add_child(device_t bus, u_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,
257294883Sjhibbits    int *rid, rman_res_t start, rman_res_t end, rman_res_t 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 (
289294883Sjhibbits    device_t dev, device_t child, int type, int rid, rman_res_t start,
290294883Sjhibbits    rman_res_t count)
291110285Snyan{
292110285Snyan	struct  canbus_device *cbdev =
293110285Snyan	    (struct canbus_device *)device_get_ivars(child);
294110285Snyan	struct resource_list *rl = &cbdev->cbdev_resources;
295110285Snyan
296110285Snyan	resource_list_add(rl, type, rid, start, (start + count - 1), count);
297110285Snyan
298110285Snyan	return (0);
299110285Snyan}
300110285Snyan
301110285Snyanstatic void
302110285Snyancanbus_delete_resource(device_t dev, device_t child, int type, int rid)
303110285Snyan{
304110285Snyan        struct  canbus_device *cbdev =
305110285Snyan	    (struct canbus_device *)device_get_ivars(child);
306110285Snyan        struct resource_list *rl = &cbdev->cbdev_resources;
307110285Snyan
308110285Snyan        resource_list_delete(rl, type, rid);
309110285Snyan}
310110285Snyan
311110285Snyan
312110285Snyanu_int8_t
313110285Snyancanbus_read(device_t dev, device_t child, int reg)
314110285Snyan{
315110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
316110285Snyan
317110285Snyan	bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
318110285Snyan	return (bus_space_read_1(sc->data_tag, sc->data_handle, 0));
319110285Snyan}
320110285Snyan
321110285Snyanvoid
322110285Snyancanbus_write(device_t dev, device_t child, int reg, u_int8_t val)
323110285Snyan{
324110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
325110285Snyan
326110285Snyan	bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
327110285Snyan	bus_space_write_1(sc->data_tag, sc->data_handle, 0, val);
328110285Snyan}
329110285Snyan
330110285Snyanvoid
331110285Snyancanbus_write_multi(device_t dev,
332110285Snyan    device_t child, int reg, const int count, const u_int8_t *vals)
333110285Snyan{
334110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
335110285Snyan	int i;
336110285Snyan
337110285Snyan	bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg);
338110285Snyan
339110285Snyan	for (i = 0; i < count; i ++) {
340110285Snyan		bus_space_write_1(sc->data_tag, sc->data_handle, 0, vals[i]);
341110285Snyan		DELAY(sc->io_delay_time);
342110285Snyan	}
343110285Snyan}
344110285Snyan
345110285Snyanvoid
346110285Snyancanbus_delay(device_t dev, device_t child)
347110285Snyan{
348110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
349110285Snyan
350110285Snyan	DELAY(sc->io_delay_time);
351110285Snyan}
352110285Snyan
353110285Snyan
354110285Snyan/*
355110285Snyan * canbus local function.
356110285Snyan */
357110285Snyan
358110285Snyan/*
359110285Snyan * CanBe I/O resource set function
360110285Snyan */
361110285Snyanstatic void
362110285Snyanset_ioresource(device_t dev)
363110285Snyan{
364110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
365110285Snyan
366110285Snyan	sc->index_id = 0;
367110285Snyan	sc->data_id = 1;
368110285Snyan
369110285Snyan	bus_set_resource(
370110285Snyan	    dev, SYS_RES_IOPORT, sc->index_id, CANBE_IOPORT_INDEX, 1);
371110285Snyan	bus_set_resource(
372110285Snyan	    dev, SYS_RES_IOPORT, sc->data_id, CANBE_IOPORT_DATA, 1);
373110285Snyan}
374110285Snyan
375110285Snyan/*
376110285Snyan * CanBe I/O resource delete function
377110285Snyan */
378110285Snyanstatic void
379110285Snyandelete_ioresource(device_t dev)
380110285Snyan{
381110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
382110285Snyan
383110285Snyan	bus_delete_resource(dev, SYS_RES_IOPORT, sc->index_id);
384110285Snyan	bus_delete_resource(dev, SYS_RES_IOPORT, sc->data_id);
385110285Snyan}
386110285Snyan
387110285Snyan/*
388110285Snyan * CanBe I/O resource alloc function
389110285Snyan */
390110285Snyanstatic int
391110285Snyanalloc_ioresource(device_t dev)
392110285Snyan{
393110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
394110285Snyan
395127135Snjl	sc->index_res = bus_alloc_resource_any(
396127135Snjl	    dev, SYS_RES_IOPORT, &sc->index_id, RF_ACTIVE);
397127135Snjl	sc->data_res = bus_alloc_resource_any(
398127135Snjl	    dev, SYS_RES_IOPORT, &sc->data_id, RF_ACTIVE);
399110285Snyan	if (sc->index_res == NULL || sc->data_res == NULL) {
400110285Snyan		device_printf(dev, "could not map I/O\n");
401110285Snyan		return (ENXIO);
402110285Snyan	}
403110285Snyan
404110285Snyan	sc->index_tag = rman_get_bustag(sc->index_res);
405110285Snyan	sc->index_handle = rman_get_bushandle(sc->index_res);
406110285Snyan	sc->data_tag = rman_get_bustag(sc->data_res);
407110285Snyan	sc->data_handle = rman_get_bushandle(sc->data_res);
408110285Snyan
409110285Snyan	return (0);
410110285Snyan}
411110285Snyan
412110285Snyan/*
413110285Snyan * CanBe I/O resource release function
414110285Snyan */
415110285Snyanstatic void
416110285Snyanrelease_ioresource(device_t dev)
417110285Snyan{
418110285Snyan	struct canbus_softc *sc = device_get_softc(dev);
419110285Snyan
420110285Snyan	bus_release_resource(dev, SYS_RES_IOPORT, sc->index_id, sc->index_res);
421110285Snyan	bus_release_resource(dev, SYS_RES_IOPORT, sc->data_id, sc->data_res);
422110285Snyan}
423110285Snyan
424110285Snyan
425110285Snyanstatic int
426110285Snyanprint_all_resources(device_t dev)
427110285Snyan{
428110285Snyan	struct  canbus_device *cbdev =
429110285Snyan	    (struct canbus_device *)device_get_ivars(dev);
430110285Snyan	struct resource_list *rl = &cbdev->cbdev_resources;
431110285Snyan	int retval = 0;
432110285Snyan
433143866Snyan	if (STAILQ_FIRST(rl))
434110285Snyan		retval += printf(" at");
435110285Snyan
436297199Sjhibbits	retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
437297199Sjhibbits	retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#jx");
438297199Sjhibbits	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
439110285Snyan
440110285Snyan	return retval;
441110285Snyan}
442