canbus.c revision 110329
138786Sdfr/*- 238786Sdfr * Copyright (c) 2000 KIYOHARA Takashi <kiyohara@kk.iij4u.ne.jp> 338786Sdfr * Copyright (c) 2000 Takanori Watanabe <takawata@jp.FreeBSD.org> 438786Sdfr * 538786Sdfr * Redistribution and use in source and binary forms, with or without 638786Sdfr * modification, are permitted provided that the following conditions 738786Sdfr * are met: 838786Sdfr * 1. Redistributions of source code must retain the above copyright 938786Sdfr * notice, this list of conditions and the following disclaimer. 1038786Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1138786Sdfr * notice, this list of conditions and the following disclaimer in the 1238786Sdfr * documentation and/or other materials provided with the distribution. 1338786Sdfr * 1438786Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538786Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638786Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738786Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838786Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938786Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038786Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138786Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238786Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338786Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438786Sdfr * 2538786Sdfr * $FreeBSD: head/sys/pc98/pc98/canbus.c 110329 2003-02-04 15:50:33Z takawata $ 2638786Sdfr */ 2738786Sdfr 2838786Sdfr#include <sys/param.h> 2950476Speter#include <sys/systm.h> 3038786Sdfr#include <sys/bus.h> 3138786Sdfr#include <sys/kernel.h> 3249831Smpp#include <sys/malloc.h> 3379538Sru#include <sys/module.h> 3438786Sdfr#include <sys/sysctl.h> 3538786Sdfr 3638786Sdfr#include <machine/clock.h> 3738786Sdfr 3838786Sdfr#include <machine/bus.h> 3938786Sdfr#include <machine/resource.h> 4084306Sru#include <sys/rman.h> 4184306Sru 4238786Sdfr#include <pc98/pc98/canbus.h> 4338786Sdfr#include <pc98/pc98/canbusvars.h> 4438786Sdfr#include "canbus_if.h" 4538786Sdfr 4638786Sdfr 4738786Sdfr#define CANBE_IO_DELAY_TIME 5000 48121380Shmp 49121380Shmp 5038786Sdfrstatic MALLOC_DEFINE(M_CANBUSDEV, "canbusdev", "CanBe device"); 5138786Sdfrstruct canbus_device { 5238786Sdfr struct resource_list cbdev_resources; 5338786Sdfr}; 5438786Sdfr 5538786Sdfr/* canbus softc */ 5638786Sdfrstruct canbus_softc { 5738786Sdfr int io_delay_time; /* CanBe I/O delay time */ 58147647Shmp 5938786Sdfr struct sysctl_ctx_list canbus_sysctl_ctx; 60 /* dynamic sysctl tree */ 61 62 /* index register */ 63 int index_id; /* index ID */ 64 struct resource *index_res; /* index resouce */ 65 bus_space_tag_t index_tag; /* index tag */ 66 bus_space_handle_t index_handle; /* index handle */ 67 68 /* data register */ 69 int data_id; /* data ID */ 70 struct resource *data_res; /* data resouce */ 71 bus_space_tag_t data_tag; /* data tag */ 72 bus_space_handle_t data_handle; /* data handle */ 73}; 74 75 76/* Device interface methods */ 77static void canbus_identify(driver_t *, device_t); 78static int canbus_probe(device_t); 79static int canbus_attach(device_t); 80static int canbus_detach(device_t); 81 82/* Bus interface methods */ 83static int canbus_print_child(device_t, device_t); 84static device_t canbus_add_child(device_t, int, const char *, int); 85static struct resource * canbus_alloc_resource( 86 device_t, device_t, int, int *, u_long, u_long, u_long, u_int); 87static int canbus_activate_resource( 88 device_t, device_t, int, int, struct resource *); 89static int canbus_deactivate_resource( 90 device_t, device_t, int, int, struct resource *); 91static int canbus_release_resource( 92 device_t, device_t, int, int, struct resource *); 93static int canbus_set_resource ( 94 device_t, device_t, int, int, u_long, u_long); 95static void canbus_delete_resource(device_t, device_t, int, int); 96 97/* canbus local function */ 98static void set_ioresource(device_t dev); 99static void delete_ioresource(device_t dev); 100static int alloc_ioresource(device_t); 101static void release_ioresource(device_t); 102static int print_all_resources(device_t); 103 104static device_method_t canbus_methods[] = { 105 /* Device interface */ 106 DEVMETHOD(device_identify, canbus_identify), 107 DEVMETHOD(device_probe, canbus_probe), 108 DEVMETHOD(device_attach, canbus_attach), 109 DEVMETHOD(device_detach, canbus_detach), 110 111 /* Bus interface */ 112 DEVMETHOD(bus_print_child, canbus_print_child), 113 DEVMETHOD(bus_add_child, canbus_add_child), 114 DEVMETHOD(bus_alloc_resource, canbus_alloc_resource), 115 DEVMETHOD(bus_activate_resource, canbus_activate_resource), 116 DEVMETHOD(bus_deactivate_resource, canbus_deactivate_resource), 117 DEVMETHOD(bus_release_resource, canbus_release_resource), 118 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 119 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 120 DEVMETHOD(bus_set_resource, canbus_set_resource), 121 DEVMETHOD(bus_delete_resource, canbus_delete_resource), 122 123 /* CanBe interface */ 124 DEVMETHOD(canbus_read, canbus_read), 125 DEVMETHOD(canbus_write, canbus_write), 126 DEVMETHOD(canbus_write_multi, canbus_write_multi), 127 128 {0, 0} 129}; 130 131static driver_t canbus_driver = { 132 "canbus", 133 canbus_methods, 134 sizeof(struct canbus_softc), 135}; 136 137devclass_t canbus_devclass; 138DRIVER_MODULE(canbus, nexus, canbus_driver, canbus_devclass, 0, 0); 139MODULE_VERSION(canbus, 1); 140 141 142static void 143canbus_identify(driver_t *drv, device_t parent) 144{ 145 if (device_find_child(parent, "canbus", 0) == NULL) { 146 if (BUS_ADD_CHILD(parent, 33, "canbus", 0) == NULL) 147 device_printf(parent, "canbus cannot attach\n"); 148 } 149} 150 151 152static int 153canbus_probe(device_t dev) 154{ 155 u_int8_t flag; 156 157 set_ioresource(dev); 158 if(alloc_ioresource(dev)) 159 return (ENXIO); 160 flag = canbus_read(dev, NULL, CANBE_SOUND_INTR_ADDR); 161 release_ioresource(dev); 162 163 if (bootverbose) 164 device_printf(dev, "probe flag = 0x%x\n", flag); 165 166 if (flag != CANBE_SOUND_INTR_VAL0 && flag != CANBE_SOUND_INTR_VAL1 && 167 flag != CANBE_SOUND_INTR_VAL2 && flag != CANBE_SOUND_INTR_VAL3) { 168 device_printf(dev, "Device Not Found\n"); 169 return (ENXIO); 170 } 171 device_set_desc(dev, "CanBe I/O Bus"); 172 173 return (0); 174} 175 176static int 177canbus_attach(device_t dev) 178{ 179 struct canbus_softc *sc = device_get_softc(dev); 180 struct sysctl_oid *canbus_sysctl_tree; 181 182 sc->io_delay_time = CANBE_IO_DELAY_TIME; 183 184 /* I/O resource setup */ 185 if(alloc_ioresource(dev)) 186 return (ENXIO); 187 188 /* Dynamic sysctl tree setup */ 189 sysctl_ctx_init(&sc->canbus_sysctl_ctx); 190 canbus_sysctl_tree = SYSCTL_ADD_NODE(&sc->canbus_sysctl_ctx, 191 SYSCTL_STATIC_CHILDREN(/* tree top */), OID_AUTO, 192 "canbus", CTLFLAG_RD, 0, "CanBe I/O Bus"); 193 SYSCTL_ADD_INT(&sc->canbus_sysctl_ctx, 194 SYSCTL_CHILDREN(canbus_sysctl_tree), OID_AUTO, "io_delay_time", 195 CTLFLAG_RW, &sc->io_delay_time, 0, "CanBe Bus I/O delay time"); 196 197 bus_generic_probe(dev); 198 bus_generic_attach(dev); 199 200 return (0); 201} 202 203 204static int 205canbus_detach(device_t dev) 206{ 207 struct canbus_softc *sc = device_get_softc(dev); 208 209 /* I/O resource free */ 210 release_ioresource(dev); 211 delete_ioresource(dev); 212 213 /* Dynamic sysctl tree destroy */ 214 if (sysctl_ctx_free(&sc->canbus_sysctl_ctx)) { 215 device_printf(dev, 216 "can't free this context - other oids depend on it\n"); 217 return (ENOTEMPTY); 218 } 219 220 return (0); 221} 222 223 224static int 225canbus_print_child(device_t dev, device_t child) 226{ 227 int retval = 0; 228 229 retval += bus_print_child_header(dev, child); 230 retval += print_all_resources(child); 231 retval += bus_print_child_footer(dev, child); 232 233 return (retval); 234} 235 236static device_t 237canbus_add_child(device_t bus, int order, const char *name, int unit) 238{ 239 device_t child; 240 struct canbus_device *cbdev; 241 242 child = device_add_child_ordered(bus, order, name, unit); 243 244 cbdev = malloc( 245 sizeof(struct canbus_device), M_CANBUSDEV, M_NOWAIT | M_ZERO); 246 if (!cbdev) 247 return (0); 248 249 resource_list_init(&cbdev->cbdev_resources); 250 device_set_ivars(child, cbdev); 251 252 return (child); 253} 254 255static struct resource * 256canbus_alloc_resource(device_t dev, device_t child, int type, 257 int *rid, u_long start, u_long end, u_long count, u_int flags) 258{ 259 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), 260 child, type, rid, start, end, count, flags)); 261} 262 263static int 264canbus_activate_resource( 265 device_t dev, device_t child, int type, int rid, struct resource *res) 266{ 267 return (BUS_ACTIVATE_RESOURCE( 268 device_get_parent(dev), child, type, rid, res)); 269} 270 271static int 272canbus_deactivate_resource( 273 device_t dev, device_t child, int type, int rid, struct resource *res) 274{ 275 return (BUS_DEACTIVATE_RESOURCE( 276 device_get_parent(dev), child, type, rid, res)); 277} 278 279static int 280canbus_release_resource( 281 device_t dev, device_t child, int type, int rid, struct resource *res) 282{ 283 return (BUS_RELEASE_RESOURCE( 284 device_get_parent(dev), child, type, rid, res)); 285} 286 287static int 288canbus_set_resource ( 289 device_t dev, device_t child, int type, int rid, u_long start, u_long count) 290{ 291 struct canbus_device *cbdev = 292 (struct canbus_device *)device_get_ivars(child); 293 struct resource_list *rl = &cbdev->cbdev_resources; 294 295 resource_list_add(rl, type, rid, start, (start + count - 1), count); 296 297 return (0); 298} 299 300static void 301canbus_delete_resource(device_t dev, device_t child, int type, int rid) 302{ 303 struct canbus_device *cbdev = 304 (struct canbus_device *)device_get_ivars(child); 305 struct resource_list *rl = &cbdev->cbdev_resources; 306 307 resource_list_delete(rl, type, rid); 308} 309 310 311u_int8_t 312canbus_read(device_t dev, device_t child, int reg) 313{ 314 struct canbus_softc *sc = device_get_softc(dev); 315 316 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg); 317 return (bus_space_read_1(sc->data_tag, sc->data_handle, 0)); 318} 319 320void 321canbus_write(device_t dev, device_t child, int reg, u_int8_t val) 322{ 323 struct canbus_softc *sc = device_get_softc(dev); 324 325 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg); 326 bus_space_write_1(sc->data_tag, sc->data_handle, 0, val); 327} 328 329void 330canbus_write_multi(device_t dev, 331 device_t child, int reg, const int count, const u_int8_t *vals) 332{ 333 struct canbus_softc *sc = device_get_softc(dev); 334 int i; 335 336 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg); 337 338 for (i = 0; i < count; i ++) { 339 bus_space_write_1(sc->data_tag, sc->data_handle, 0, vals[i]); 340 DELAY(sc->io_delay_time); 341 } 342} 343 344void 345canbus_delay(device_t dev, device_t child) 346{ 347 struct canbus_softc *sc = device_get_softc(dev); 348 349 DELAY(sc->io_delay_time); 350} 351 352 353/* 354 * canbus local function. 355 */ 356 357/* 358 * CanBe I/O resource set function 359 */ 360static void 361set_ioresource(device_t dev) 362{ 363 struct canbus_softc *sc = device_get_softc(dev); 364 365 sc->index_id = 0; 366 sc->data_id = 1; 367 368 bus_set_resource( 369 dev, SYS_RES_IOPORT, sc->index_id, CANBE_IOPORT_INDEX, 1); 370 bus_set_resource( 371 dev, SYS_RES_IOPORT, sc->data_id, CANBE_IOPORT_DATA, 1); 372} 373 374/* 375 * CanBe I/O resource delete function 376 */ 377static void 378delete_ioresource(device_t dev) 379{ 380 struct canbus_softc *sc = device_get_softc(dev); 381 382 bus_delete_resource(dev, SYS_RES_IOPORT, sc->index_id); 383 bus_delete_resource(dev, SYS_RES_IOPORT, sc->data_id); 384} 385 386/* 387 * CanBe I/O resource alloc function 388 */ 389static int 390alloc_ioresource(device_t dev) 391{ 392 struct canbus_softc *sc = device_get_softc(dev); 393 394 sc->index_res = bus_alloc_resource( 395 dev, SYS_RES_IOPORT, &sc->index_id, 0ul, ~0ul, 1, RF_ACTIVE); 396 sc->data_res = bus_alloc_resource( 397 dev, SYS_RES_IOPORT, &sc->data_id, 0ul, ~0ul, 1, RF_ACTIVE); 398 if (sc->index_res == NULL || sc->data_res == NULL) { 399 device_printf(dev, "could not map I/O\n"); 400 return (ENXIO); 401 } 402 403 sc->index_tag = rman_get_bustag(sc->index_res); 404 sc->index_handle = rman_get_bushandle(sc->index_res); 405 sc->data_tag = rman_get_bustag(sc->data_res); 406 sc->data_handle = rman_get_bushandle(sc->data_res); 407 408 return (0); 409} 410 411/* 412 * CanBe I/O resource release function 413 */ 414static void 415release_ioresource(device_t dev) 416{ 417 struct canbus_softc *sc = device_get_softc(dev); 418 419 bus_release_resource(dev, SYS_RES_IOPORT, sc->index_id, sc->index_res); 420 bus_release_resource(dev, SYS_RES_IOPORT, sc->data_id, sc->data_res); 421} 422 423 424static int 425print_all_resources(device_t dev) 426{ 427 struct canbus_device *cbdev = 428 (struct canbus_device *)device_get_ivars(dev); 429 struct resource_list *rl = &cbdev->cbdev_resources; 430 int retval = 0; 431 432 if (SLIST_FIRST(rl)) 433 retval += printf(" at"); 434 435 retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); 436 retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx"); 437 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 438 439 return retval; 440} 441