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