1*86f4a437SRobert Watson /*- 2*86f4a437SRobert Watson * Copyright (c) 2012 Robert N. M. Watson 3*86f4a437SRobert Watson * All rights reserved. 4*86f4a437SRobert Watson * 5*86f4a437SRobert Watson * This software was developed by SRI International and the University of 6*86f4a437SRobert Watson * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7*86f4a437SRobert Watson * ("CTSRD"), as part of the DARPA CRASH research programme. 8*86f4a437SRobert Watson * 9*86f4a437SRobert Watson * Redistribution and use in source and binary forms, with or without 10*86f4a437SRobert Watson * modification, are permitted provided that the following conditions 11*86f4a437SRobert Watson * are met: 12*86f4a437SRobert Watson * 1. Redistributions of source code must retain the above copyright 13*86f4a437SRobert Watson * notice, this list of conditions and the following disclaimer. 14*86f4a437SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 15*86f4a437SRobert Watson * notice, this list of conditions and the following disclaimer in the 16*86f4a437SRobert Watson * documentation and/or other materials provided with the distribution. 17*86f4a437SRobert Watson * 18*86f4a437SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19*86f4a437SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*86f4a437SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*86f4a437SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22*86f4a437SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*86f4a437SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*86f4a437SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*86f4a437SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*86f4a437SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*86f4a437SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*86f4a437SRobert Watson * SUCH DAMAGE. 29*86f4a437SRobert Watson */ 30*86f4a437SRobert Watson 31*86f4a437SRobert Watson #include <sys/cdefs.h> 32*86f4a437SRobert Watson __FBSDID("$FreeBSD$"); 33*86f4a437SRobert Watson 34*86f4a437SRobert Watson #include <sys/param.h> 35*86f4a437SRobert Watson #include <sys/bus.h> 36*86f4a437SRobert Watson #include <sys/condvar.h> 37*86f4a437SRobert Watson #include <sys/conf.h> 38*86f4a437SRobert Watson #include <sys/kernel.h> 39*86f4a437SRobert Watson #include <sys/lock.h> 40*86f4a437SRobert Watson #include <sys/malloc.h> 41*86f4a437SRobert Watson #include <sys/module.h> 42*86f4a437SRobert Watson #include <sys/mutex.h> 43*86f4a437SRobert Watson #include <sys/rman.h> 44*86f4a437SRobert Watson #include <sys/stat.h> 45*86f4a437SRobert Watson #include <sys/systm.h> 46*86f4a437SRobert Watson #include <sys/uio.h> 47*86f4a437SRobert Watson 48*86f4a437SRobert Watson #include <machine/bus.h> 49*86f4a437SRobert Watson #include <machine/resource.h> 50*86f4a437SRobert Watson #include <machine/vm.h> 51*86f4a437SRobert Watson 52*86f4a437SRobert Watson #include <vm/vm.h> 53*86f4a437SRobert Watson 54*86f4a437SRobert Watson #include <dev/altera/avgen/altera_avgen.h> 55*86f4a437SRobert Watson 56*86f4a437SRobert Watson /* 57*86f4a437SRobert Watson * Generic device driver for allowing read(), write(), and mmap() on 58*86f4a437SRobert Watson * memory-mapped, Avalon-attached devices. There is no actual dependence on 59*86f4a437SRobert Watson * Avalon, so conceivably this should just be soc_dev or similar, since many 60*86f4a437SRobert Watson * system-on-chip bus environments would work fine with the same code. 61*86f4a437SRobert Watson */ 62*86f4a437SRobert Watson 63*86f4a437SRobert Watson static d_mmap_t altera_avgen_mmap; 64*86f4a437SRobert Watson static d_read_t altera_avgen_read; 65*86f4a437SRobert Watson static d_write_t altera_avgen_write; 66*86f4a437SRobert Watson 67*86f4a437SRobert Watson static struct cdevsw avg_cdevsw = { 68*86f4a437SRobert Watson .d_version = D_VERSION, 69*86f4a437SRobert Watson .d_mmap = altera_avgen_mmap, 70*86f4a437SRobert Watson .d_read = altera_avgen_read, 71*86f4a437SRobert Watson .d_write = altera_avgen_write, 72*86f4a437SRobert Watson .d_name = "altera_avgen", 73*86f4a437SRobert Watson }; 74*86f4a437SRobert Watson 75*86f4a437SRobert Watson static int 76*86f4a437SRobert Watson altera_avgen_read(struct cdev *dev, struct uio *uio, int flag) 77*86f4a437SRobert Watson { 78*86f4a437SRobert Watson struct altera_avgen_softc *sc; 79*86f4a437SRobert Watson u_long offset, size; 80*86f4a437SRobert Watson #ifdef NOTYET 81*86f4a437SRobert Watson uint64_t v8; 82*86f4a437SRobert Watson #endif 83*86f4a437SRobert Watson uint32_t v4; 84*86f4a437SRobert Watson uint16_t v2; 85*86f4a437SRobert Watson uint8_t v1; 86*86f4a437SRobert Watson u_int width; 87*86f4a437SRobert Watson int error; 88*86f4a437SRobert Watson 89*86f4a437SRobert Watson sc = dev->si_drv1; 90*86f4a437SRobert Watson if ((sc->avg_flags & ALTERA_AVALON_FLAG_READ) == 0) 91*86f4a437SRobert Watson return (EACCES); 92*86f4a437SRobert Watson width = sc->avg_width; 93*86f4a437SRobert Watson if (uio->uio_offset < 0 || uio->uio_offset % width != 0 || 94*86f4a437SRobert Watson uio->uio_resid % width != 0) 95*86f4a437SRobert Watson return (ENODEV); 96*86f4a437SRobert Watson size = rman_get_size(sc->avg_res); 97*86f4a437SRobert Watson if ((uio->uio_offset + uio->uio_resid < 0) || 98*86f4a437SRobert Watson (uio->uio_offset + uio->uio_resid > size)) 99*86f4a437SRobert Watson return (ENODEV); 100*86f4a437SRobert Watson while (uio->uio_resid > 0) { 101*86f4a437SRobert Watson offset = uio->uio_offset; 102*86f4a437SRobert Watson if (offset + width > size) 103*86f4a437SRobert Watson return (ENODEV); 104*86f4a437SRobert Watson switch (width) { 105*86f4a437SRobert Watson case 1: 106*86f4a437SRobert Watson v1 = bus_read_1(sc->avg_res, offset); 107*86f4a437SRobert Watson error = uiomove(&v1, sizeof(v1), uio); 108*86f4a437SRobert Watson break; 109*86f4a437SRobert Watson 110*86f4a437SRobert Watson case 2: 111*86f4a437SRobert Watson v2 = bus_read_2(sc->avg_res, offset); 112*86f4a437SRobert Watson error = uiomove(&v2, sizeof(v2), uio); 113*86f4a437SRobert Watson break; 114*86f4a437SRobert Watson 115*86f4a437SRobert Watson case 4: 116*86f4a437SRobert Watson v4 = bus_read_4(sc->avg_res, offset); 117*86f4a437SRobert Watson error = uiomove(&v4, sizeof(v4), uio); 118*86f4a437SRobert Watson break; 119*86f4a437SRobert Watson 120*86f4a437SRobert Watson #ifdef NOTYET 121*86f4a437SRobert Watson case 8: 122*86f4a437SRobert Watson v8 = bus_read_8(sc->avg_res, offset); 123*86f4a437SRobert Watson error = uiomove(&v8, sizeof(v8), uio); 124*86f4a437SRobert Watson break; 125*86f4a437SRobert Watson 126*86f4a437SRobert Watson #endif 127*86f4a437SRobert Watson 128*86f4a437SRobert Watson default: 129*86f4a437SRobert Watson panic("%s: unexpected widthment %u", __func__, width); 130*86f4a437SRobert Watson } 131*86f4a437SRobert Watson if (error) 132*86f4a437SRobert Watson return (error); 133*86f4a437SRobert Watson } 134*86f4a437SRobert Watson return (0); 135*86f4a437SRobert Watson } 136*86f4a437SRobert Watson 137*86f4a437SRobert Watson static int 138*86f4a437SRobert Watson altera_avgen_write(struct cdev *dev, struct uio *uio, int flag) 139*86f4a437SRobert Watson { 140*86f4a437SRobert Watson struct altera_avgen_softc *sc; 141*86f4a437SRobert Watson u_long offset, size; 142*86f4a437SRobert Watson #ifdef NOTYET 143*86f4a437SRobert Watson uint64_t v8; 144*86f4a437SRobert Watson #endif 145*86f4a437SRobert Watson uint32_t v4; 146*86f4a437SRobert Watson uint16_t v2; 147*86f4a437SRobert Watson uint8_t v1; 148*86f4a437SRobert Watson u_int width; 149*86f4a437SRobert Watson int error; 150*86f4a437SRobert Watson 151*86f4a437SRobert Watson sc = dev->si_drv1; 152*86f4a437SRobert Watson if ((sc->avg_flags & ALTERA_AVALON_FLAG_WRITE) == 0) 153*86f4a437SRobert Watson return (EACCES); 154*86f4a437SRobert Watson width = sc->avg_width; 155*86f4a437SRobert Watson if (uio->uio_offset < 0 || uio->uio_offset % width != 0 || 156*86f4a437SRobert Watson uio->uio_resid % width != 0) 157*86f4a437SRobert Watson return (ENODEV); 158*86f4a437SRobert Watson size = rman_get_size(sc->avg_res); 159*86f4a437SRobert Watson while (uio->uio_resid > 0) { 160*86f4a437SRobert Watson offset = uio->uio_offset; 161*86f4a437SRobert Watson if (offset + width > size) 162*86f4a437SRobert Watson return (ENODEV); 163*86f4a437SRobert Watson switch (width) { 164*86f4a437SRobert Watson case 1: 165*86f4a437SRobert Watson error = uiomove(&v1, sizeof(v1), uio); 166*86f4a437SRobert Watson if (error) 167*86f4a437SRobert Watson return (error); 168*86f4a437SRobert Watson bus_write_1(sc->avg_res, offset, v1); 169*86f4a437SRobert Watson break; 170*86f4a437SRobert Watson 171*86f4a437SRobert Watson case 2: 172*86f4a437SRobert Watson error = uiomove(&v2, sizeof(v2), uio); 173*86f4a437SRobert Watson if (error) 174*86f4a437SRobert Watson return (error); 175*86f4a437SRobert Watson bus_write_2(sc->avg_res, offset, v2); 176*86f4a437SRobert Watson break; 177*86f4a437SRobert Watson 178*86f4a437SRobert Watson case 4: 179*86f4a437SRobert Watson error = uiomove(&v4, sizeof(v4), uio); 180*86f4a437SRobert Watson if (error) 181*86f4a437SRobert Watson return (error); 182*86f4a437SRobert Watson bus_write_4(sc->avg_res, offset, v4); 183*86f4a437SRobert Watson break; 184*86f4a437SRobert Watson 185*86f4a437SRobert Watson #ifdef NOTYET 186*86f4a437SRobert Watson case 8: 187*86f4a437SRobert Watson error = uiomove(&v8, sizeof(v8), uio); 188*86f4a437SRobert Watson if (error) 189*86f4a437SRobert Watson return (error); 190*86f4a437SRobert Watson bus_write_8(sc->avg_res, offset, v8); 191*86f4a437SRobert Watson break; 192*86f4a437SRobert Watson #endif 193*86f4a437SRobert Watson 194*86f4a437SRobert Watson default: 195*86f4a437SRobert Watson panic("%s: unexpected width %u", __func__, width); 196*86f4a437SRobert Watson } 197*86f4a437SRobert Watson } 198*86f4a437SRobert Watson return (0); 199*86f4a437SRobert Watson } 200*86f4a437SRobert Watson 201*86f4a437SRobert Watson static int 202*86f4a437SRobert Watson altera_avgen_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 203*86f4a437SRobert Watson int nprot, vm_memattr_t *memattr) 204*86f4a437SRobert Watson { 205*86f4a437SRobert Watson struct altera_avgen_softc *sc; 206*86f4a437SRobert Watson 207*86f4a437SRobert Watson sc = dev->si_drv1; 208*86f4a437SRobert Watson if (nprot & VM_PROT_READ) { 209*86f4a437SRobert Watson if ((sc->avg_flags & ALTERA_AVALON_FLAG_MMAP_READ) == 0) 210*86f4a437SRobert Watson return (EACCES); 211*86f4a437SRobert Watson } 212*86f4a437SRobert Watson if (nprot & VM_PROT_WRITE) { 213*86f4a437SRobert Watson if ((sc->avg_flags & ALTERA_AVALON_FLAG_MMAP_WRITE) == 0) 214*86f4a437SRobert Watson return (EACCES); 215*86f4a437SRobert Watson } 216*86f4a437SRobert Watson if (nprot & VM_PROT_EXECUTE) { 217*86f4a437SRobert Watson if ((sc->avg_flags & ALTERA_AVALON_FLAG_MMAP_EXEC) == 0) 218*86f4a437SRobert Watson return (EACCES); 219*86f4a437SRobert Watson } 220*86f4a437SRobert Watson if (trunc_page(offset) == offset && 221*86f4a437SRobert Watson rman_get_size(sc->avg_res) >= offset + PAGE_SIZE) { 222*86f4a437SRobert Watson *paddr = rman_get_start(sc->avg_res) + offset; 223*86f4a437SRobert Watson *memattr = VM_MEMATTR_UNCACHEABLE; 224*86f4a437SRobert Watson } else 225*86f4a437SRobert Watson return (ENODEV); 226*86f4a437SRobert Watson return (0); 227*86f4a437SRobert Watson } 228*86f4a437SRobert Watson 229*86f4a437SRobert Watson static int 230*86f4a437SRobert Watson altera_avgen_nexus_probe(device_t dev) 231*86f4a437SRobert Watson { 232*86f4a437SRobert Watson 233*86f4a437SRobert Watson device_set_desc(dev, "Generic Altera Avalon device attachment"); 234*86f4a437SRobert Watson return (BUS_PROBE_DEFAULT); 235*86f4a437SRobert Watson } 236*86f4a437SRobert Watson 237*86f4a437SRobert Watson static int 238*86f4a437SRobert Watson altera_avgen_process_options(struct altera_avgen_softc *sc, 239*86f4a437SRobert Watson const char *str_fileio, const char *str_mmapio, const char *str_devname, 240*86f4a437SRobert Watson int devunit) 241*86f4a437SRobert Watson { 242*86f4a437SRobert Watson const char *cp; 243*86f4a437SRobert Watson device_t dev = sc->avg_dev; 244*86f4a437SRobert Watson 245*86f4a437SRobert Watson /* 246*86f4a437SRobert Watson * Check for valid combinations of options. 247*86f4a437SRobert Watson */ 248*86f4a437SRobert Watson if (str_fileio == NULL && str_mmapio == NULL) { 249*86f4a437SRobert Watson device_printf(dev, 250*86f4a437SRobert Watson "at least one of %s or %s must be specified\n", 251*86f4a437SRobert Watson ALTERA_AVALON_STR_FILEIO, ALTERA_AVALON_STR_MMAPIO); 252*86f4a437SRobert Watson return (ENXIO); 253*86f4a437SRobert Watson } 254*86f4a437SRobert Watson if (str_devname == NULL && devunit != -1) { 255*86f4a437SRobert Watson device_printf(dev, "%s requires %s be specified\n", 256*86f4a437SRobert Watson ALTERA_AVALON_STR_DEVUNIT, ALTERA_AVALON_STR_DEVNAME); 257*86f4a437SRobert Watson return (ENXIO); 258*86f4a437SRobert Watson } 259*86f4a437SRobert Watson 260*86f4a437SRobert Watson /* 261*86f4a437SRobert Watson * Extract, digest, and save values. 262*86f4a437SRobert Watson */ 263*86f4a437SRobert Watson switch (sc->avg_width) { 264*86f4a437SRobert Watson case 1: 265*86f4a437SRobert Watson case 2: 266*86f4a437SRobert Watson case 4: 267*86f4a437SRobert Watson #ifdef NOTYET 268*86f4a437SRobert Watson case 8: 269*86f4a437SRobert Watson #endif 270*86f4a437SRobert Watson break; 271*86f4a437SRobert Watson 272*86f4a437SRobert Watson default: 273*86f4a437SRobert Watson device_printf(dev, "%s unsupported value %u\n", 274*86f4a437SRobert Watson ALTERA_AVALON_STR_WIDTH, sc->avg_width); 275*86f4a437SRobert Watson return (ENXIO); 276*86f4a437SRobert Watson } 277*86f4a437SRobert Watson sc->avg_flags = 0; 278*86f4a437SRobert Watson if (str_fileio != NULL) { 279*86f4a437SRobert Watson for (cp = str_fileio; *cp != '\0'; cp++) { 280*86f4a437SRobert Watson switch (*cp) { 281*86f4a437SRobert Watson case ALTERA_AVALON_CHAR_READ: 282*86f4a437SRobert Watson sc->avg_flags |= ALTERA_AVALON_FLAG_READ; 283*86f4a437SRobert Watson break; 284*86f4a437SRobert Watson 285*86f4a437SRobert Watson case ALTERA_AVALON_CHAR_WRITE: 286*86f4a437SRobert Watson sc->avg_flags |= ALTERA_AVALON_FLAG_WRITE; 287*86f4a437SRobert Watson break; 288*86f4a437SRobert Watson 289*86f4a437SRobert Watson default: 290*86f4a437SRobert Watson device_printf(dev, 291*86f4a437SRobert Watson "invalid %s character %c\n", 292*86f4a437SRobert Watson ALTERA_AVALON_STR_FILEIO, *cp); 293*86f4a437SRobert Watson return (ENXIO); 294*86f4a437SRobert Watson } 295*86f4a437SRobert Watson } 296*86f4a437SRobert Watson } 297*86f4a437SRobert Watson if (str_mmapio != NULL) { 298*86f4a437SRobert Watson for (cp = str_mmapio; *cp != '\0'; cp++) { 299*86f4a437SRobert Watson switch (*cp) { 300*86f4a437SRobert Watson case ALTERA_AVALON_CHAR_READ: 301*86f4a437SRobert Watson sc->avg_flags |= ALTERA_AVALON_FLAG_MMAP_READ; 302*86f4a437SRobert Watson break; 303*86f4a437SRobert Watson 304*86f4a437SRobert Watson case ALTERA_AVALON_CHAR_WRITE: 305*86f4a437SRobert Watson sc->avg_flags |= 306*86f4a437SRobert Watson ALTERA_AVALON_FLAG_MMAP_WRITE; 307*86f4a437SRobert Watson break; 308*86f4a437SRobert Watson 309*86f4a437SRobert Watson case ALTERA_AVALON_CHAR_EXEC: 310*86f4a437SRobert Watson sc->avg_flags |= ALTERA_AVALON_FLAG_MMAP_EXEC; 311*86f4a437SRobert Watson break; 312*86f4a437SRobert Watson 313*86f4a437SRobert Watson default: 314*86f4a437SRobert Watson device_printf(dev, 315*86f4a437SRobert Watson "invalid %s character %c\n", 316*86f4a437SRobert Watson ALTERA_AVALON_STR_MMAPIO, *cp); 317*86f4a437SRobert Watson return (ENXIO); 318*86f4a437SRobert Watson } 319*86f4a437SRobert Watson } 320*86f4a437SRobert Watson } 321*86f4a437SRobert Watson return (0); 322*86f4a437SRobert Watson } 323*86f4a437SRobert Watson 324*86f4a437SRobert Watson static int 325*86f4a437SRobert Watson altera_avgen_nexus_attach(device_t dev) 326*86f4a437SRobert Watson { 327*86f4a437SRobert Watson struct altera_avgen_softc *sc; 328*86f4a437SRobert Watson const char *str_fileio, *str_mmapio; 329*86f4a437SRobert Watson const char *str_devname; 330*86f4a437SRobert Watson char devname[SPECNAMELEN + 1]; 331*86f4a437SRobert Watson int devunit, error; 332*86f4a437SRobert Watson 333*86f4a437SRobert Watson sc = device_get_softc(dev); 334*86f4a437SRobert Watson sc->avg_dev = dev; 335*86f4a437SRobert Watson sc->avg_unit = device_get_unit(dev); 336*86f4a437SRobert Watson 337*86f4a437SRobert Watson /* 338*86f4a437SRobert Watson * Query non-standard hints to find out what operations are permitted 339*86f4a437SRobert Watson * on the device, and whether it is cached. 340*86f4a437SRobert Watson */ 341*86f4a437SRobert Watson str_fileio = NULL; 342*86f4a437SRobert Watson str_mmapio = NULL; 343*86f4a437SRobert Watson str_devname = NULL; 344*86f4a437SRobert Watson devunit = -1; 345*86f4a437SRobert Watson sc->avg_width = 1; 346*86f4a437SRobert Watson error = resource_int_value(device_get_name(dev), device_get_unit(dev), 347*86f4a437SRobert Watson ALTERA_AVALON_STR_WIDTH, &sc->avg_width); 348*86f4a437SRobert Watson if (error != 0 && error != ENOENT) { 349*86f4a437SRobert Watson device_printf(dev, "invalid %s\n", ALTERA_AVALON_STR_WIDTH); 350*86f4a437SRobert Watson return (error); 351*86f4a437SRobert Watson } 352*86f4a437SRobert Watson (void)resource_string_value(device_get_name(dev), 353*86f4a437SRobert Watson device_get_unit(dev), ALTERA_AVALON_STR_FILEIO, &str_fileio); 354*86f4a437SRobert Watson (void)resource_string_value(device_get_name(dev), 355*86f4a437SRobert Watson device_get_unit(dev), ALTERA_AVALON_STR_MMAPIO, &str_mmapio); 356*86f4a437SRobert Watson (void)resource_string_value(device_get_name(dev), 357*86f4a437SRobert Watson device_get_unit(dev), ALTERA_AVALON_STR_DEVNAME, &str_devname); 358*86f4a437SRobert Watson (void)resource_int_value(device_get_name(dev), device_get_unit(dev), 359*86f4a437SRobert Watson ALTERA_AVALON_STR_DEVUNIT, &devunit); 360*86f4a437SRobert Watson error = altera_avgen_process_options(sc, str_fileio, str_mmapio, 361*86f4a437SRobert Watson str_devname, devunit); 362*86f4a437SRobert Watson if (error) 363*86f4a437SRobert Watson return (error); 364*86f4a437SRobert Watson 365*86f4a437SRobert Watson /* Select a device name. */ 366*86f4a437SRobert Watson if (str_devname != NULL) { 367*86f4a437SRobert Watson if (devunit != -1) 368*86f4a437SRobert Watson (void)snprintf(devname, sizeof(devname), "%s%d", 369*86f4a437SRobert Watson str_devname, devunit); 370*86f4a437SRobert Watson else 371*86f4a437SRobert Watson (void)snprintf(devname, sizeof(devname), "%s", 372*86f4a437SRobert Watson str_devname); 373*86f4a437SRobert Watson } else 374*86f4a437SRobert Watson snprintf(devname, sizeof(devname), "%s%d", "avgen", 375*86f4a437SRobert Watson sc->avg_unit); 376*86f4a437SRobert Watson 377*86f4a437SRobert Watson /* Memory allocation and checking. */ 378*86f4a437SRobert Watson sc->avg_rid = 0; 379*86f4a437SRobert Watson sc->avg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 380*86f4a437SRobert Watson &sc->avg_rid, RF_ACTIVE); 381*86f4a437SRobert Watson if (sc->avg_res == NULL) { 382*86f4a437SRobert Watson device_printf(dev, "couldn't map memory\n"); 383*86f4a437SRobert Watson return (ENXIO); 384*86f4a437SRobert Watson } 385*86f4a437SRobert Watson if (rman_get_size(sc->avg_res) >= PAGE_SIZE || str_mmapio != NULL) { 386*86f4a437SRobert Watson if (rman_get_size(sc->avg_res) % PAGE_SIZE != 0) { 387*86f4a437SRobert Watson device_printf(dev, 388*86f4a437SRobert Watson "memory region not even multiple of page size\n"); 389*86f4a437SRobert Watson error = ENXIO; 390*86f4a437SRobert Watson goto error; 391*86f4a437SRobert Watson } 392*86f4a437SRobert Watson if (rman_get_start(sc->avg_res) % PAGE_SIZE != 0) { 393*86f4a437SRobert Watson device_printf(dev, "memory region not page-aligned\n"); 394*86f4a437SRobert Watson error = ENXIO; 395*86f4a437SRobert Watson goto error; 396*86f4a437SRobert Watson } 397*86f4a437SRobert Watson } 398*86f4a437SRobert Watson 399*86f4a437SRobert Watson /* Device node allocation. */ 400*86f4a437SRobert Watson if (str_devname == NULL) { 401*86f4a437SRobert Watson str_devname = "altera_avgen%d"; 402*86f4a437SRobert Watson devunit = sc->avg_unit; 403*86f4a437SRobert Watson } 404*86f4a437SRobert Watson if (devunit != -1) 405*86f4a437SRobert Watson sc->avg_cdev = make_dev(&avg_cdevsw, sc->avg_unit, UID_ROOT, 406*86f4a437SRobert Watson GID_WHEEL, S_IRUSR | S_IWUSR, str_devname, devunit); 407*86f4a437SRobert Watson else 408*86f4a437SRobert Watson sc->avg_cdev = make_dev(&avg_cdevsw, sc->avg_unit, UID_ROOT, 409*86f4a437SRobert Watson GID_WHEEL, S_IRUSR | S_IWUSR, str_devname); 410*86f4a437SRobert Watson if (sc->avg_cdev == NULL) { 411*86f4a437SRobert Watson device_printf(sc->avg_dev, "%s: make_dev failed\n", __func__); 412*86f4a437SRobert Watson error = ENXIO; 413*86f4a437SRobert Watson goto error; 414*86f4a437SRobert Watson } 415*86f4a437SRobert Watson /* XXXRW: Slight race between make_dev(9) and here. */ 416*86f4a437SRobert Watson sc->avg_cdev->si_drv1 = sc; 417*86f4a437SRobert Watson return (0); 418*86f4a437SRobert Watson 419*86f4a437SRobert Watson error: 420*86f4a437SRobert Watson bus_release_resource(dev, SYS_RES_MEMORY, sc->avg_rid, sc->avg_res); 421*86f4a437SRobert Watson return (error); 422*86f4a437SRobert Watson } 423*86f4a437SRobert Watson 424*86f4a437SRobert Watson static int 425*86f4a437SRobert Watson altera_avgen_nexus_detach(device_t dev) 426*86f4a437SRobert Watson { 427*86f4a437SRobert Watson struct altera_avgen_softc *sc; 428*86f4a437SRobert Watson 429*86f4a437SRobert Watson sc = device_get_softc(dev); 430*86f4a437SRobert Watson destroy_dev(sc->avg_cdev); 431*86f4a437SRobert Watson bus_release_resource(dev, SYS_RES_MEMORY, sc->avg_rid, sc->avg_res); 432*86f4a437SRobert Watson return (0); 433*86f4a437SRobert Watson } 434*86f4a437SRobert Watson 435*86f4a437SRobert Watson static device_method_t altera_avgen_nexus_methods[] = { 436*86f4a437SRobert Watson DEVMETHOD(device_probe, altera_avgen_nexus_probe), 437*86f4a437SRobert Watson DEVMETHOD(device_attach, altera_avgen_nexus_attach), 438*86f4a437SRobert Watson DEVMETHOD(device_detach, altera_avgen_nexus_detach), 439*86f4a437SRobert Watson { 0, 0 } 440*86f4a437SRobert Watson }; 441*86f4a437SRobert Watson 442*86f4a437SRobert Watson static driver_t altera_avgen_nexus_driver = { 443*86f4a437SRobert Watson "altera_avgen", 444*86f4a437SRobert Watson altera_avgen_nexus_methods, 445*86f4a437SRobert Watson sizeof(struct altera_avgen_softc), 446*86f4a437SRobert Watson }; 447*86f4a437SRobert Watson 448*86f4a437SRobert Watson static devclass_t altera_avgen_devclass; 449*86f4a437SRobert Watson 450*86f4a437SRobert Watson DRIVER_MODULE(avgen, nexus, altera_avgen_nexus_driver, altera_avgen_devclass, 451*86f4a437SRobert Watson 0, 0); 452