fbd.c revision 257013
1/*- 2 * Copyright (c) 2013 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Aleksandr Rybalko under sponsorship from the 6 * FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: user/ed/newcons/sys/dev/fb/fbd.c 257013 2013-10-23 19:45:14Z ray $ 30 */ 31 32/* Generic framebuffer */ 33/* TODO unlink from VT(9) */ 34/* TODO done normal /dev/fb methods */ 35 36#include <sys/cdefs.h> 37__FBSDID("$FreeBSD: user/ed/newcons/sys/dev/fb/fbd.c 257013 2013-10-23 19:45:14Z ray $"); 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/conf.h> 42#include <sys/kernel.h> 43#include <sys/malloc.h> 44#include <sys/queue.h> 45#include <sys/fbio.h> 46#include <dev/vt/hw/fb/vt_fb.h> 47 48LIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head = 49 LIST_HEAD_INITIALIZER(fb_list_head); 50struct fb_list_entry { 51 struct fb_info *fb_info; 52 struct cdev *fb_si; 53 LIST_ENTRY(fb_list_entry) fb_list; 54}; 55 56static void fbd_evh_init(void *); 57/* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */ 58SYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL); 59 60static d_open_t fb_open; 61static d_close_t fb_close; 62static d_read_t fb_read; 63static d_write_t fb_write; 64static d_ioctl_t fb_ioctl; 65static d_mmap_t fb_mmap; 66 67static struct cdevsw fb_cdevsw = { 68 .d_version = D_VERSION, 69 .d_flags = D_NEEDGIANT, 70 .d_open = fb_open, 71 .d_close = fb_close, 72 .d_read = fb_read, 73 .d_write = fb_write, 74 .d_ioctl = fb_ioctl, 75 .d_mmap = fb_mmap, 76 .d_name = "fb", 77}; 78 79static int framebuffer_dev_unit = 0; 80 81static int 82fb_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 83{ 84 85 return (0); 86} 87 88static int 89fb_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 90{ 91 92 return (0); 93} 94 95static int 96fb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 97 struct thread *td) 98{ 99 100 return (0); 101} 102 103static int 104fb_read(struct cdev *dev, struct uio *uio, int ioflag) 105{ 106 107 return (0); /* XXX nothing to read, yet */ 108} 109 110static int 111fb_write(struct cdev *dev, struct uio *uio, int ioflag) 112{ 113 114 return (0); /* XXX nothing written */ 115} 116 117static int 118fb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 119 vm_memattr_t *memattr) 120{ 121 struct fb_info *info; 122 123 info = dev->si_drv1; 124 if (offset < info->fb_size) { 125 *paddr = info->fb_pbase + offset; 126 return (0); 127 } 128 return (EINVAL); 129} 130 131 132static void 133vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 134{ 135 136 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 137 *(uint8_t *)(sc->fb_vbase + o) = v; 138} 139 140static void 141vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 142{ 143 144 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 145 *(uint16_t *)(sc->fb_vbase + o) = v; 146} 147 148static void 149vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 150{ 151 152 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 153 *(uint32_t *)(sc->fb_vbase + o) = v; 154} 155 156static void 157vt_fb_mem_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from, 158 uint32_t size) 159{ 160 161 memmove((void *)(sc->fb_vbase + offset_to), (void *)(sc->fb_vbase + 162 offset_from), size); 163} 164 165static void 166vt_fb_indir_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 167{ 168 169 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 170 sc->fb_write(sc->fb_priv, o, &v, 1); 171} 172 173static void 174vt_fb_indir_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 175{ 176 177 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 178 sc->fb_write(sc->fb_priv, o, &v, 2); 179} 180 181static void 182vt_fb_indir_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 183{ 184 185 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 186 sc->fb_write(sc->fb_priv, o, &v, 4); 187} 188 189static void 190vt_fb_indir_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from, 191 uint32_t size) 192{ 193 194 sc->copy(sc->fb_priv, offset_to, offset_from, size); 195} 196 197static int 198fb_probe(struct fb_info *info) 199{ 200 201 if (info->fb_size == 0) 202 return (ENXIO); 203 204 if (info->fb_write != NULL) { 205 if (info->fb_write == NULL) { 206 return (EINVAL); 207 } 208 info->fb_flags |= FB_FLAG_NOMMAP; 209 info->wr1 = &vt_fb_indir_wr1; 210 info->wr2 = &vt_fb_indir_wr2; 211 info->wr4 = &vt_fb_indir_wr4; 212 info->copy = &vt_fb_indir_copy; 213 } else if (info->fb_vbase != 0) { 214 if (info->fb_pbase == 0) 215 info->fb_flags |= FB_FLAG_NOMMAP; 216 info->wr1 = &vt_fb_mem_wr1; 217 info->wr2 = &vt_fb_mem_wr2; 218 info->wr4 = &vt_fb_mem_wr4; 219 info->copy = &vt_fb_mem_copy; 220 } else 221 return (ENXIO); 222 223 return (0); 224} 225 226 227static int 228fb_init(struct fb_list_entry *entry, int unit) 229{ 230 struct fb_info *info; 231 232 info = entry->fb_info; 233 entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL, 234 0600, "fb%d", unit); 235 entry->fb_si->si_drv1 = info; 236 237 return (0); 238} 239 240int 241fbd_list() 242{ 243 struct fb_list_entry *entry; 244 245 if (LIST_EMPTY(&fb_list_head)) 246 return (ENOENT); 247 248 LIST_FOREACH(entry, &fb_list_head, fb_list) { 249 printf("FB %s @%p\n", entry->fb_info->fb_name, 250 (void *)entry->fb_info->fb_pbase); 251 } 252 253 return (0); 254} 255 256static struct fb_list_entry * 257fbd_find(struct fb_info* info) 258{ 259 struct fb_list_entry *entry, *tmp; 260 261 LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 262 if (entry->fb_info == info) { 263 return (entry); 264 } 265 } 266 267 return (NULL); 268} 269 270int 271fbd_register(struct fb_info* info) 272{ 273 struct fb_list_entry *entry; 274 int err, first; 275 276 first = 0; 277 if (LIST_EMPTY(&fb_list_head)) 278 first++; 279 280 entry = fbd_find(info); 281 if (entry != NULL) { 282 /* XXX Update framebuffer params */ 283 return (0); 284 } 285 286 err = fb_probe(info); 287 if (err) 288 return (err); 289 290 entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO); 291 entry->fb_info = info; 292 293 LIST_INSERT_HEAD(&fb_list_head, entry, fb_list); 294 295 err = fb_init(entry, framebuffer_dev_unit++); 296 if (err) 297 return (err); 298 299 if (first) 300 vt_fb_attach(info); 301 302 return (0); 303} 304 305int 306fbd_unregister(struct fb_info* info) 307{ 308 struct fb_list_entry *entry, *tmp; 309 310 LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 311 if (entry->fb_info == info) { 312 LIST_REMOVE(entry, fb_list); 313 free(entry, M_DEVBUF); 314 return (0); 315 } 316 } 317 318 return (ENOENT); 319} 320 321static void 322register_fb_wrap(void *arg, void *ptr) 323{ 324 325 fbd_register((struct fb_info *)ptr); 326} 327 328static void 329unregister_fb_wrap(void *arg, void *ptr) 330{ 331 332 fbd_unregister((struct fb_info *)ptr); 333} 334 335static void 336fbd_evh_init(void *ctx) 337{ 338 339 EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL, 340 EVENTHANDLER_PRI_ANY); 341 EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL, 342 EVENTHANDLER_PRI_ANY); 343} 344