fbd.c revision 279752
195065Strhodes/*- 295065Strhodes * Copyright (c) 2013 The FreeBSD Foundation 395065Strhodes * All rights reserved. 495065Strhodes * 595065Strhodes * This software was developed by Aleksandr Rybalko under sponsorship from the 695065Strhodes * FreeBSD Foundation. 795065Strhodes * 895065Strhodes * Redistribution and use in source and binary forms, with or without 995065Strhodes * modification, are permitted provided that the following conditions 1095065Strhodes * are met: 1195065Strhodes * 1. Redistributions of source code must retain the above copyright 1295065Strhodes * notice, this list of conditions and the following disclaimer. 1395065Strhodes * 2. Redistributions in binary form must reproduce the above copyright 1495065Strhodes * notice, this list of conditions and the following disclaimer in the 1595065Strhodes * documentation and/or other materials provided with the distribution. 1695065Strhodes * 1795065Strhodes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1895065Strhodes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1995065Strhodes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2095065Strhodes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2195065Strhodes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2295065Strhodes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2395065Strhodes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2495065Strhodes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2595065Strhodes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2695065Strhodes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2795065Strhodes * SUCH DAMAGE. 2895065Strhodes * 2995065Strhodes * $FreeBSD: head/sys/dev/fb/fbd.c 279752 2015-03-07 20:45:15Z hselasky $ 3097593Sru */ 3197593Sru 32239090Sglebius/* Generic framebuffer */ 3395065Strhodes/* TODO unlink from VT(9) */ 3495065Strhodes/* TODO done normal /dev/fb methods */ 3595065Strhodes 3695065Strhodes#include <sys/cdefs.h> 3795065Strhodes__FBSDID("$FreeBSD: head/sys/dev/fb/fbd.c 279752 2015-03-07 20:45:15Z hselasky $"); 3895065Strhodes 39164524Sbrueffer#include <sys/param.h> 40164524Sbrueffer#include <sys/systm.h> 41164524Sbrueffer#include <sys/bus.h> 42164524Sbrueffer#include <sys/conf.h> 43227750Smiwi#include <sys/kernel.h> 44227750Smiwi#include <sys/malloc.h> 45131034Simp#include <sys/module.h> 46164524Sbrueffer#include <sys/queue.h> 47164524Sbrueffer#include <sys/fbio.h> 48164524Sbrueffer 49164524Sbrueffer#include <machine/bus.h> 50164524Sbrueffer 51164524Sbrueffer#include <dev/vt/vt.h> 52164524Sbrueffer#include <dev/vt/hw/fb/vt_fb.h> 53164524Sbrueffer 5495065Strhodes#include <vm/vm.h> 5595065Strhodes#include <vm/pmap.h> 5695065Strhodes 5795065Strhodes#include "fb_if.h" 5895065Strhodes 5995065StrhodesLIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head = 6097593Sru LIST_HEAD_INITIALIZER(fb_list_head); 6197593Srustruct fb_list_entry { 6295065Strhodes struct fb_info *fb_info; 6397593Sru struct cdev *fb_si; 6497593Sru LIST_ENTRY(fb_list_entry) fb_list; 65134738Sbrueffer}; 6695065Strhodes 6795065Strhodesstruct fbd_softc { 6895065Strhodes device_t sc_dev; 6995065Strhodes struct fb_info *sc_info; 7095065Strhodes}; 71134046Ssimon 72134046Ssimonstatic void fbd_evh_init(void *); 73134046Ssimon/* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */ 74134046SsimonSYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL); 75134046Ssimon 76134046Ssimonstatic d_open_t fb_open; 77134046Ssimonstatic d_close_t fb_close; 78134046Ssimonstatic d_read_t fb_read; 79134046Ssimonstatic d_write_t fb_write; 80159745Snetchildstatic d_ioctl_t fb_ioctl; 81159745Snetchildstatic d_mmap_t fb_mmap; 82171910Ssanpei 83171910Ssanpeistatic struct cdevsw fb_cdevsw = { 84171910Ssanpei .d_version = D_VERSION, 85171910Ssanpei .d_flags = D_NEEDGIANT, 86134046Ssimon .d_open = fb_open, 87134046Ssimon .d_close = fb_close, 88159745Snetchild .d_read = fb_read, 89159745Snetchild .d_write = fb_write, 90134046Ssimon .d_ioctl = fb_ioctl, 91149230Skeramida .d_mmap = fb_mmap, 92149236Skeramida .d_name = "fb", 93184182Sn_hibma}; 94184182Sn_hibma 95239090Sglebiusstatic int framebuffer_dev_unit = 0; 96239090Sglebius 97134046Ssimonstatic int 9895065Strhodesfb_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 9995065Strhodes{ 10095065Strhodes 10195065Strhodes return (0); 10295065Strhodes} 10395065Strhodes 10495065Strhodesstatic int 10595065Strhodesfb_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 10695065Strhodes{ 10795065Strhodes 10895065Strhodes return (0); 10995065Strhodes} 11097593Sru 11197593Srustatic int 11295065Strhodesfb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 11395065Strhodes struct thread *td) 11495065Strhodes{ 11595065Strhodes struct fb_info *info; 116 int error; 117 118 error = 0; 119 info = dev->si_drv1; 120 121 switch (cmd) { 122 case FBIOGTYPE: 123 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 124 break; 125 126 case FBIO_GETWINORG: /* get frame buffer window origin */ 127 *(u_int *)data = 0; 128 break; 129 130 case FBIO_GETDISPSTART: /* get display start address */ 131 ((video_display_start_t *)data)->x = 0; 132 ((video_display_start_t *)data)->y = 0; 133 break; 134 135 case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 136 *(u_int *)data = info->fb_stride; 137 break; 138 139 case FBIO_BLANK: /* blank display */ 140 if (info->setblankmode != NULL) 141 error = info->setblankmode(info->fb_priv, *(int *)data); 142 break; 143 144 default: 145 error = ENOIOCTL; 146 break; 147 } 148 return (error); 149} 150 151static int 152fb_read(struct cdev *dev, struct uio *uio, int ioflag) 153{ 154 155 return (0); /* XXX nothing to read, yet */ 156} 157 158static int 159fb_write(struct cdev *dev, struct uio *uio, int ioflag) 160{ 161 162 return (0); /* XXX nothing written */ 163} 164 165static int 166fb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 167 vm_memattr_t *memattr) 168{ 169 struct fb_info *info; 170 171 info = dev->si_drv1; 172 173 if (info->fb_flags & FB_FLAG_NOMMAP) 174 return (ENODEV); 175 176 if (offset >= 0 && offset < info->fb_size) { 177 if (info->fb_pbase == 0) 178 *paddr = vtophys((uint8_t *)info->fb_vbase + offset); 179 else 180 *paddr = info->fb_pbase + offset; 181 return (0); 182 } 183 return (EINVAL); 184} 185 186static int 187fb_init(struct fb_list_entry *entry, int unit) 188{ 189 struct fb_info *info; 190 191 info = entry->fb_info; 192 entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL, 193 0600, "fb%d", unit); 194 entry->fb_si->si_drv1 = info; 195 info->fb_cdev = entry->fb_si; 196 197 return (0); 198} 199 200int 201fbd_list() 202{ 203 struct fb_list_entry *entry; 204 205 if (LIST_EMPTY(&fb_list_head)) 206 return (ENOENT); 207 208 LIST_FOREACH(entry, &fb_list_head, fb_list) { 209 printf("FB %s @%p\n", entry->fb_info->fb_name, 210 (void *)entry->fb_info->fb_pbase); 211 } 212 213 return (0); 214} 215 216static struct fb_list_entry * 217fbd_find(struct fb_info* info) 218{ 219 struct fb_list_entry *entry, *tmp; 220 221 LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 222 if (entry->fb_info == info) { 223 return (entry); 224 } 225 } 226 227 return (NULL); 228} 229 230int 231fbd_register(struct fb_info* info) 232{ 233 struct fb_list_entry *entry; 234 int err, first; 235 236 first = 0; 237 if (LIST_EMPTY(&fb_list_head)) 238 first++; 239 240 entry = fbd_find(info); 241 if (entry != NULL) { 242 /* XXX Update framebuffer params */ 243 return (0); 244 } 245 246 entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO); 247 entry->fb_info = info; 248 249 LIST_INSERT_HEAD(&fb_list_head, entry, fb_list); 250 251 err = fb_init(entry, framebuffer_dev_unit++); 252 if (err) 253 return (err); 254 255 if (first) { 256 err = vt_fb_attach(info); 257 if (err) 258 return (err); 259 } 260 261 return (0); 262} 263 264int 265fbd_unregister(struct fb_info* info) 266{ 267 struct fb_list_entry *entry, *tmp; 268 269 LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 270 if (entry->fb_info == info) { 271 LIST_REMOVE(entry, fb_list); 272 if (LIST_EMPTY(&fb_list_head)) 273 vt_fb_detach(info); 274 free(entry, M_DEVBUF); 275 return (0); 276 } 277 } 278 279 return (ENOENT); 280} 281 282static void 283register_fb_wrap(void *arg, void *ptr) 284{ 285 286 fbd_register((struct fb_info *)ptr); 287} 288 289static void 290unregister_fb_wrap(void *arg, void *ptr) 291{ 292 293 fbd_unregister((struct fb_info *)ptr); 294} 295 296static void 297fbd_evh_init(void *ctx) 298{ 299 300 EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL, 301 EVENTHANDLER_PRI_ANY); 302 EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL, 303 EVENTHANDLER_PRI_ANY); 304} 305 306/* Newbus methods. */ 307static int 308fbd_probe(device_t dev) 309{ 310 311 return (BUS_PROBE_NOWILDCARD); 312} 313 314static int 315fbd_attach(device_t dev) 316{ 317 struct fbd_softc *sc; 318 int err; 319 320 sc = device_get_softc(dev); 321 322 sc->sc_dev = dev; 323 sc->sc_info = FB_GETINFO(device_get_parent(dev)); 324 if (sc->sc_info == NULL) 325 return (ENXIO); 326 err = fbd_register(sc->sc_info); 327 328 return (err); 329} 330 331static int 332fbd_detach(device_t dev) 333{ 334 struct fbd_softc *sc; 335 int err; 336 337 sc = device_get_softc(dev); 338 339 err = fbd_unregister(sc->sc_info); 340 341 return (err); 342} 343 344static device_method_t fbd_methods[] = { 345 /* Device interface */ 346 DEVMETHOD(device_probe, fbd_probe), 347 DEVMETHOD(device_attach, fbd_attach), 348 DEVMETHOD(device_detach, fbd_detach), 349 350 DEVMETHOD(device_shutdown, bus_generic_shutdown), 351 352 { 0, 0 } 353}; 354 355driver_t fbd_driver = { 356 "fbd", 357 fbd_methods, 358 sizeof(struct fbd_softc) 359}; 360 361devclass_t fbd_devclass; 362 363DRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0); 364DRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0); 365DRIVER_MODULE(fbd, udl, fbd_driver, fbd_devclass, 0, 0); 366MODULE_VERSION(fbd, 1); 367 368