fbd.c revision 257727
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: user/ed/newcons/sys/dev/fb/fbd.c 257727 2013-11-05 23:12:53Z ray $ 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: user/ed/newcons/sys/dev/fb/fbd.c 257727 2013-11-05 23:12:53Z ray $"); 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{ 112256905Sray 113256905Sray return (0); 114256905Sray} 115256905Sray 116256905Sraystatic int 117256905Srayfb_read(struct cdev *dev, struct uio *uio, int ioflag) 118256905Sray{ 119256905Sray 120256905Sray return (0); /* XXX nothing to read, yet */ 121256905Sray} 122256905Sray 123256905Sraystatic int 124256905Srayfb_write(struct cdev *dev, struct uio *uio, int ioflag) 125256905Sray{ 126256905Sray 127256905Sray return (0); /* XXX nothing written */ 128256905Sray} 129256905Sray 130256905Sraystatic int 131256905Srayfb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 132256905Sray vm_memattr_t *memattr) 133256905Sray{ 134256905Sray struct fb_info *info; 135256905Sray 136256905Sray info = dev->si_drv1; 137256905Sray if (offset < info->fb_size) { 138256905Sray *paddr = info->fb_pbase + offset; 139256905Sray return (0); 140256905Sray } 141256905Sray return (EINVAL); 142256905Sray} 143256905Sray 144256905Sray 145256905Sraystatic void 146256905Srayvt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 147256905Sray{ 148256905Sray 149256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 150256905Sray *(uint8_t *)(sc->fb_vbase + o) = v; 151256905Sray} 152256905Sray 153256905Sraystatic void 154256905Srayvt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 155256905Sray{ 156256905Sray 157256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 158256905Sray *(uint16_t *)(sc->fb_vbase + o) = v; 159256905Sray} 160256905Sray 161256905Sraystatic void 162256905Srayvt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 163256905Sray{ 164256905Sray 165256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 166256905Sray *(uint32_t *)(sc->fb_vbase + o) = v; 167256905Sray} 168256905Sray 169256905Sraystatic void 170257013Srayvt_fb_mem_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from, 171257013Sray uint32_t size) 172257013Sray{ 173257013Sray 174257013Sray memmove((void *)(sc->fb_vbase + offset_to), (void *)(sc->fb_vbase + 175257013Sray offset_from), size); 176257013Sray} 177257013Sray 178257013Sraystatic void 179256905Srayvt_fb_indir_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 180256905Sray{ 181256905Sray 182256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 183256905Sray sc->fb_write(sc->fb_priv, o, &v, 1); 184256905Sray} 185256905Sray 186256905Sraystatic void 187256905Srayvt_fb_indir_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 188256905Sray{ 189256905Sray 190256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 191256905Sray sc->fb_write(sc->fb_priv, o, &v, 2); 192256905Sray} 193256905Sray 194256905Sraystatic void 195256905Srayvt_fb_indir_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 196256905Sray{ 197256905Sray 198256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 199256905Sray sc->fb_write(sc->fb_priv, o, &v, 4); 200256905Sray} 201256905Sray 202257013Sraystatic void 203257013Srayvt_fb_indir_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from, 204257013Sray uint32_t size) 205257013Sray{ 206257013Sray 207257013Sray sc->copy(sc->fb_priv, offset_to, offset_from, size); 208257013Sray} 209257013Sray 210257727Srayint 211256905Srayfb_probe(struct fb_info *info) 212256905Sray{ 213256905Sray 214256905Sray if (info->fb_size == 0) 215256905Sray return (ENXIO); 216256905Sray 217256905Sray if (info->fb_write != NULL) { 218256905Sray if (info->fb_write == NULL) { 219256905Sray return (EINVAL); 220256905Sray } 221256905Sray info->fb_flags |= FB_FLAG_NOMMAP; 222256905Sray info->wr1 = &vt_fb_indir_wr1; 223256905Sray info->wr2 = &vt_fb_indir_wr2; 224256905Sray info->wr4 = &vt_fb_indir_wr4; 225257013Sray info->copy = &vt_fb_indir_copy; 226256905Sray } else if (info->fb_vbase != 0) { 227256905Sray if (info->fb_pbase == 0) 228256905Sray info->fb_flags |= FB_FLAG_NOMMAP; 229256905Sray info->wr1 = &vt_fb_mem_wr1; 230256905Sray info->wr2 = &vt_fb_mem_wr2; 231256905Sray info->wr4 = &vt_fb_mem_wr4; 232257013Sray info->copy = &vt_fb_mem_copy; 233256905Sray } else 234256905Sray return (ENXIO); 235256905Sray 236256905Sray return (0); 237256905Sray} 238256905Sray 239256905Sray 240256905Sraystatic int 241256905Srayfb_init(struct fb_list_entry *entry, int unit) 242256905Sray{ 243256905Sray struct fb_info *info; 244256905Sray 245256905Sray info = entry->fb_info; 246256905Sray entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL, 247256905Sray 0600, "fb%d", unit); 248256905Sray entry->fb_si->si_drv1 = info; 249256905Sray 250256905Sray return (0); 251256905Sray} 252256905Sray 253256905Srayint 254256905Srayfbd_list() 255256905Sray{ 256256905Sray struct fb_list_entry *entry; 257256905Sray 258256905Sray if (LIST_EMPTY(&fb_list_head)) 259256905Sray return (ENOENT); 260256905Sray 261256905Sray LIST_FOREACH(entry, &fb_list_head, fb_list) { 262256905Sray printf("FB %s @%p\n", entry->fb_info->fb_name, 263256905Sray (void *)entry->fb_info->fb_pbase); 264256905Sray } 265256905Sray 266256905Sray return (0); 267256905Sray} 268256905Sray 269256905Sraystatic struct fb_list_entry * 270256905Srayfbd_find(struct fb_info* info) 271256905Sray{ 272256905Sray struct fb_list_entry *entry, *tmp; 273256905Sray 274256905Sray LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 275256905Sray if (entry->fb_info == info) { 276256905Sray return (entry); 277256905Sray } 278256905Sray } 279256905Sray 280256905Sray return (NULL); 281256905Sray} 282256905Sray 283256905Srayint 284256905Srayfbd_register(struct fb_info* info) 285256905Sray{ 286256905Sray struct fb_list_entry *entry; 287256905Sray int err, first; 288256905Sray 289256905Sray first = 0; 290256905Sray if (LIST_EMPTY(&fb_list_head)) 291256905Sray first++; 292256905Sray 293256905Sray entry = fbd_find(info); 294256905Sray if (entry != NULL) { 295256905Sray /* XXX Update framebuffer params */ 296256905Sray return (0); 297256905Sray } 298256905Sray 299256905Sray err = fb_probe(info); 300256905Sray if (err) 301256905Sray return (err); 302256905Sray 303256905Sray entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO); 304256905Sray entry->fb_info = info; 305256905Sray 306256905Sray LIST_INSERT_HEAD(&fb_list_head, entry, fb_list); 307256905Sray 308256905Sray err = fb_init(entry, framebuffer_dev_unit++); 309256905Sray if (err) 310256905Sray return (err); 311256905Sray 312256905Sray if (first) 313256905Sray vt_fb_attach(info); 314256905Sray 315256905Sray return (0); 316256905Sray} 317256905Sray 318256905Srayint 319256905Srayfbd_unregister(struct fb_info* info) 320256905Sray{ 321256905Sray struct fb_list_entry *entry, *tmp; 322256905Sray 323256905Sray LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 324256905Sray if (entry->fb_info == info) { 325256905Sray LIST_REMOVE(entry, fb_list); 326256905Sray free(entry, M_DEVBUF); 327256905Sray return (0); 328256905Sray } 329256905Sray } 330256905Sray 331256905Sray return (ENOENT); 332256905Sray} 333256905Sray 334256905Sraystatic void 335256905Srayregister_fb_wrap(void *arg, void *ptr) 336256905Sray{ 337256905Sray 338256905Sray fbd_register((struct fb_info *)ptr); 339256905Sray} 340256905Sray 341256905Sraystatic void 342256905Srayunregister_fb_wrap(void *arg, void *ptr) 343256905Sray{ 344256905Sray 345256905Sray fbd_unregister((struct fb_info *)ptr); 346256905Sray} 347256905Sray 348256905Sraystatic void 349256905Srayfbd_evh_init(void *ctx) 350256905Sray{ 351256905Sray 352256905Sray EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL, 353256905Sray EVENTHANDLER_PRI_ANY); 354256905Sray EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL, 355256905Sray EVENTHANDLER_PRI_ANY); 356256905Sray} 357257438Sray 358257438Sray/* Newbus methods. */ 359257438Sraystatic int 360257438Srayfbd_probe(device_t dev) 361257438Sray{ 362257438Sray 363257438Sray return (BUS_PROBE_NOWILDCARD); 364257438Sray} 365257438Sray 366257438Sraystatic int 367257438Srayfbd_attach(device_t dev) 368257438Sray{ 369257438Sray struct fbd_softc *sc; 370257438Sray int err; 371257438Sray 372257438Sray sc = device_get_softc(dev); 373257438Sray 374257438Sray sc->sc_dev = dev; 375257438Sray sc->sc_info = FB_GETINFO(device_get_parent(dev)); 376257546Sray if (sc->sc_info == NULL) 377257546Sray return (ENXIO); 378257438Sray err = fbd_register(sc->sc_info); 379257438Sray 380257438Sray return (err); 381257438Sray} 382257438Sray 383257438Sraystatic int 384257438Srayfbd_detach(device_t dev) 385257438Sray{ 386257438Sray struct fbd_softc *sc; 387257438Sray int err; 388257438Sray 389257438Sray sc = device_get_softc(dev); 390257438Sray 391257438Sray err = fbd_unregister(sc->sc_info); 392257438Sray 393257438Sray return (err); 394257438Sray} 395257438Sray 396257438Sray 397257438Sraystatic device_method_t fbd_methods[] = { 398257438Sray /* Device interface */ 399257438Sray DEVMETHOD(device_probe, fbd_probe), 400257438Sray DEVMETHOD(device_attach, fbd_attach), 401257438Sray DEVMETHOD(device_detach, fbd_detach), 402257438Sray 403257438Sray DEVMETHOD(device_shutdown, bus_generic_shutdown), 404257438Sray DEVMETHOD(device_suspend, bus_generic_suspend), 405257438Sray DEVMETHOD(device_resume, bus_generic_resume), 406257438Sray 407257438Sray { 0, 0 } 408257438Sray}; 409257438Sray 410257438Sraydriver_t fbd_driver = { 411257438Sray "fbd", 412257438Sray fbd_methods, 413257438Sray sizeof(struct fbd_softc) 414257438Sray}; 415257438Sray 416257438Sraydevclass_t fbd_devclass; 417257438Sray 418257438SrayDRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0); 419257517SrayDRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0); 420257438SrayMODULE_VERSION(fbd, 1); 421257438Sray 422