fbd.c revision 278846
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: head/sys/dev/fb/fbd.c 278846 2015-02-16 11:49:48Z hselasky $ 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: head/sys/dev/fb/fbd.c 278846 2015-02-16 11:49:48Z hselasky $"); 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 54257438Sray#include "fb_if.h" 55257438Sray 56256905SrayLIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head = 57256905Sray LIST_HEAD_INITIALIZER(fb_list_head); 58256905Sraystruct fb_list_entry { 59256905Sray struct fb_info *fb_info; 60256905Sray struct cdev *fb_si; 61256905Sray LIST_ENTRY(fb_list_entry) fb_list; 62256905Sray}; 63256905Sray 64257438Sraystruct fbd_softc { 65257438Sray device_t sc_dev; 66257438Sray struct fb_info *sc_info; 67257438Sray}; 68257438Sray 69256905Sraystatic void fbd_evh_init(void *); 70256905Sray/* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */ 71256905SraySYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL); 72256905Sray 73256905Sraystatic d_open_t fb_open; 74256905Sraystatic d_close_t fb_close; 75256905Sraystatic d_read_t fb_read; 76256905Sraystatic d_write_t fb_write; 77256905Sraystatic d_ioctl_t fb_ioctl; 78256905Sraystatic d_mmap_t fb_mmap; 79256905Sray 80256905Sraystatic struct cdevsw fb_cdevsw = { 81256905Sray .d_version = D_VERSION, 82256905Sray .d_flags = D_NEEDGIANT, 83256905Sray .d_open = fb_open, 84256905Sray .d_close = fb_close, 85256905Sray .d_read = fb_read, 86256905Sray .d_write = fb_write, 87256905Sray .d_ioctl = fb_ioctl, 88256905Sray .d_mmap = fb_mmap, 89256905Sray .d_name = "fb", 90256905Sray}; 91256905Sray 92256905Sraystatic int framebuffer_dev_unit = 0; 93256905Sray 94256905Sraystatic int 95256905Srayfb_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 96256905Sray{ 97256905Sray 98256905Sray return (0); 99256905Sray} 100256905Sray 101256905Sraystatic int 102256905Srayfb_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 103256905Sray{ 104256905Sray 105256905Sray return (0); 106256905Sray} 107256905Sray 108256905Sraystatic int 109256905Srayfb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 110256905Sray struct thread *td) 111256905Sray{ 112258491Sray struct fb_info *info; 113258491Sray int error; 114256905Sray 115258491Sray error = 0; 116258491Sray info = dev->si_drv1; 117258491Sray 118258491Sray switch (cmd) { 119258491Sray case FBIOGTYPE: 120258491Sray bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 121258491Sray break; 122258491Sray 123258491Sray case FBIO_GETWINORG: /* get frame buffer window origin */ 124258491Sray *(u_int *)data = 0; 125258491Sray break; 126258491Sray 127258491Sray case FBIO_GETDISPSTART: /* get display start address */ 128258491Sray ((video_display_start_t *)data)->x = 0; 129258491Sray ((video_display_start_t *)data)->y = 0; 130258491Sray break; 131258491Sray 132258491Sray case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 133258491Sray *(u_int *)data = info->fb_stride; 134258491Sray break; 135258491Sray 136258491Sray case FBIO_BLANK: /* blank display */ 137278846Shselasky if (info->setblankmode != NULL) 138278846Shselasky error = info->setblankmode(info->fb_priv, *(int *)data); 139258491Sray break; 140258491Sray 141258491Sray default: 142258491Sray error = ENOIOCTL; 143258491Sray break; 144258491Sray } 145258491Sray return (error); 146256905Sray} 147256905Sray 148256905Sraystatic int 149256905Srayfb_read(struct cdev *dev, struct uio *uio, int ioflag) 150256905Sray{ 151256905Sray 152256905Sray return (0); /* XXX nothing to read, yet */ 153256905Sray} 154256905Sray 155256905Sraystatic int 156256905Srayfb_write(struct cdev *dev, struct uio *uio, int ioflag) 157256905Sray{ 158256905Sray 159256905Sray return (0); /* XXX nothing written */ 160256905Sray} 161256905Sray 162256905Sraystatic int 163256905Srayfb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 164256905Sray vm_memattr_t *memattr) 165256905Sray{ 166256905Sray struct fb_info *info; 167256905Sray 168256905Sray info = dev->si_drv1; 169269620Snwhitehorn 170269620Snwhitehorn if ((info->fb_flags & FB_FLAG_NOMMAP) || info->fb_pbase == 0) 171269620Snwhitehorn return (ENODEV); 172269620Snwhitehorn 173256905Sray if (offset < info->fb_size) { 174256905Sray *paddr = info->fb_pbase + offset; 175256905Sray return (0); 176256905Sray } 177256905Sray return (EINVAL); 178256905Sray} 179256905Sray 180256905Sraystatic int 181256905Srayfb_init(struct fb_list_entry *entry, int unit) 182256905Sray{ 183256905Sray struct fb_info *info; 184256905Sray 185256905Sray info = entry->fb_info; 186256905Sray entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL, 187256905Sray 0600, "fb%d", unit); 188256905Sray entry->fb_si->si_drv1 = info; 189259777Sray info->fb_cdev = entry->fb_si; 190256905Sray 191256905Sray return (0); 192256905Sray} 193256905Sray 194256905Srayint 195256905Srayfbd_list() 196256905Sray{ 197256905Sray struct fb_list_entry *entry; 198256905Sray 199256905Sray if (LIST_EMPTY(&fb_list_head)) 200256905Sray return (ENOENT); 201256905Sray 202256905Sray LIST_FOREACH(entry, &fb_list_head, fb_list) { 203256905Sray printf("FB %s @%p\n", entry->fb_info->fb_name, 204256905Sray (void *)entry->fb_info->fb_pbase); 205256905Sray } 206256905Sray 207256905Sray return (0); 208256905Sray} 209256905Sray 210256905Sraystatic struct fb_list_entry * 211256905Srayfbd_find(struct fb_info* info) 212256905Sray{ 213256905Sray struct fb_list_entry *entry, *tmp; 214256905Sray 215256905Sray LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 216256905Sray if (entry->fb_info == info) { 217256905Sray return (entry); 218256905Sray } 219256905Sray } 220256905Sray 221256905Sray return (NULL); 222256905Sray} 223256905Sray 224256905Srayint 225256905Srayfbd_register(struct fb_info* info) 226256905Sray{ 227256905Sray struct fb_list_entry *entry; 228256905Sray int err, first; 229256905Sray 230256905Sray first = 0; 231256905Sray if (LIST_EMPTY(&fb_list_head)) 232256905Sray first++; 233256905Sray 234256905Sray entry = fbd_find(info); 235256905Sray if (entry != NULL) { 236256905Sray /* XXX Update framebuffer params */ 237256905Sray return (0); 238256905Sray } 239256905Sray 240256905Sray entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO); 241256905Sray entry->fb_info = info; 242256905Sray 243256905Sray LIST_INSERT_HEAD(&fb_list_head, entry, fb_list); 244256905Sray 245256905Sray err = fb_init(entry, framebuffer_dev_unit++); 246256905Sray if (err) 247256905Sray return (err); 248256905Sray 249269620Snwhitehorn if (first) { 250269779Sdumbbell err = vt_fb_attach(info); 251269779Sdumbbell if (err) 252269779Sdumbbell return (err); 253269620Snwhitehorn } 254256905Sray 255256905Sray return (0); 256256905Sray} 257256905Sray 258256905Srayint 259256905Srayfbd_unregister(struct fb_info* info) 260256905Sray{ 261256905Sray struct fb_list_entry *entry, *tmp; 262256905Sray 263256905Sray LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 264256905Sray if (entry->fb_info == info) { 265256905Sray LIST_REMOVE(entry, fb_list); 266256905Sray free(entry, M_DEVBUF); 267256905Sray return (0); 268256905Sray } 269256905Sray } 270256905Sray 271256905Sray return (ENOENT); 272256905Sray} 273256905Sray 274256905Sraystatic void 275256905Srayregister_fb_wrap(void *arg, void *ptr) 276256905Sray{ 277256905Sray 278256905Sray fbd_register((struct fb_info *)ptr); 279256905Sray} 280256905Sray 281256905Sraystatic void 282256905Srayunregister_fb_wrap(void *arg, void *ptr) 283256905Sray{ 284256905Sray 285256905Sray fbd_unregister((struct fb_info *)ptr); 286256905Sray} 287256905Sray 288256905Sraystatic void 289256905Srayfbd_evh_init(void *ctx) 290256905Sray{ 291256905Sray 292256905Sray EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL, 293256905Sray EVENTHANDLER_PRI_ANY); 294256905Sray EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL, 295256905Sray EVENTHANDLER_PRI_ANY); 296256905Sray} 297257438Sray 298257438Sray/* Newbus methods. */ 299257438Sraystatic int 300257438Srayfbd_probe(device_t dev) 301257438Sray{ 302257438Sray 303257438Sray return (BUS_PROBE_NOWILDCARD); 304257438Sray} 305257438Sray 306257438Sraystatic int 307257438Srayfbd_attach(device_t dev) 308257438Sray{ 309257438Sray struct fbd_softc *sc; 310257438Sray int err; 311257438Sray 312257438Sray sc = device_get_softc(dev); 313257438Sray 314257438Sray sc->sc_dev = dev; 315257438Sray sc->sc_info = FB_GETINFO(device_get_parent(dev)); 316257546Sray if (sc->sc_info == NULL) 317257546Sray return (ENXIO); 318257438Sray err = fbd_register(sc->sc_info); 319257438Sray 320257438Sray return (err); 321257438Sray} 322257438Sray 323257438Sraystatic int 324257438Srayfbd_detach(device_t dev) 325257438Sray{ 326257438Sray struct fbd_softc *sc; 327257438Sray int err; 328257438Sray 329257438Sray sc = device_get_softc(dev); 330257438Sray 331257438Sray err = fbd_unregister(sc->sc_info); 332257438Sray 333257438Sray return (err); 334257438Sray} 335257438Sray 336257438Sraystatic device_method_t fbd_methods[] = { 337257438Sray /* Device interface */ 338257438Sray DEVMETHOD(device_probe, fbd_probe), 339257438Sray DEVMETHOD(device_attach, fbd_attach), 340257438Sray DEVMETHOD(device_detach, fbd_detach), 341257438Sray 342257438Sray DEVMETHOD(device_shutdown, bus_generic_shutdown), 343257438Sray 344257438Sray { 0, 0 } 345257438Sray}; 346257438Sray 347257438Sraydriver_t fbd_driver = { 348257438Sray "fbd", 349257438Sray fbd_methods, 350257438Sray sizeof(struct fbd_softc) 351257438Sray}; 352257438Sray 353257438Sraydevclass_t fbd_devclass; 354257438Sray 355257438SrayDRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0); 356257517SrayDRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0); 357257438SrayMODULE_VERSION(fbd, 1); 358257438Sray 359