canbus.c revision 127135
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: head/sys/pc98/pc98/canbus.c 127135 2004-03-17 17:50:55Z njl $ 28 */ 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/bus.h> 33#include <sys/kernel.h> 34#include <sys/malloc.h> 35#include <sys/module.h> 36#include <sys/sysctl.h> 37 38#include <machine/clock.h> 39 40#include <machine/bus.h> 41#include <machine/resource.h> 42#include <sys/rman.h> 43 44#include <pc98/pc98/canbus.h> 45#include <pc98/pc98/canbusvars.h> 46#include "canbus_if.h" 47 48 49#define CANBE_IO_DELAY_TIME 5000 50 51 52static MALLOC_DEFINE(M_CANBUSDEV, "canbusdev", "CanBe device"); 53struct canbus_device { 54 struct resource_list cbdev_resources; 55}; 56 57/* canbus softc */ 58struct canbus_softc { 59 int io_delay_time; /* CanBe I/O delay time */ 60 61 struct sysctl_ctx_list canbus_sysctl_ctx; 62 /* dynamic sysctl tree */ 63 64 /* index register */ 65 int index_id; /* index ID */ 66 struct resource *index_res; /* index resouce */ 67 bus_space_tag_t index_tag; /* index tag */ 68 bus_space_handle_t index_handle; /* index handle */ 69 70 /* data register */ 71 int data_id; /* data ID */ 72 struct resource *data_res; /* data resouce */ 73 bus_space_tag_t data_tag; /* data tag */ 74 bus_space_handle_t data_handle; /* data handle */ 75}; 76 77 78/* Device interface methods */ 79static void canbus_identify(driver_t *, device_t); 80static int canbus_probe(device_t); 81static int canbus_attach(device_t); 82static int canbus_detach(device_t); 83 84/* Bus interface methods */ 85static int canbus_print_child(device_t, device_t); 86static device_t canbus_add_child(device_t, int, const char *, int); 87static struct resource * canbus_alloc_resource( 88 device_t, device_t, int, int *, u_long, u_long, u_long, u_int); 89static int canbus_activate_resource( 90 device_t, device_t, int, int, struct resource *); 91static int canbus_deactivate_resource( 92 device_t, device_t, int, int, struct resource *); 93static int canbus_release_resource( 94 device_t, device_t, int, int, struct resource *); 95static int canbus_set_resource ( 96 device_t, device_t, int, int, u_long, u_long); 97static void canbus_delete_resource(device_t, device_t, int, int); 98 99/* canbus local function */ 100static void set_ioresource(device_t dev); 101static void delete_ioresource(device_t dev); 102static int alloc_ioresource(device_t); 103static void release_ioresource(device_t); 104static int print_all_resources(device_t); 105 106static device_method_t canbus_methods[] = { 107 /* Device interface */ 108 DEVMETHOD(device_identify, canbus_identify), 109 DEVMETHOD(device_probe, canbus_probe), 110 DEVMETHOD(device_attach, canbus_attach), 111 DEVMETHOD(device_detach, canbus_detach), 112 113 /* Bus interface */ 114 DEVMETHOD(bus_print_child, canbus_print_child), 115 DEVMETHOD(bus_add_child, canbus_add_child), 116 DEVMETHOD(bus_alloc_resource, canbus_alloc_resource), 117 DEVMETHOD(bus_activate_resource, canbus_activate_resource), 118 DEVMETHOD(bus_deactivate_resource, canbus_deactivate_resource), 119 DEVMETHOD(bus_release_resource, canbus_release_resource), 120 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 121 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 122 DEVMETHOD(bus_set_resource, canbus_set_resource), 123 DEVMETHOD(bus_delete_resource, canbus_delete_resource), 124 125 /* CanBe interface */ 126 DEVMETHOD(canbus_read, canbus_read), 127 DEVMETHOD(canbus_write, canbus_write), 128 DEVMETHOD(canbus_write_multi, canbus_write_multi), 129 130 {0, 0} 131}; 132 133static driver_t canbus_driver = { 134 "canbus", 135 canbus_methods, 136 sizeof(struct canbus_softc), 137}; 138 139devclass_t canbus_devclass; 140DRIVER_MODULE(canbus, nexus, canbus_driver, canbus_devclass, 0, 0); 141MODULE_VERSION(canbus, 1); 142 143 144static void 145canbus_identify(driver_t *drv, device_t parent) 146{ 147 if (device_find_child(parent, "canbus", 0) == NULL) { 148 if (BUS_ADD_CHILD(parent, 33, "canbus", 0) == NULL) 149 device_printf(parent, "canbus cannot attach\n"); 150 } 151} 152 153 154static int 155canbus_probe(device_t dev) 156{ 157 u_int8_t flag; 158 159 set_ioresource(dev); 160 if(alloc_ioresource(dev)) 161 return (ENXIO); 162 flag = canbus_read(dev, NULL, CANBE_SOUND_INTR_ADDR); 163 release_ioresource(dev); 164 165 if (bootverbose) 166 device_printf(dev, "probe flag = 0x%x\n", flag); 167 168 if (flag != CANBE_SOUND_INTR_VAL0 && flag != CANBE_SOUND_INTR_VAL1 && 169 flag != CANBE_SOUND_INTR_VAL2 && flag != CANBE_SOUND_INTR_VAL3) { 170 device_printf(dev, "Device Not Found\n"); 171 return (ENXIO); 172 } 173 device_set_desc(dev, "CanBe I/O Bus"); 174 175 return (0); 176} 177 178static int 179canbus_attach(device_t dev) 180{ 181 struct canbus_softc *sc = device_get_softc(dev); 182 struct sysctl_oid *canbus_sysctl_tree; 183 184 sc->io_delay_time = CANBE_IO_DELAY_TIME; 185 186 /* I/O resource setup */ 187 if(alloc_ioresource(dev)) 188 return (ENXIO); 189 190 /* Dynamic sysctl tree setup */ 191 sysctl_ctx_init(&sc->canbus_sysctl_ctx); 192 canbus_sysctl_tree = SYSCTL_ADD_NODE(&sc->canbus_sysctl_ctx, 193 SYSCTL_STATIC_CHILDREN(/* tree top */), OID_AUTO, 194 "canbus", CTLFLAG_RD, 0, "CanBe I/O Bus"); 195 SYSCTL_ADD_INT(&sc->canbus_sysctl_ctx, 196 SYSCTL_CHILDREN(canbus_sysctl_tree), OID_AUTO, "io_delay_time", 197 CTLFLAG_RW, &sc->io_delay_time, 0, "CanBe Bus I/O delay time"); 198 199 bus_generic_probe(dev); 200 bus_generic_attach(dev); 201 202 return (0); 203} 204 205 206static int 207canbus_detach(device_t dev) 208{ 209 struct canbus_softc *sc = device_get_softc(dev); 210 211 /* I/O resource free */ 212 release_ioresource(dev); 213 delete_ioresource(dev); 214 215 /* Dynamic sysctl tree destroy */ 216 if (sysctl_ctx_free(&sc->canbus_sysctl_ctx)) { 217 device_printf(dev, 218 "can't free this context - other oids depend on it\n"); 219 return (ENOTEMPTY); 220 } 221 222 return (0); 223} 224 225 226static int 227canbus_print_child(device_t dev, device_t child) 228{ 229 int retval = 0; 230 231 retval += bus_print_child_header(dev, child); 232 retval += print_all_resources(child); 233 retval += bus_print_child_footer(dev, child); 234 235 return (retval); 236} 237 238static device_t 239canbus_add_child(device_t bus, int order, const char *name, int unit) 240{ 241 device_t child; 242 struct canbus_device *cbdev; 243 244 child = device_add_child_ordered(bus, order, name, unit); 245 246 cbdev = malloc( 247 sizeof(struct canbus_device), M_CANBUSDEV, M_NOWAIT | M_ZERO); 248 if (!cbdev) 249 return (0); 250 251 resource_list_init(&cbdev->cbdev_resources); 252 device_set_ivars(child, cbdev); 253 254 return (child); 255} 256 257static struct resource * 258canbus_alloc_resource(device_t dev, device_t child, int type, 259 int *rid, u_long start, u_long end, u_long count, u_int flags) 260{ 261 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), 262 child, type, rid, start, end, count, flags)); 263} 264 265static int 266canbus_activate_resource( 267 device_t dev, device_t child, int type, int rid, struct resource *res) 268{ 269 return (BUS_ACTIVATE_RESOURCE( 270 device_get_parent(dev), child, type, rid, res)); 271} 272 273static int 274canbus_deactivate_resource( 275 device_t dev, device_t child, int type, int rid, struct resource *res) 276{ 277 return (BUS_DEACTIVATE_RESOURCE( 278 device_get_parent(dev), child, type, rid, res)); 279} 280 281static int 282canbus_release_resource( 283 device_t dev, device_t child, int type, int rid, struct resource *res) 284{ 285 return (BUS_RELEASE_RESOURCE( 286 device_get_parent(dev), child, type, rid, res)); 287} 288 289static int 290canbus_set_resource ( 291 device_t dev, device_t child, int type, int rid, u_long start, u_long count) 292{ 293 struct canbus_device *cbdev = 294 (struct canbus_device *)device_get_ivars(child); 295 struct resource_list *rl = &cbdev->cbdev_resources; 296 297 resource_list_add(rl, type, rid, start, (start + count - 1), count); 298 299 return (0); 300} 301 302static void 303canbus_delete_resource(device_t dev, device_t child, int type, int rid) 304{ 305 struct canbus_device *cbdev = 306 (struct canbus_device *)device_get_ivars(child); 307 struct resource_list *rl = &cbdev->cbdev_resources; 308 309 resource_list_delete(rl, type, rid); 310} 311 312 313u_int8_t 314canbus_read(device_t dev, device_t child, int reg) 315{ 316 struct canbus_softc *sc = device_get_softc(dev); 317 318 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg); 319 return (bus_space_read_1(sc->data_tag, sc->data_handle, 0)); 320} 321 322void 323canbus_write(device_t dev, device_t child, int reg, u_int8_t val) 324{ 325 struct canbus_softc *sc = device_get_softc(dev); 326 327 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg); 328 bus_space_write_1(sc->data_tag, sc->data_handle, 0, val); 329} 330 331void 332canbus_write_multi(device_t dev, 333 device_t child, int reg, const int count, const u_int8_t *vals) 334{ 335 struct canbus_softc *sc = device_get_softc(dev); 336 int i; 337 338 bus_space_write_1(sc->index_tag, sc->index_handle, 0, reg); 339 340 for (i = 0; i < count; i ++) { 341 bus_space_write_1(sc->data_tag, sc->data_handle, 0, vals[i]); 342 DELAY(sc->io_delay_time); 343 } 344} 345 346void 347canbus_delay(device_t dev, device_t child) 348{ 349 struct canbus_softc *sc = device_get_softc(dev); 350 351 DELAY(sc->io_delay_time); 352} 353 354 355/* 356 * canbus local function. 357 */ 358 359/* 360 * CanBe I/O resource set function 361 */ 362static void 363set_ioresource(device_t dev) 364{ 365 struct canbus_softc *sc = device_get_softc(dev); 366 367 sc->index_id = 0; 368 sc->data_id = 1; 369 370 bus_set_resource( 371 dev, SYS_RES_IOPORT, sc->index_id, CANBE_IOPORT_INDEX, 1); 372 bus_set_resource( 373 dev, SYS_RES_IOPORT, sc->data_id, CANBE_IOPORT_DATA, 1); 374} 375 376/* 377 * CanBe I/O resource delete function 378 */ 379static void 380delete_ioresource(device_t dev) 381{ 382 struct canbus_softc *sc = device_get_softc(dev); 383 384 bus_delete_resource(dev, SYS_RES_IOPORT, sc->index_id); 385 bus_delete_resource(dev, SYS_RES_IOPORT, sc->data_id); 386} 387 388/* 389 * CanBe I/O resource alloc function 390 */ 391static int 392alloc_ioresource(device_t dev) 393{ 394 struct canbus_softc *sc = device_get_softc(dev); 395 396 sc->index_res = bus_alloc_resource_any( 397 dev, SYS_RES_IOPORT, &sc->index_id, RF_ACTIVE); 398 sc->data_res = bus_alloc_resource_any( 399 dev, SYS_RES_IOPORT, &sc->data_id, RF_ACTIVE); 400 if (sc->index_res == NULL || sc->data_res == NULL) { 401 device_printf(dev, "could not map I/O\n"); 402 return (ENXIO); 403 } 404 405 sc->index_tag = rman_get_bustag(sc->index_res); 406 sc->index_handle = rman_get_bushandle(sc->index_res); 407 sc->data_tag = rman_get_bustag(sc->data_res); 408 sc->data_handle = rman_get_bushandle(sc->data_res); 409 410 return (0); 411} 412 413/* 414 * CanBe I/O resource release function 415 */ 416static void 417release_ioresource(device_t dev) 418{ 419 struct canbus_softc *sc = device_get_softc(dev); 420 421 bus_release_resource(dev, SYS_RES_IOPORT, sc->index_id, sc->index_res); 422 bus_release_resource(dev, SYS_RES_IOPORT, sc->data_id, sc->data_res); 423} 424 425 426static int 427print_all_resources(device_t dev) 428{ 429 struct canbus_device *cbdev = 430 (struct canbus_device *)device_get_ivars(dev); 431 struct resource_list *rl = &cbdev->cbdev_resources; 432 int retval = 0; 433 434 if (SLIST_FIRST(rl)) 435 retval += printf(" at"); 436 437 retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); 438 retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx"); 439 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 440 441 return retval; 442} 443