1256905Sray/*- 2256905Sray * Copyright (c) 2013 The FreeBSD Foundation 3256905Sray * All rights reserved. 4256905Sray * 5256905Sray * This software was developed by Aleksandr Rybalko under sponsorship from the 6256905Sray * FreeBSD Foundation. 7256905Sray * 8256905Sray * Redistribution and use in source and binary forms, with or without 9256905Sray * modification, are permitted provided that the following conditions 10256905Sray * are met: 11256905Sray * 1. Redistributions of source code must retain the above copyright 12256905Sray * notice, this list of conditions and the following disclaimer. 13256905Sray * 2. Redistributions in binary form must reproduce the above copyright 14256905Sray * notice, this list of conditions and the following disclaimer in the 15256905Sray * documentation and/or other materials provided with the distribution. 16256905Sray * 17256905Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18256905Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19256905Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20256905Sray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21256905Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22256905Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23256905Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24256905Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25256905Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26256905Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27256905Sray * SUCH DAMAGE. 28256905Sray * 29256905Sray * $FreeBSD: stable/11/sys/dev/fb/fbd.c 307589 2016-10-19 01:35:21Z gonzo $ 30256905Sray */ 31256905Sray 32256905Sray/* Generic framebuffer */ 33256905Sray/* TODO unlink from VT(9) */ 34256905Sray/* TODO done normal /dev/fb methods */ 35256905Sray 36256905Sray#include <sys/cdefs.h> 37256905Sray__FBSDID("$FreeBSD: stable/11/sys/dev/fb/fbd.c 307589 2016-10-19 01:35:21Z gonzo $"); 38256905Sray 39256905Sray#include <sys/param.h> 40256905Sray#include <sys/systm.h> 41257438Sray#include <sys/bus.h> 42256905Sray#include <sys/conf.h> 43256905Sray#include <sys/kernel.h> 44256905Sray#include <sys/malloc.h> 45257438Sray#include <sys/module.h> 46256905Sray#include <sys/queue.h> 47256905Sray#include <sys/fbio.h> 48257438Sray 49257438Sray#include <machine/bus.h> 50257438Sray 51257727Sray#include <dev/vt/vt.h> 52256905Sray#include <dev/vt/hw/fb/vt_fb.h> 53256905Sray 54279752Shselasky#include <vm/vm.h> 55279752Shselasky#include <vm/pmap.h> 56279752Shselasky 57257438Sray#include "fb_if.h" 58257438Sray 59256905SrayLIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head = 60256905Sray LIST_HEAD_INITIALIZER(fb_list_head); 61256905Sraystruct fb_list_entry { 62256905Sray struct fb_info *fb_info; 63256905Sray struct cdev *fb_si; 64256905Sray LIST_ENTRY(fb_list_entry) fb_list; 65256905Sray}; 66256905Sray 67257438Sraystruct fbd_softc { 68257438Sray device_t sc_dev; 69257438Sray struct fb_info *sc_info; 70257438Sray}; 71257438Sray 72256905Sraystatic void fbd_evh_init(void *); 73256905Sray/* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */ 74256905SraySYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL); 75256905Sray 76256905Sraystatic d_open_t fb_open; 77256905Sraystatic d_close_t fb_close; 78256905Sraystatic d_read_t fb_read; 79256905Sraystatic d_write_t fb_write; 80256905Sraystatic d_ioctl_t fb_ioctl; 81256905Sraystatic d_mmap_t fb_mmap; 82256905Sray 83256905Sraystatic struct cdevsw fb_cdevsw = { 84256905Sray .d_version = D_VERSION, 85256905Sray .d_flags = D_NEEDGIANT, 86256905Sray .d_open = fb_open, 87256905Sray .d_close = fb_close, 88256905Sray .d_read = fb_read, 89256905Sray .d_write = fb_write, 90256905Sray .d_ioctl = fb_ioctl, 91256905Sray .d_mmap = fb_mmap, 92256905Sray .d_name = "fb", 93256905Sray}; 94256905Sray 95256905Sraystatic int framebuffer_dev_unit = 0; 96256905Sray 97256905Sraystatic int 98256905Srayfb_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 99256905Sray{ 100256905Sray 101256905Sray return (0); 102256905Sray} 103256905Sray 104256905Sraystatic int 105256905Srayfb_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 106256905Sray{ 107256905Sray 108256905Sray return (0); 109256905Sray} 110256905Sray 111256905Sraystatic int 112256905Srayfb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 113256905Sray struct thread *td) 114256905Sray{ 115258491Sray struct fb_info *info; 116258491Sray int error; 117256905Sray 118258491Sray error = 0; 119258491Sray info = dev->si_drv1; 120258491Sray 121258491Sray switch (cmd) { 122258491Sray case FBIOGTYPE: 123258491Sray bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 124258491Sray break; 125258491Sray 126258491Sray case FBIO_GETWINORG: /* get frame buffer window origin */ 127258491Sray *(u_int *)data = 0; 128258491Sray break; 129258491Sray 130258491Sray case FBIO_GETDISPSTART: /* get display start address */ 131258491Sray ((video_display_start_t *)data)->x = 0; 132258491Sray ((video_display_start_t *)data)->y = 0; 133258491Sray break; 134258491Sray 135258491Sray case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 136258491Sray *(u_int *)data = info->fb_stride; 137258491Sray break; 138258491Sray 139258491Sray case FBIO_BLANK: /* blank display */ 140278846Shselasky if (info->setblankmode != NULL) 141278846Shselasky error = info->setblankmode(info->fb_priv, *(int *)data); 142258491Sray break; 143258491Sray 144258491Sray default: 145258491Sray error = ENOIOCTL; 146258491Sray break; 147258491Sray } 148258491Sray return (error); 149256905Sray} 150256905Sray 151256905Sraystatic int 152256905Srayfb_read(struct cdev *dev, struct uio *uio, int ioflag) 153256905Sray{ 154256905Sray 155256905Sray return (0); /* XXX nothing to read, yet */ 156256905Sray} 157256905Sray 158256905Sraystatic int 159256905Srayfb_write(struct cdev *dev, struct uio *uio, int ioflag) 160256905Sray{ 161256905Sray 162256905Sray return (0); /* XXX nothing written */ 163256905Sray} 164256905Sray 165256905Sraystatic int 166256905Srayfb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 167256905Sray vm_memattr_t *memattr) 168256905Sray{ 169256905Sray struct fb_info *info; 170256905Sray 171256905Sray info = dev->si_drv1; 172269620Snwhitehorn 173279752Shselasky if (info->fb_flags & FB_FLAG_NOMMAP) 174269620Snwhitehorn return (ENODEV); 175269620Snwhitehorn 176279752Shselasky if (offset >= 0 && offset < info->fb_size) { 177279752Shselasky if (info->fb_pbase == 0) 178279752Shselasky *paddr = vtophys((uint8_t *)info->fb_vbase + offset); 179279752Shselasky else 180279752Shselasky *paddr = info->fb_pbase + offset; 181307589Sgonzo if (info->fb_flags & FB_FLAG_MEMATTR) 182307589Sgonzo *memattr = info->fb_memattr; 183256905Sray return (0); 184256905Sray } 185256905Sray return (EINVAL); 186256905Sray} 187256905Sray 188256905Sraystatic int 189256905Srayfb_init(struct fb_list_entry *entry, int unit) 190256905Sray{ 191256905Sray struct fb_info *info; 192256905Sray 193256905Sray info = entry->fb_info; 194256905Sray entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL, 195256905Sray 0600, "fb%d", unit); 196256905Sray entry->fb_si->si_drv1 = info; 197259777Sray info->fb_cdev = entry->fb_si; 198256905Sray 199256905Sray return (0); 200256905Sray} 201256905Sray 202256905Srayint 203256905Srayfbd_list() 204256905Sray{ 205256905Sray struct fb_list_entry *entry; 206256905Sray 207256905Sray if (LIST_EMPTY(&fb_list_head)) 208256905Sray return (ENOENT); 209256905Sray 210256905Sray LIST_FOREACH(entry, &fb_list_head, fb_list) { 211256905Sray printf("FB %s @%p\n", entry->fb_info->fb_name, 212256905Sray (void *)entry->fb_info->fb_pbase); 213256905Sray } 214256905Sray 215256905Sray return (0); 216256905Sray} 217256905Sray 218256905Sraystatic struct fb_list_entry * 219256905Srayfbd_find(struct fb_info* info) 220256905Sray{ 221256905Sray struct fb_list_entry *entry, *tmp; 222256905Sray 223256905Sray LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 224256905Sray if (entry->fb_info == info) { 225256905Sray return (entry); 226256905Sray } 227256905Sray } 228256905Sray 229256905Sray return (NULL); 230256905Sray} 231256905Sray 232256905Srayint 233256905Srayfbd_register(struct fb_info* info) 234256905Sray{ 235256905Sray struct fb_list_entry *entry; 236256905Sray int err, first; 237256905Sray 238256905Sray first = 0; 239256905Sray if (LIST_EMPTY(&fb_list_head)) 240256905Sray first++; 241256905Sray 242256905Sray entry = fbd_find(info); 243256905Sray if (entry != NULL) { 244256905Sray /* XXX Update framebuffer params */ 245256905Sray return (0); 246256905Sray } 247256905Sray 248256905Sray entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO); 249256905Sray entry->fb_info = info; 250256905Sray 251256905Sray LIST_INSERT_HEAD(&fb_list_head, entry, fb_list); 252256905Sray 253256905Sray err = fb_init(entry, framebuffer_dev_unit++); 254256905Sray if (err) 255256905Sray return (err); 256256905Sray 257269620Snwhitehorn if (first) { 258269779Sdumbbell err = vt_fb_attach(info); 259269779Sdumbbell if (err) 260269779Sdumbbell return (err); 261269620Snwhitehorn } 262256905Sray 263256905Sray return (0); 264256905Sray} 265256905Sray 266256905Srayint 267256905Srayfbd_unregister(struct fb_info* info) 268256905Sray{ 269256905Sray struct fb_list_entry *entry, *tmp; 270256905Sray 271256905Sray LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 272256905Sray if (entry->fb_info == info) { 273256905Sray LIST_REMOVE(entry, fb_list); 274279488Sdumbbell if (LIST_EMPTY(&fb_list_head)) 275279488Sdumbbell vt_fb_detach(info); 276256905Sray free(entry, M_DEVBUF); 277256905Sray return (0); 278256905Sray } 279256905Sray } 280256905Sray 281256905Sray return (ENOENT); 282256905Sray} 283256905Sray 284256905Sraystatic void 285256905Srayregister_fb_wrap(void *arg, void *ptr) 286256905Sray{ 287256905Sray 288256905Sray fbd_register((struct fb_info *)ptr); 289256905Sray} 290256905Sray 291256905Sraystatic void 292256905Srayunregister_fb_wrap(void *arg, void *ptr) 293256905Sray{ 294256905Sray 295256905Sray fbd_unregister((struct fb_info *)ptr); 296256905Sray} 297256905Sray 298256905Sraystatic void 299256905Srayfbd_evh_init(void *ctx) 300256905Sray{ 301256905Sray 302256905Sray EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL, 303256905Sray EVENTHANDLER_PRI_ANY); 304256905Sray EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL, 305256905Sray EVENTHANDLER_PRI_ANY); 306256905Sray} 307257438Sray 308257438Sray/* Newbus methods. */ 309257438Sraystatic int 310257438Srayfbd_probe(device_t dev) 311257438Sray{ 312257438Sray 313257438Sray return (BUS_PROBE_NOWILDCARD); 314257438Sray} 315257438Sray 316257438Sraystatic int 317257438Srayfbd_attach(device_t dev) 318257438Sray{ 319257438Sray struct fbd_softc *sc; 320257438Sray int err; 321257438Sray 322257438Sray sc = device_get_softc(dev); 323257438Sray 324257438Sray sc->sc_dev = dev; 325257438Sray sc->sc_info = FB_GETINFO(device_get_parent(dev)); 326257546Sray if (sc->sc_info == NULL) 327257546Sray return (ENXIO); 328257438Sray err = fbd_register(sc->sc_info); 329257438Sray 330257438Sray return (err); 331257438Sray} 332257438Sray 333257438Sraystatic int 334257438Srayfbd_detach(device_t dev) 335257438Sray{ 336257438Sray struct fbd_softc *sc; 337257438Sray int err; 338257438Sray 339257438Sray sc = device_get_softc(dev); 340257438Sray 341257438Sray err = fbd_unregister(sc->sc_info); 342257438Sray 343257438Sray return (err); 344257438Sray} 345257438Sray 346257438Sraystatic device_method_t fbd_methods[] = { 347257438Sray /* Device interface */ 348257438Sray DEVMETHOD(device_probe, fbd_probe), 349257438Sray DEVMETHOD(device_attach, fbd_attach), 350257438Sray DEVMETHOD(device_detach, fbd_detach), 351257438Sray 352257438Sray DEVMETHOD(device_shutdown, bus_generic_shutdown), 353257438Sray 354257438Sray { 0, 0 } 355257438Sray}; 356257438Sray 357257438Sraydriver_t fbd_driver = { 358257438Sray "fbd", 359257438Sray fbd_methods, 360257438Sray sizeof(struct fbd_softc) 361257438Sray}; 362257438Sray 363257438Sraydevclass_t fbd_devclass; 364257438Sray 365257438SrayDRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0); 366257517SrayDRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0); 367279752ShselaskyDRIVER_MODULE(fbd, udl, fbd_driver, fbd_devclass, 0, 0); 368257438SrayMODULE_VERSION(fbd, 1); 369257438Sray 370