fbd.c revision 257517
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 257517 2013-11-01 19:19:47Z 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 257517 2013-11-01 19:19:47Z 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 51256905Sray#include <dev/vt/hw/fb/vt_fb.h> 52256905Sray 53257438Sray#include "fb_if.h" 54257438Sray 55256905SrayLIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head = 56256905Sray LIST_HEAD_INITIALIZER(fb_list_head); 57256905Sraystruct fb_list_entry { 58256905Sray struct fb_info *fb_info; 59256905Sray struct cdev *fb_si; 60256905Sray LIST_ENTRY(fb_list_entry) fb_list; 61256905Sray}; 62256905Sray 63257438Sraystruct fbd_softc { 64257438Sray device_t sc_dev; 65257438Sray struct fb_info *sc_info; 66257438Sray}; 67257438Sray 68256905Sraystatic void fbd_evh_init(void *); 69256905Sray/* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */ 70256905SraySYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL); 71256905Sray 72256905Sraystatic d_open_t fb_open; 73256905Sraystatic d_close_t fb_close; 74256905Sraystatic d_read_t fb_read; 75256905Sraystatic d_write_t fb_write; 76256905Sraystatic d_ioctl_t fb_ioctl; 77256905Sraystatic d_mmap_t fb_mmap; 78256905Sray 79256905Sraystatic struct cdevsw fb_cdevsw = { 80256905Sray .d_version = D_VERSION, 81256905Sray .d_flags = D_NEEDGIANT, 82256905Sray .d_open = fb_open, 83256905Sray .d_close = fb_close, 84256905Sray .d_read = fb_read, 85256905Sray .d_write = fb_write, 86256905Sray .d_ioctl = fb_ioctl, 87256905Sray .d_mmap = fb_mmap, 88256905Sray .d_name = "fb", 89256905Sray}; 90256905Sray 91256905Sraystatic int framebuffer_dev_unit = 0; 92256905Sray 93256905Sraystatic int 94256905Srayfb_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 95256905Sray{ 96256905Sray 97256905Sray return (0); 98256905Sray} 99256905Sray 100256905Sraystatic int 101256905Srayfb_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 102256905Sray{ 103256905Sray 104256905Sray return (0); 105256905Sray} 106256905Sray 107256905Sraystatic int 108256905Srayfb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 109256905Sray struct thread *td) 110256905Sray{ 111256905Sray 112256905Sray return (0); 113256905Sray} 114256905Sray 115256905Sraystatic int 116256905Srayfb_read(struct cdev *dev, struct uio *uio, int ioflag) 117256905Sray{ 118256905Sray 119256905Sray return (0); /* XXX nothing to read, yet */ 120256905Sray} 121256905Sray 122256905Sraystatic int 123256905Srayfb_write(struct cdev *dev, struct uio *uio, int ioflag) 124256905Sray{ 125256905Sray 126256905Sray return (0); /* XXX nothing written */ 127256905Sray} 128256905Sray 129256905Sraystatic int 130256905Srayfb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 131256905Sray vm_memattr_t *memattr) 132256905Sray{ 133256905Sray struct fb_info *info; 134256905Sray 135256905Sray info = dev->si_drv1; 136256905Sray if (offset < info->fb_size) { 137256905Sray *paddr = info->fb_pbase + offset; 138256905Sray return (0); 139256905Sray } 140256905Sray return (EINVAL); 141256905Sray} 142256905Sray 143256905Sray 144256905Sraystatic void 145256905Srayvt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 146256905Sray{ 147256905Sray 148256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 149256905Sray *(uint8_t *)(sc->fb_vbase + o) = v; 150256905Sray} 151256905Sray 152256905Sraystatic void 153256905Srayvt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 154256905Sray{ 155256905Sray 156256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 157256905Sray *(uint16_t *)(sc->fb_vbase + o) = v; 158256905Sray} 159256905Sray 160256905Sraystatic void 161256905Srayvt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 162256905Sray{ 163256905Sray 164256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 165256905Sray *(uint32_t *)(sc->fb_vbase + o) = v; 166256905Sray} 167256905Sray 168256905Sraystatic void 169257013Srayvt_fb_mem_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from, 170257013Sray uint32_t size) 171257013Sray{ 172257013Sray 173257013Sray memmove((void *)(sc->fb_vbase + offset_to), (void *)(sc->fb_vbase + 174257013Sray offset_from), size); 175257013Sray} 176257013Sray 177257013Sraystatic void 178256905Srayvt_fb_indir_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 179256905Sray{ 180256905Sray 181256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 182256905Sray sc->fb_write(sc->fb_priv, o, &v, 1); 183256905Sray} 184256905Sray 185256905Sraystatic void 186256905Srayvt_fb_indir_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 187256905Sray{ 188256905Sray 189256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 190256905Sray sc->fb_write(sc->fb_priv, o, &v, 2); 191256905Sray} 192256905Sray 193256905Sraystatic void 194256905Srayvt_fb_indir_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 195256905Sray{ 196256905Sray 197256905Sray KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 198256905Sray sc->fb_write(sc->fb_priv, o, &v, 4); 199256905Sray} 200256905Sray 201257013Sraystatic void 202257013Srayvt_fb_indir_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from, 203257013Sray uint32_t size) 204257013Sray{ 205257013Sray 206257013Sray sc->copy(sc->fb_priv, offset_to, offset_from, size); 207257013Sray} 208257013Sray 209256905Sraystatic int 210256905Srayfb_probe(struct fb_info *info) 211256905Sray{ 212256905Sray 213256905Sray if (info->fb_size == 0) 214256905Sray return (ENXIO); 215256905Sray 216256905Sray if (info->fb_write != NULL) { 217256905Sray if (info->fb_write == NULL) { 218256905Sray return (EINVAL); 219256905Sray } 220256905Sray info->fb_flags |= FB_FLAG_NOMMAP; 221256905Sray info->wr1 = &vt_fb_indir_wr1; 222256905Sray info->wr2 = &vt_fb_indir_wr2; 223256905Sray info->wr4 = &vt_fb_indir_wr4; 224257013Sray info->copy = &vt_fb_indir_copy; 225256905Sray } else if (info->fb_vbase != 0) { 226256905Sray if (info->fb_pbase == 0) 227256905Sray info->fb_flags |= FB_FLAG_NOMMAP; 228256905Sray info->wr1 = &vt_fb_mem_wr1; 229256905Sray info->wr2 = &vt_fb_mem_wr2; 230256905Sray info->wr4 = &vt_fb_mem_wr4; 231257013Sray info->copy = &vt_fb_mem_copy; 232256905Sray } else 233256905Sray return (ENXIO); 234256905Sray 235256905Sray return (0); 236256905Sray} 237256905Sray 238256905Sray 239256905Sraystatic int 240256905Srayfb_init(struct fb_list_entry *entry, int unit) 241256905Sray{ 242256905Sray struct fb_info *info; 243256905Sray 244256905Sray info = entry->fb_info; 245256905Sray entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL, 246256905Sray 0600, "fb%d", unit); 247256905Sray entry->fb_si->si_drv1 = info; 248256905Sray 249256905Sray return (0); 250256905Sray} 251256905Sray 252256905Srayint 253256905Srayfbd_list() 254256905Sray{ 255256905Sray struct fb_list_entry *entry; 256256905Sray 257256905Sray if (LIST_EMPTY(&fb_list_head)) 258256905Sray return (ENOENT); 259256905Sray 260256905Sray LIST_FOREACH(entry, &fb_list_head, fb_list) { 261256905Sray printf("FB %s @%p\n", entry->fb_info->fb_name, 262256905Sray (void *)entry->fb_info->fb_pbase); 263256905Sray } 264256905Sray 265256905Sray return (0); 266256905Sray} 267256905Sray 268256905Sraystatic struct fb_list_entry * 269256905Srayfbd_find(struct fb_info* info) 270256905Sray{ 271256905Sray struct fb_list_entry *entry, *tmp; 272256905Sray 273256905Sray LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 274256905Sray if (entry->fb_info == info) { 275256905Sray return (entry); 276256905Sray } 277256905Sray } 278256905Sray 279256905Sray return (NULL); 280256905Sray} 281256905Sray 282256905Srayint 283256905Srayfbd_register(struct fb_info* info) 284256905Sray{ 285256905Sray struct fb_list_entry *entry; 286256905Sray int err, first; 287256905Sray 288256905Sray first = 0; 289256905Sray if (LIST_EMPTY(&fb_list_head)) 290256905Sray first++; 291256905Sray 292256905Sray entry = fbd_find(info); 293256905Sray if (entry != NULL) { 294256905Sray /* XXX Update framebuffer params */ 295256905Sray return (0); 296256905Sray } 297256905Sray 298256905Sray err = fb_probe(info); 299256905Sray if (err) 300256905Sray return (err); 301256905Sray 302256905Sray entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO); 303256905Sray entry->fb_info = info; 304256905Sray 305256905Sray LIST_INSERT_HEAD(&fb_list_head, entry, fb_list); 306256905Sray 307256905Sray err = fb_init(entry, framebuffer_dev_unit++); 308256905Sray if (err) 309256905Sray return (err); 310256905Sray 311256905Sray if (first) 312256905Sray vt_fb_attach(info); 313256905Sray 314256905Sray return (0); 315256905Sray} 316256905Sray 317256905Srayint 318256905Srayfbd_unregister(struct fb_info* info) 319256905Sray{ 320256905Sray struct fb_list_entry *entry, *tmp; 321256905Sray 322256905Sray LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 323256905Sray if (entry->fb_info == info) { 324256905Sray LIST_REMOVE(entry, fb_list); 325256905Sray free(entry, M_DEVBUF); 326256905Sray return (0); 327256905Sray } 328256905Sray } 329256905Sray 330256905Sray return (ENOENT); 331256905Sray} 332256905Sray 333256905Sraystatic void 334256905Srayregister_fb_wrap(void *arg, void *ptr) 335256905Sray{ 336256905Sray 337256905Sray fbd_register((struct fb_info *)ptr); 338256905Sray} 339256905Sray 340256905Sraystatic void 341256905Srayunregister_fb_wrap(void *arg, void *ptr) 342256905Sray{ 343256905Sray 344256905Sray fbd_unregister((struct fb_info *)ptr); 345256905Sray} 346256905Sray 347256905Sraystatic void 348256905Srayfbd_evh_init(void *ctx) 349256905Sray{ 350256905Sray 351256905Sray EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL, 352256905Sray EVENTHANDLER_PRI_ANY); 353256905Sray EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL, 354256905Sray EVENTHANDLER_PRI_ANY); 355256905Sray} 356257438Sray 357257438Sray/* Newbus methods. */ 358257438Sraystatic int 359257438Srayfbd_probe(device_t dev) 360257438Sray{ 361257438Sray 362257438Sray return (BUS_PROBE_NOWILDCARD); 363257438Sray} 364257438Sray 365257438Sraystatic int 366257438Srayfbd_attach(device_t dev) 367257438Sray{ 368257438Sray struct fbd_softc *sc; 369257438Sray int err; 370257438Sray 371257438Sray sc = device_get_softc(dev); 372257438Sray 373257438Sray sc->sc_dev = dev; 374257438Sray sc->sc_info = FB_GETINFO(device_get_parent(dev)); 375257438Sray err = fbd_register(sc->sc_info); 376257438Sray 377257438Sray return (err); 378257438Sray} 379257438Sray 380257438Sraystatic int 381257438Srayfbd_detach(device_t dev) 382257438Sray{ 383257438Sray struct fbd_softc *sc; 384257438Sray int err; 385257438Sray 386257438Sray sc = device_get_softc(dev); 387257438Sray 388257438Sray err = fbd_unregister(sc->sc_info); 389257438Sray 390257438Sray return (err); 391257438Sray} 392257438Sray 393257438Sray 394257438Sraystatic device_method_t fbd_methods[] = { 395257438Sray /* Device interface */ 396257438Sray DEVMETHOD(device_probe, fbd_probe), 397257438Sray DEVMETHOD(device_attach, fbd_attach), 398257438Sray DEVMETHOD(device_detach, fbd_detach), 399257438Sray 400257438Sray DEVMETHOD(device_shutdown, bus_generic_shutdown), 401257438Sray DEVMETHOD(device_suspend, bus_generic_suspend), 402257438Sray DEVMETHOD(device_resume, bus_generic_resume), 403257438Sray 404257438Sray { 0, 0 } 405257438Sray}; 406257438Sray 407257438Sraydriver_t fbd_driver = { 408257438Sray "fbd", 409257438Sray fbd_methods, 410257438Sray sizeof(struct fbd_softc) 411257438Sray}; 412257438Sray 413257438Sraydevclass_t fbd_devclass; 414257438Sray 415257438SrayDRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0); 416257517SrayDRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0); 417257438SrayMODULE_VERSION(fbd, 1); 418257438Sray 419