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/fb/fbd.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) 2013 The FreeBSD Foundation
    3  * All rights reserved.
    4  *
    5  * This software was developed by Aleksandr Rybalko under sponsorship from the
    6  * FreeBSD Foundation.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  * $FreeBSD$
   30  */
   31 
   32 /* Generic framebuffer */
   33 /* TODO unlink from VT(9) */
   34 /* TODO done normal /dev/fb methods */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/bus.h>
   42 #include <sys/conf.h>
   43 #include <sys/kernel.h>
   44 #include <sys/malloc.h>
   45 #include <sys/module.h>
   46 #include <sys/queue.h>
   47 #include <sys/fbio.h>
   48 
   49 #include <machine/bus.h>
   50 
   51 #include <dev/vt/vt.h>
   52 #include <dev/vt/hw/fb/vt_fb.h>
   53 
   54 #include "fb_if.h"
   55 
   56 LIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head =
   57     LIST_HEAD_INITIALIZER(fb_list_head);
   58 struct fb_list_entry {
   59         struct fb_info  *fb_info;
   60         struct cdev     *fb_si;
   61         LIST_ENTRY(fb_list_entry) fb_list;
   62 };
   63 
   64 struct fbd_softc {
   65         device_t        sc_dev;
   66         struct fb_info  *sc_info;
   67 };
   68 
   69 static void fbd_evh_init(void *);
   70 /* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */
   71 SYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL);
   72 
   73 static d_open_t         fb_open;
   74 static d_close_t        fb_close;
   75 static d_read_t         fb_read;
   76 static d_write_t        fb_write;
   77 static d_ioctl_t        fb_ioctl;
   78 static d_mmap_t         fb_mmap;
   79 
   80 static struct cdevsw fb_cdevsw = {
   81         .d_version =    D_VERSION,
   82         .d_flags =      D_NEEDGIANT,
   83         .d_open =       fb_open,
   84         .d_close =      fb_close,
   85         .d_read =       fb_read,
   86         .d_write =      fb_write,
   87         .d_ioctl =      fb_ioctl,
   88         .d_mmap =       fb_mmap,
   89         .d_name =       "fb",
   90 };
   91 
   92 static int framebuffer_dev_unit = 0;
   93 
   94 static int
   95 fb_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
   96 {
   97 
   98         return (0);
   99 }
  100 
  101 static int
  102 fb_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
  103 {
  104 
  105         return (0);
  106 }
  107 
  108 static int
  109 fb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
  110     struct thread *td)
  111 {
  112         struct fb_info *info;
  113         int error;
  114 
  115         error = 0;
  116         info = dev->si_drv1;
  117 
  118         switch (cmd) {
  119         case FBIOGTYPE:
  120                 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
  121                 break;
  122 
  123         case FBIO_GETWINORG:    /* get frame buffer window origin */
  124                 *(u_int *)data = 0;
  125                 break;
  126 
  127         case FBIO_GETDISPSTART: /* get display start address */
  128                 ((video_display_start_t *)data)->x = 0;
  129                 ((video_display_start_t *)data)->y = 0;
  130                 break;
  131 
  132         case FBIO_GETLINEWIDTH: /* get scan line width in bytes */
  133                 *(u_int *)data = info->fb_stride;
  134                 break;
  135 
  136         case FBIO_BLANK:        /* blank display */
  137                 error = 0;      /* TODO */
  138                 break;
  139 
  140         default:
  141                 error = ENOIOCTL;
  142                 break;
  143         }
  144         return (error);
  145 }
  146 
  147 static int
  148 fb_read(struct cdev *dev, struct uio *uio, int ioflag)
  149 {
  150 
  151         return (0); /* XXX nothing to read, yet */
  152 }
  153 
  154 static int
  155 fb_write(struct cdev *dev, struct uio *uio, int ioflag)
  156 {
  157 
  158         return (0); /* XXX nothing written */
  159 }
  160 
  161 static int
  162 fb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
  163     vm_memattr_t *memattr)
  164 {
  165         struct fb_info *info;
  166 
  167         info = dev->si_drv1;
  168         if (offset < info->fb_size) {
  169                 *paddr = info->fb_pbase + offset;
  170                 return (0);
  171         }
  172         return (EINVAL);
  173 }
  174 
  175 
  176 static void
  177 vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v)
  178 {
  179 
  180         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
  181         *(uint8_t *)(sc->fb_vbase + o) = v;
  182 }
  183 
  184 static void
  185 vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v)
  186 {
  187 
  188         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
  189         *(uint16_t *)(sc->fb_vbase + o) = v;
  190 }
  191 
  192 static void
  193 vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v)
  194 {
  195 
  196         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
  197         *(uint32_t *)(sc->fb_vbase + o) = v;
  198 }
  199 
  200 static void
  201 vt_fb_mem_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from,
  202     uint32_t size)
  203 {
  204 
  205         memmove((void *)(sc->fb_vbase + offset_to), (void *)(sc->fb_vbase +
  206             offset_from), size);
  207 }
  208 
  209 static void
  210 vt_fb_indir_wr1(struct fb_info *sc, uint32_t o, uint8_t v)
  211 {
  212 
  213         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
  214         sc->fb_write(sc->fb_priv, o, &v, 1);
  215 }
  216 
  217 static void
  218 vt_fb_indir_wr2(struct fb_info *sc, uint32_t o, uint16_t v)
  219 {
  220 
  221         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
  222         sc->fb_write(sc->fb_priv, o, &v, 2);
  223 }
  224 
  225 static void
  226 vt_fb_indir_wr4(struct fb_info *sc, uint32_t o, uint32_t v)
  227 {
  228 
  229         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
  230         sc->fb_write(sc->fb_priv, o, &v, 4);
  231 }
  232 
  233 static void
  234 vt_fb_indir_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from,
  235     uint32_t size)
  236 {
  237 
  238         sc->copy(sc->fb_priv, offset_to, offset_from, size);
  239 }
  240 
  241 int
  242 fb_probe(struct fb_info *info)
  243 {
  244 
  245         if (info->fb_size == 0)
  246                 return (ENXIO);
  247 
  248         if (info->fb_write != NULL) {
  249                 if (info->fb_write == NULL) {
  250                         return (EINVAL);
  251                 }
  252                 info->fb_flags |= FB_FLAG_NOMMAP;
  253                 info->wr1 = &vt_fb_indir_wr1;
  254                 info->wr2 = &vt_fb_indir_wr2;
  255                 info->wr4 = &vt_fb_indir_wr4;
  256                 info->copy = &vt_fb_indir_copy;
  257         } else if (info->fb_vbase != 0) {
  258                 if (info->fb_pbase == 0) {
  259                         info->fb_flags |= FB_FLAG_NOMMAP;
  260                 } else {
  261                         if (info->fb_mmap == NULL)
  262                                 info->fb_mmap = &fb_mmap;
  263                 }
  264                 info->wr1 = &vt_fb_mem_wr1;
  265                 info->wr2 = &vt_fb_mem_wr2;
  266                 info->wr4 = &vt_fb_mem_wr4;
  267                 info->copy = &vt_fb_mem_copy;
  268         } else
  269                 return (ENXIO);
  270 
  271         if (info->fb_ioctl == NULL)
  272                 info->fb_ioctl = &fb_ioctl;
  273 
  274 
  275         return (0);
  276 }
  277 
  278 
  279 static int
  280 fb_init(struct fb_list_entry *entry, int unit)
  281 {
  282         struct fb_info *info;
  283 
  284         info = entry->fb_info;
  285         entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL,
  286             0600, "fb%d", unit);
  287         entry->fb_si->si_drv1 = info;
  288         info->fb_cdev = entry->fb_si;
  289 
  290         return (0);
  291 }
  292 
  293 int
  294 fbd_list()
  295 {
  296         struct fb_list_entry *entry;
  297 
  298         if (LIST_EMPTY(&fb_list_head))
  299                 return (ENOENT);
  300 
  301         LIST_FOREACH(entry, &fb_list_head, fb_list) {
  302                 printf("FB %s @%p\n", entry->fb_info->fb_name,
  303                     (void *)entry->fb_info->fb_pbase);
  304         }
  305 
  306         return (0);
  307 }
  308 
  309 static struct fb_list_entry *
  310 fbd_find(struct fb_info* info)
  311 {
  312         struct fb_list_entry *entry, *tmp;
  313 
  314         LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
  315                 if (entry->fb_info == info) {
  316                         return (entry);
  317                 }
  318         }
  319 
  320         return (NULL);
  321 }
  322 
  323 int
  324 fbd_register(struct fb_info* info)
  325 {
  326         struct fb_list_entry *entry;
  327         int err, first;
  328 
  329         first = 0;
  330         if (LIST_EMPTY(&fb_list_head))
  331                 first++;
  332 
  333         entry = fbd_find(info);
  334         if (entry != NULL) {
  335                 /* XXX Update framebuffer params */
  336                 return (0);
  337         }
  338 
  339         err = fb_probe(info);
  340         if (err)
  341                 return (err);
  342 
  343         entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO);
  344         entry->fb_info = info;
  345 
  346         LIST_INSERT_HEAD(&fb_list_head, entry, fb_list);
  347 
  348         err = fb_init(entry, framebuffer_dev_unit++);
  349         if (err)
  350                 return (err);
  351 
  352         if (first)
  353                 vt_fb_attach(info);
  354 
  355         return (0);
  356 }
  357 
  358 int
  359 fbd_unregister(struct fb_info* info)
  360 {
  361         struct fb_list_entry *entry, *tmp;
  362 
  363         LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
  364                 if (entry->fb_info == info) {
  365                         LIST_REMOVE(entry, fb_list);
  366                         free(entry, M_DEVBUF);
  367                         return (0);
  368                 }
  369         }
  370 
  371         return (ENOENT);
  372 }
  373 
  374 static void
  375 register_fb_wrap(void *arg, void *ptr)
  376 {
  377 
  378         fbd_register((struct fb_info *)ptr);
  379 }
  380 
  381 static void
  382 unregister_fb_wrap(void *arg, void *ptr)
  383 {
  384 
  385         fbd_unregister((struct fb_info *)ptr);
  386 }
  387 
  388 static void
  389 fbd_evh_init(void *ctx)
  390 {
  391 
  392         EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL,
  393             EVENTHANDLER_PRI_ANY);
  394         EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL,
  395             EVENTHANDLER_PRI_ANY);
  396 }
  397 
  398 /* Newbus methods. */
  399 static int
  400 fbd_probe(device_t dev)
  401 {
  402 
  403         return (BUS_PROBE_NOWILDCARD);
  404 }
  405 
  406 static int
  407 fbd_attach(device_t dev)
  408 {
  409         struct fbd_softc *sc;
  410         int err;
  411 
  412         sc = device_get_softc(dev);
  413 
  414         sc->sc_dev = dev;
  415         sc->sc_info = FB_GETINFO(device_get_parent(dev));
  416         if (sc->sc_info == NULL)
  417                 return (ENXIO);
  418         err = fbd_register(sc->sc_info);
  419 
  420         return (err);
  421 }
  422 
  423 static int
  424 fbd_detach(device_t dev)
  425 {
  426         struct fbd_softc *sc;
  427         int err;
  428 
  429         sc = device_get_softc(dev);
  430 
  431         err = fbd_unregister(sc->sc_info);
  432 
  433         return (err);
  434 }
  435 
  436 static int
  437 fbd_suspend(device_t dev)
  438 {
  439 
  440         vt_fb_suspend();
  441         return (bus_generic_suspend(dev));
  442 }
  443 
  444 static int
  445 fbd_resume(device_t dev)
  446 {
  447 
  448         vt_fb_resume();
  449         return (bus_generic_resume(dev));
  450 }
  451 
  452 static device_method_t fbd_methods[] = {
  453         /* Device interface */
  454         DEVMETHOD(device_probe,         fbd_probe),
  455         DEVMETHOD(device_attach,        fbd_attach),
  456         DEVMETHOD(device_detach,        fbd_detach),
  457 
  458         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  459         DEVMETHOD(device_suspend,       fbd_suspend),
  460         DEVMETHOD(device_resume,        fbd_resume),
  461 
  462         { 0, 0 }
  463 };
  464 
  465 driver_t fbd_driver = {
  466         "fbd",
  467         fbd_methods,
  468         sizeof(struct fbd_softc)
  469 };
  470 
  471 devclass_t      fbd_devclass;
  472 
  473 DRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0);
  474 DRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0);
  475 MODULE_VERSION(fbd, 1);
  476 

Cache object: 1521c6a5083eed8dc4509a6c3f1b0702


[ 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.