The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/altera/avgen/altera_avgen.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: eacbee1c1a42126610d6f524937b2d51


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.