38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/bus.h> 42#include <sys/conf.h> 43#include <sys/kernel.h> 44#include <sys/malloc.h> 45#include <sys/module.h> 46#include <sys/queue.h> 47#include <sys/fbio.h> 48 49#include <machine/bus.h> 50 51#include <dev/vt/vt.h> 52#include <dev/vt/hw/fb/vt_fb.h> 53 54#include "fb_if.h" 55 56LIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head = 57 LIST_HEAD_INITIALIZER(fb_list_head); 58struct fb_list_entry { 59 struct fb_info *fb_info; 60 struct cdev *fb_si; 61 LIST_ENTRY(fb_list_entry) fb_list; 62}; 63 64struct fbd_softc { 65 device_t sc_dev; 66 struct fb_info *sc_info; 67}; 68 69static void fbd_evh_init(void *); 70/* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */ 71SYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL); 72 73static d_open_t fb_open; 74static d_close_t fb_close; 75static d_read_t fb_read; 76static d_write_t fb_write; 77static d_ioctl_t fb_ioctl; 78static d_mmap_t fb_mmap; 79 80static struct cdevsw fb_cdevsw = { 81 .d_version = D_VERSION, 82 .d_flags = D_NEEDGIANT, 83 .d_open = fb_open, 84 .d_close = fb_close, 85 .d_read = fb_read, 86 .d_write = fb_write, 87 .d_ioctl = fb_ioctl, 88 .d_mmap = fb_mmap, 89 .d_name = "fb", 90}; 91 92static int framebuffer_dev_unit = 0; 93 94static int 95fb_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 96{ 97 98 return (0); 99} 100 101static int 102fb_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 103{ 104 105 return (0); 106} 107 108static int 109fb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 110 struct thread *td) 111{ 112 struct fb_info *info; 113 int error; 114 115 error = 0; 116 info = dev->si_drv1; 117 118 switch (cmd) { 119 case FBIOGTYPE: 120 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 121 break; 122 123 case FBIO_GETWINORG: /* get frame buffer window origin */ 124 *(u_int *)data = 0; 125 break; 126 127 case FBIO_GETDISPSTART: /* get display start address */ 128 ((video_display_start_t *)data)->x = 0; 129 ((video_display_start_t *)data)->y = 0; 130 break; 131 132 case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 133 *(u_int *)data = info->fb_stride; 134 break; 135 136 case FBIO_BLANK: /* blank display */ 137 error = 0; /* TODO */ 138 break; 139 140 default: 141 error = ENOIOCTL; 142 break; 143 } 144 return (error); 145} 146 147static int 148fb_read(struct cdev *dev, struct uio *uio, int ioflag) 149{ 150 151 return (0); /* XXX nothing to read, yet */ 152} 153 154static int 155fb_write(struct cdev *dev, struct uio *uio, int ioflag) 156{ 157 158 return (0); /* XXX nothing written */ 159} 160 161static int 162fb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 163 vm_memattr_t *memattr) 164{ 165 struct fb_info *info; 166 167 info = dev->si_drv1; 168 if (offset < info->fb_size) { 169 *paddr = info->fb_pbase + offset; 170 return (0); 171 } 172 return (EINVAL); 173} 174 175 176static void 177vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 178{ 179 180 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 181 *(uint8_t *)(sc->fb_vbase + o) = v; 182} 183 184static void 185vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 186{ 187 188 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 189 *(uint16_t *)(sc->fb_vbase + o) = v; 190} 191 192static void 193vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 194{ 195 196 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 197 *(uint32_t *)(sc->fb_vbase + o) = v; 198} 199 200static void 201vt_fb_mem_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from, 202 uint32_t size) 203{ 204 205 memmove((void *)(sc->fb_vbase + offset_to), (void *)(sc->fb_vbase + 206 offset_from), size); 207} 208 209static void 210vt_fb_indir_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 211{ 212 213 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 214 sc->fb_write(sc->fb_priv, o, &v, 1); 215} 216 217static void 218vt_fb_indir_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 219{ 220 221 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 222 sc->fb_write(sc->fb_priv, o, &v, 2); 223} 224 225static void 226vt_fb_indir_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 227{ 228 229 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 230 sc->fb_write(sc->fb_priv, o, &v, 4); 231} 232 233static void 234vt_fb_indir_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from, 235 uint32_t size) 236{ 237 238 sc->copy(sc->fb_priv, offset_to, offset_from, size); 239} 240 241int 242fb_probe(struct fb_info *info) 243{ 244 245 if (info->fb_size == 0) 246 return (ENXIO); 247 248 if (info->fb_write != NULL) { 249 if (info->fb_write == NULL) { 250 return (EINVAL); 251 } 252 info->fb_flags |= FB_FLAG_NOMMAP; 253 info->wr1 = &vt_fb_indir_wr1; 254 info->wr2 = &vt_fb_indir_wr2; 255 info->wr4 = &vt_fb_indir_wr4; 256 info->copy = &vt_fb_indir_copy; 257 } else if (info->fb_vbase != 0) { 258 if (info->fb_pbase == 0) 259 info->fb_flags |= FB_FLAG_NOMMAP; 260 info->wr1 = &vt_fb_mem_wr1; 261 info->wr2 = &vt_fb_mem_wr2; 262 info->wr4 = &vt_fb_mem_wr4; 263 info->copy = &vt_fb_mem_copy; 264 } else 265 return (ENXIO); 266 267 return (0); 268} 269 270 271static int 272fb_init(struct fb_list_entry *entry, int unit) 273{ 274 struct fb_info *info; 275 276 info = entry->fb_info; 277 entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL, 278 0600, "fb%d", unit); 279 entry->fb_si->si_drv1 = info; 280 281 return (0); 282} 283 284int 285fbd_list() 286{ 287 struct fb_list_entry *entry; 288 289 if (LIST_EMPTY(&fb_list_head)) 290 return (ENOENT); 291 292 LIST_FOREACH(entry, &fb_list_head, fb_list) { 293 printf("FB %s @%p\n", entry->fb_info->fb_name, 294 (void *)entry->fb_info->fb_pbase); 295 } 296 297 return (0); 298} 299 300static struct fb_list_entry * 301fbd_find(struct fb_info* info) 302{ 303 struct fb_list_entry *entry, *tmp; 304 305 LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 306 if (entry->fb_info == info) { 307 return (entry); 308 } 309 } 310 311 return (NULL); 312} 313 314int 315fbd_register(struct fb_info* info) 316{ 317 struct fb_list_entry *entry; 318 int err, first; 319 320 first = 0; 321 if (LIST_EMPTY(&fb_list_head)) 322 first++; 323 324 entry = fbd_find(info); 325 if (entry != NULL) { 326 /* XXX Update framebuffer params */ 327 return (0); 328 } 329 330 err = fb_probe(info); 331 if (err) 332 return (err); 333 334 entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO); 335 entry->fb_info = info; 336 337 LIST_INSERT_HEAD(&fb_list_head, entry, fb_list); 338 339 err = fb_init(entry, framebuffer_dev_unit++); 340 if (err) 341 return (err); 342 343 if (first) 344 vt_fb_attach(info); 345 346 return (0); 347} 348 349int 350fbd_unregister(struct fb_info* info) 351{ 352 struct fb_list_entry *entry, *tmp; 353 354 LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 355 if (entry->fb_info == info) { 356 LIST_REMOVE(entry, fb_list); 357 free(entry, M_DEVBUF); 358 return (0); 359 } 360 } 361 362 return (ENOENT); 363} 364 365static void 366register_fb_wrap(void *arg, void *ptr) 367{ 368 369 fbd_register((struct fb_info *)ptr); 370} 371 372static void 373unregister_fb_wrap(void *arg, void *ptr) 374{ 375 376 fbd_unregister((struct fb_info *)ptr); 377} 378 379static void 380fbd_evh_init(void *ctx) 381{ 382 383 EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL, 384 EVENTHANDLER_PRI_ANY); 385 EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL, 386 EVENTHANDLER_PRI_ANY); 387} 388 389/* Newbus methods. */ 390static int 391fbd_probe(device_t dev) 392{ 393 394 return (BUS_PROBE_NOWILDCARD); 395} 396 397static int 398fbd_attach(device_t dev) 399{ 400 struct fbd_softc *sc; 401 int err; 402 403 sc = device_get_softc(dev); 404 405 sc->sc_dev = dev; 406 sc->sc_info = FB_GETINFO(device_get_parent(dev)); 407 if (sc->sc_info == NULL) 408 return (ENXIO); 409 err = fbd_register(sc->sc_info); 410 411 return (err); 412} 413 414static int 415fbd_detach(device_t dev) 416{ 417 struct fbd_softc *sc; 418 int err; 419 420 sc = device_get_softc(dev); 421 422 err = fbd_unregister(sc->sc_info); 423 424 return (err); 425} 426 427static int 428fbd_suspend(device_t dev) 429{ 430 431 vt_fb_suspend(); 432 return (bus_generic_suspend(dev)); 433} 434 435static int 436fbd_resume(device_t dev) 437{ 438 439 vt_fb_resume(); 440 return (bus_generic_resume(dev)); 441} 442 443static device_method_t fbd_methods[] = { 444 /* Device interface */ 445 DEVMETHOD(device_probe, fbd_probe), 446 DEVMETHOD(device_attach, fbd_attach), 447 DEVMETHOD(device_detach, fbd_detach), 448 449 DEVMETHOD(device_shutdown, bus_generic_shutdown), 450 DEVMETHOD(device_suspend, fbd_suspend), 451 DEVMETHOD(device_resume, fbd_resume), 452 453 { 0, 0 } 454}; 455 456driver_t fbd_driver = { 457 "fbd", 458 fbd_methods, 459 sizeof(struct fbd_softc) 460}; 461 462devclass_t fbd_devclass; 463 464DRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0); 465DRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0); 466MODULE_VERSION(fbd, 1); 467
| 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/bus.h> 42#include <sys/conf.h> 43#include <sys/kernel.h> 44#include <sys/malloc.h> 45#include <sys/module.h> 46#include <sys/queue.h> 47#include <sys/fbio.h> 48 49#include <machine/bus.h> 50 51#include <dev/vt/vt.h> 52#include <dev/vt/hw/fb/vt_fb.h> 53 54#include "fb_if.h" 55 56LIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head = 57 LIST_HEAD_INITIALIZER(fb_list_head); 58struct fb_list_entry { 59 struct fb_info *fb_info; 60 struct cdev *fb_si; 61 LIST_ENTRY(fb_list_entry) fb_list; 62}; 63 64struct fbd_softc { 65 device_t sc_dev; 66 struct fb_info *sc_info; 67}; 68 69static void fbd_evh_init(void *); 70/* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */ 71SYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL); 72 73static d_open_t fb_open; 74static d_close_t fb_close; 75static d_read_t fb_read; 76static d_write_t fb_write; 77static d_ioctl_t fb_ioctl; 78static d_mmap_t fb_mmap; 79 80static struct cdevsw fb_cdevsw = { 81 .d_version = D_VERSION, 82 .d_flags = D_NEEDGIANT, 83 .d_open = fb_open, 84 .d_close = fb_close, 85 .d_read = fb_read, 86 .d_write = fb_write, 87 .d_ioctl = fb_ioctl, 88 .d_mmap = fb_mmap, 89 .d_name = "fb", 90}; 91 92static int framebuffer_dev_unit = 0; 93 94static int 95fb_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 96{ 97 98 return (0); 99} 100 101static int 102fb_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 103{ 104 105 return (0); 106} 107 108static int 109fb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 110 struct thread *td) 111{ 112 struct fb_info *info; 113 int error; 114 115 error = 0; 116 info = dev->si_drv1; 117 118 switch (cmd) { 119 case FBIOGTYPE: 120 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 121 break; 122 123 case FBIO_GETWINORG: /* get frame buffer window origin */ 124 *(u_int *)data = 0; 125 break; 126 127 case FBIO_GETDISPSTART: /* get display start address */ 128 ((video_display_start_t *)data)->x = 0; 129 ((video_display_start_t *)data)->y = 0; 130 break; 131 132 case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 133 *(u_int *)data = info->fb_stride; 134 break; 135 136 case FBIO_BLANK: /* blank display */ 137 error = 0; /* TODO */ 138 break; 139 140 default: 141 error = ENOIOCTL; 142 break; 143 } 144 return (error); 145} 146 147static int 148fb_read(struct cdev *dev, struct uio *uio, int ioflag) 149{ 150 151 return (0); /* XXX nothing to read, yet */ 152} 153 154static int 155fb_write(struct cdev *dev, struct uio *uio, int ioflag) 156{ 157 158 return (0); /* XXX nothing written */ 159} 160 161static int 162fb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, 163 vm_memattr_t *memattr) 164{ 165 struct fb_info *info; 166 167 info = dev->si_drv1; 168 if (offset < info->fb_size) { 169 *paddr = info->fb_pbase + offset; 170 return (0); 171 } 172 return (EINVAL); 173} 174 175 176static void 177vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 178{ 179 180 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 181 *(uint8_t *)(sc->fb_vbase + o) = v; 182} 183 184static void 185vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 186{ 187 188 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 189 *(uint16_t *)(sc->fb_vbase + o) = v; 190} 191 192static void 193vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 194{ 195 196 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 197 *(uint32_t *)(sc->fb_vbase + o) = v; 198} 199 200static void 201vt_fb_mem_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from, 202 uint32_t size) 203{ 204 205 memmove((void *)(sc->fb_vbase + offset_to), (void *)(sc->fb_vbase + 206 offset_from), size); 207} 208 209static void 210vt_fb_indir_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 211{ 212 213 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 214 sc->fb_write(sc->fb_priv, o, &v, 1); 215} 216 217static void 218vt_fb_indir_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 219{ 220 221 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 222 sc->fb_write(sc->fb_priv, o, &v, 2); 223} 224 225static void 226vt_fb_indir_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 227{ 228 229 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 230 sc->fb_write(sc->fb_priv, o, &v, 4); 231} 232 233static void 234vt_fb_indir_copy(struct fb_info *sc, uint32_t offset_to, uint32_t offset_from, 235 uint32_t size) 236{ 237 238 sc->copy(sc->fb_priv, offset_to, offset_from, size); 239} 240 241int 242fb_probe(struct fb_info *info) 243{ 244 245 if (info->fb_size == 0) 246 return (ENXIO); 247 248 if (info->fb_write != NULL) { 249 if (info->fb_write == NULL) { 250 return (EINVAL); 251 } 252 info->fb_flags |= FB_FLAG_NOMMAP; 253 info->wr1 = &vt_fb_indir_wr1; 254 info->wr2 = &vt_fb_indir_wr2; 255 info->wr4 = &vt_fb_indir_wr4; 256 info->copy = &vt_fb_indir_copy; 257 } else if (info->fb_vbase != 0) { 258 if (info->fb_pbase == 0) 259 info->fb_flags |= FB_FLAG_NOMMAP; 260 info->wr1 = &vt_fb_mem_wr1; 261 info->wr2 = &vt_fb_mem_wr2; 262 info->wr4 = &vt_fb_mem_wr4; 263 info->copy = &vt_fb_mem_copy; 264 } else 265 return (ENXIO); 266 267 return (0); 268} 269 270 271static int 272fb_init(struct fb_list_entry *entry, int unit) 273{ 274 struct fb_info *info; 275 276 info = entry->fb_info; 277 entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL, 278 0600, "fb%d", unit); 279 entry->fb_si->si_drv1 = info; 280 281 return (0); 282} 283 284int 285fbd_list() 286{ 287 struct fb_list_entry *entry; 288 289 if (LIST_EMPTY(&fb_list_head)) 290 return (ENOENT); 291 292 LIST_FOREACH(entry, &fb_list_head, fb_list) { 293 printf("FB %s @%p\n", entry->fb_info->fb_name, 294 (void *)entry->fb_info->fb_pbase); 295 } 296 297 return (0); 298} 299 300static struct fb_list_entry * 301fbd_find(struct fb_info* info) 302{ 303 struct fb_list_entry *entry, *tmp; 304 305 LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 306 if (entry->fb_info == info) { 307 return (entry); 308 } 309 } 310 311 return (NULL); 312} 313 314int 315fbd_register(struct fb_info* info) 316{ 317 struct fb_list_entry *entry; 318 int err, first; 319 320 first = 0; 321 if (LIST_EMPTY(&fb_list_head)) 322 first++; 323 324 entry = fbd_find(info); 325 if (entry != NULL) { 326 /* XXX Update framebuffer params */ 327 return (0); 328 } 329 330 err = fb_probe(info); 331 if (err) 332 return (err); 333 334 entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO); 335 entry->fb_info = info; 336 337 LIST_INSERT_HEAD(&fb_list_head, entry, fb_list); 338 339 err = fb_init(entry, framebuffer_dev_unit++); 340 if (err) 341 return (err); 342 343 if (first) 344 vt_fb_attach(info); 345 346 return (0); 347} 348 349int 350fbd_unregister(struct fb_info* info) 351{ 352 struct fb_list_entry *entry, *tmp; 353 354 LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { 355 if (entry->fb_info == info) { 356 LIST_REMOVE(entry, fb_list); 357 free(entry, M_DEVBUF); 358 return (0); 359 } 360 } 361 362 return (ENOENT); 363} 364 365static void 366register_fb_wrap(void *arg, void *ptr) 367{ 368 369 fbd_register((struct fb_info *)ptr); 370} 371 372static void 373unregister_fb_wrap(void *arg, void *ptr) 374{ 375 376 fbd_unregister((struct fb_info *)ptr); 377} 378 379static void 380fbd_evh_init(void *ctx) 381{ 382 383 EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL, 384 EVENTHANDLER_PRI_ANY); 385 EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL, 386 EVENTHANDLER_PRI_ANY); 387} 388 389/* Newbus methods. */ 390static int 391fbd_probe(device_t dev) 392{ 393 394 return (BUS_PROBE_NOWILDCARD); 395} 396 397static int 398fbd_attach(device_t dev) 399{ 400 struct fbd_softc *sc; 401 int err; 402 403 sc = device_get_softc(dev); 404 405 sc->sc_dev = dev; 406 sc->sc_info = FB_GETINFO(device_get_parent(dev)); 407 if (sc->sc_info == NULL) 408 return (ENXIO); 409 err = fbd_register(sc->sc_info); 410 411 return (err); 412} 413 414static int 415fbd_detach(device_t dev) 416{ 417 struct fbd_softc *sc; 418 int err; 419 420 sc = device_get_softc(dev); 421 422 err = fbd_unregister(sc->sc_info); 423 424 return (err); 425} 426 427static int 428fbd_suspend(device_t dev) 429{ 430 431 vt_fb_suspend(); 432 return (bus_generic_suspend(dev)); 433} 434 435static int 436fbd_resume(device_t dev) 437{ 438 439 vt_fb_resume(); 440 return (bus_generic_resume(dev)); 441} 442 443static device_method_t fbd_methods[] = { 444 /* Device interface */ 445 DEVMETHOD(device_probe, fbd_probe), 446 DEVMETHOD(device_attach, fbd_attach), 447 DEVMETHOD(device_detach, fbd_detach), 448 449 DEVMETHOD(device_shutdown, bus_generic_shutdown), 450 DEVMETHOD(device_suspend, fbd_suspend), 451 DEVMETHOD(device_resume, fbd_resume), 452 453 { 0, 0 } 454}; 455 456driver_t fbd_driver = { 457 "fbd", 458 fbd_methods, 459 sizeof(struct fbd_softc) 460}; 461 462devclass_t fbd_devclass; 463 464DRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0); 465DRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0); 466MODULE_VERSION(fbd, 1); 467
|