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$ 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$"); 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 */ 137258491Sray error = 0; /* TODO */ 138258491Sray break; 139258491Sray 140258491Sray default: 141258491Sray error = ENOIOCTL; 142258491Sray break; 143258491Sray } 144258491Sray return (error); 145256905Sray} 146256905Sray 147256905Sraystatic int 148256905Srayfb_read(struct cdev *dev, struct uio *uio, int ioflag) 149256905Sray{ 150256905Sray 151256905Sray return (0); /* XXX nothing to read, yet */ 152256905Sray} 153256905Sray 154256905Sraystatic int 155256905Srayfb_write(struct cdev *dev, struct uio *uio, int ioflag) 156256905Sray{ 157256905Sray 158256905Sray return (0); /* XXX nothing written */ 159256905Sray} 160256905Sray 161256905Sraystatic int 162256905Srayfb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 163256905Sray vm_memattr_t *memattr) 164256905Sray{ 165256905Sray struct fb_info *info; 166256905Sray 167256905Sray info = dev->si_drv1; 168271117Semaste 169271117Semaste if ((info->fb_flags & FB_FLAG_NOMMAP) || info->fb_pbase == 0) 170271117Semaste return (ENODEV); 171271117Semaste 172256905Sray if (offset < info->fb_size) { 173256905Sray *paddr = info->fb_pbase + offset; 174256905Sray return (0); 175256905Sray } 176256905Sray return (EINVAL); 177256905Sray} 178256905Sray 179256905Sraystatic int 180256905Srayfb_init(struct fb_list_entry *entry, int unit) 181256905Sray{ 182256905Sray struct fb_info *info; 183256905Sray 184256905Sray info = entry->fb_info; 185256905Sray entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL, 186256905Sray 0600, "fb%d", unit); 187256905Sray entry->fb_si->si_drv1 = info; 188262861Sjhb info->fb_cdev = entry->fb_si; 189256905Sray 190256905Sray return (0); 191256905Sray} 192256905Sray 193256905Srayint 194256905Srayfbd_list() 195256905Sray{ 196256905Sray struct fb_list_entry *entry; 197256905Sray 198256905Sray if (LIST_EMPTY(&fb_list_head)) 199256905Sray return (ENOENT); 200256905Sray 201256905Sray LIST_FOREACH(entry, &fb_list_head, fb_list) { 202256905Sray printf("FB %s @%p\n", entry->fb_info->fb_name, 203256905Sray (void *)entry->fb_info->fb_pbase); 204256905Sray } 205256905Sray 206256905Sray return (0); 207256905Sray} 208256905Sray 209256905Sraystatic struct fb_list_entry * 210256905Srayfbd_find(struct fb_info* info) 211256905Sray{ 212256905Sray struct fb_list_entry *entry, *tmp; 213256905Sray 214256905Sray LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 215256905Sray if (entry->fb_info == info) { 216256905Sray return (entry); 217256905Sray } 218256905Sray } 219256905Sray 220256905Sray return (NULL); 221256905Sray} 222256905Sray 223256905Srayint 224256905Srayfbd_register(struct fb_info* info) 225256905Sray{ 226256905Sray struct fb_list_entry *entry; 227256905Sray int err, first; 228256905Sray 229256905Sray first = 0; 230256905Sray if (LIST_EMPTY(&fb_list_head)) 231256905Sray first++; 232256905Sray 233256905Sray entry = fbd_find(info); 234256905Sray if (entry != NULL) { 235256905Sray /* XXX Update framebuffer params */ 236256905Sray return (0); 237256905Sray } 238256905Sray 239256905Sray entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO); 240256905Sray entry->fb_info = info; 241256905Sray 242256905Sray LIST_INSERT_HEAD(&fb_list_head, entry, fb_list); 243256905Sray 244256905Sray err = fb_init(entry, framebuffer_dev_unit++); 245256905Sray if (err) 246256905Sray return (err); 247256905Sray 248271117Semaste if (first) { 249271769Sdumbbell err = vt_fb_attach(info); 250271769Sdumbbell if (err) 251271769Sdumbbell return (err); 252271117Semaste } 253256905Sray 254256905Sray return (0); 255256905Sray} 256256905Sray 257256905Srayint 258256905Srayfbd_unregister(struct fb_info* info) 259256905Sray{ 260256905Sray struct fb_list_entry *entry, *tmp; 261256905Sray 262256905Sray LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 263256905Sray if (entry->fb_info == info) { 264256905Sray LIST_REMOVE(entry, fb_list); 265256905Sray free(entry, M_DEVBUF); 266256905Sray return (0); 267256905Sray } 268256905Sray } 269256905Sray 270256905Sray return (ENOENT); 271256905Sray} 272256905Sray 273256905Sraystatic void 274256905Srayregister_fb_wrap(void *arg, void *ptr) 275256905Sray{ 276256905Sray 277256905Sray fbd_register((struct fb_info *)ptr); 278256905Sray} 279256905Sray 280256905Sraystatic void 281256905Srayunregister_fb_wrap(void *arg, void *ptr) 282256905Sray{ 283256905Sray 284256905Sray fbd_unregister((struct fb_info *)ptr); 285256905Sray} 286256905Sray 287256905Sraystatic void 288256905Srayfbd_evh_init(void *ctx) 289256905Sray{ 290256905Sray 291256905Sray EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL, 292256905Sray EVENTHANDLER_PRI_ANY); 293256905Sray EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL, 294256905Sray EVENTHANDLER_PRI_ANY); 295256905Sray} 296257438Sray 297257438Sray/* Newbus methods. */ 298257438Sraystatic int 299257438Srayfbd_probe(device_t dev) 300257438Sray{ 301257438Sray 302257438Sray return (BUS_PROBE_NOWILDCARD); 303257438Sray} 304257438Sray 305257438Sraystatic int 306257438Srayfbd_attach(device_t dev) 307257438Sray{ 308257438Sray struct fbd_softc *sc; 309257438Sray int err; 310257438Sray 311257438Sray sc = device_get_softc(dev); 312257438Sray 313257438Sray sc->sc_dev = dev; 314257438Sray sc->sc_info = FB_GETINFO(device_get_parent(dev)); 315257546Sray if (sc->sc_info == NULL) 316257546Sray return (ENXIO); 317257438Sray err = fbd_register(sc->sc_info); 318257438Sray 319257438Sray return (err); 320257438Sray} 321257438Sray 322257438Sraystatic int 323257438Srayfbd_detach(device_t dev) 324257438Sray{ 325257438Sray struct fbd_softc *sc; 326257438Sray int err; 327257438Sray 328257438Sray sc = device_get_softc(dev); 329257438Sray 330257438Sray err = fbd_unregister(sc->sc_info); 331257438Sray 332257438Sray return (err); 333257438Sray} 334257438Sray 335257815Sraystatic int 336257815Srayfbd_suspend(device_t dev) 337257815Sray{ 338257438Sray 339257815Sray vt_fb_suspend(); 340257815Sray return (bus_generic_suspend(dev)); 341257815Sray} 342257815Sray 343257815Sraystatic int 344257815Srayfbd_resume(device_t dev) 345257815Sray{ 346257815Sray 347257815Sray vt_fb_resume(); 348257815Sray return (bus_generic_resume(dev)); 349257815Sray} 350257815Sray 351257438Sraystatic device_method_t fbd_methods[] = { 352257438Sray /* Device interface */ 353257438Sray DEVMETHOD(device_probe, fbd_probe), 354257438Sray DEVMETHOD(device_attach, fbd_attach), 355257438Sray DEVMETHOD(device_detach, fbd_detach), 356257438Sray 357257438Sray DEVMETHOD(device_shutdown, bus_generic_shutdown), 358257815Sray DEVMETHOD(device_suspend, fbd_suspend), 359257815Sray DEVMETHOD(device_resume, fbd_resume), 360257438Sray 361257438Sray { 0, 0 } 362257438Sray}; 363257438Sray 364257438Sraydriver_t fbd_driver = { 365257438Sray "fbd", 366257438Sray fbd_methods, 367257438Sray sizeof(struct fbd_softc) 368257438Sray}; 369257438Sray 370257438Sraydevclass_t fbd_devclass; 371257438Sray 372257438SrayDRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0); 373257517SrayDRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0); 374257438SrayMODULE_VERSION(fbd, 1); 375257438Sray 376