1 /* 2 * Copyright (c) 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc. 7 * 8 * %sccs.include.redist.c% 9 * 10 * from: $Hdr: fb.c,v 4.300 91/06/27 20:43:06 root Rel41 $ SONY 11 * 12 * @(#)fb.c 7.3 (Berkeley) 03/09/93 13 */ 14 15 #include "fb.h" 16 #if NFB > 0 17 /* 18 * Frame buffer driver 19 */ 20 21 #include <sys/types.h> 22 #include <machine/pte.h> 23 #include <machine/cpu.h> 24 25 #include <sys/param.h> 26 #include <sys/proc.h> 27 #include <sys/user.h> 28 #include <sys/buf.h> 29 #include <vm/vm.h> 30 #include <sys/systm.h> 31 #include <sys/map.h> 32 #include <sys/uio.h> 33 #include <sys/kernel.h> 34 35 #include <news3400/iop/framebuf.h> 36 #include <news3400/iop/fbreg.h> 37 #include <news3400/iodev/ioptohb.h> 38 39 #ifdef CPU_SINGLE 40 #include <news3400/hbdev/hbvar.h> 41 42 #define ipc_phys(x) (caddr_t)((int)(x)) 43 #define ipc_log(x) (caddr_t)((int)(x) | 0x80000000) 44 45 #define iop_driver hb_driver 46 #define iop_device hb_device 47 48 extern rop_xint(); 49 #else /* CPU_SINGLE */ 50 #include <news3400/iop/iopvar.h> 51 52 #ifdef IPC_MRX 53 #include "../ipc/newsipc.h" 54 55 #ifdef mips 56 #define ipc_phys(x) K0_TT0(x) 57 #define ipc_log(x) TT0_K0(x) 58 #else 59 #define ipc_phys(x) (caddr_t)((int)(x) & ~0x80000000) 60 #define ipc_log(x) (caddr_t)((int)(x) | 0x80000000) 61 #endif 62 63 static int port_fb, port_fb_iop; 64 #endif /* IPC_MRX */ 65 #endif /* CPU_SINGLE */ 66 67 #define FB_USED 1 68 #define VIDEO_USED 2 69 70 /* 71 * driver definition 72 */ 73 int fbprobe(), fbattach(); 74 75 struct iop_device *fbinfo[NFB]; 76 struct iop_driver fbdriver = 77 #ifdef CPU_SINGLE 78 { fbprobe, 0, fbattach, 0, 0, "fb", fbinfo, "fbc", 0, 0 }; 79 #else 80 { fbprobe, 0, fbattach, 0, "fb", fbinfo }; 81 #endif 82 83 /* static */ 84 static struct fb_softc fb_softc[NFB]; 85 static struct fbreg fbreg[NFB]; 86 static int fbstate; 87 static struct fbreg *last_fb; 88 89 static char *devname[] = { 90 /* 0*/ "", 91 /* 1*/ "NWB-512", 92 /* 2*/ "NWB-225", 93 /* 3*/ "POP-MONO", 94 /* 4*/ "POP-COLOR", 95 /* 5*/ "NWB-514", 96 /* 6*/ "NWB-251", 97 /* 7*/ "LCD-MONO", 98 /* 8*/ "LDC-COLOR", 99 /* 9*/ "NWB-518", 100 /*10*/ "NWB-252", 101 /*11*/ "NWB-253", 102 /*12*/ "NWB-254", 103 /*13*/ "NWB-255", 104 /*14*/ "SLB-101", 105 /*15*/ "NWB-256", 106 /*16*/ "NWB-257", 107 }; 108 109 static void fblock(), fbunlock(), fbreset(); 110 static int fbinit(); 111 112 #ifdef CPU_DOUBLE 113 #ifdef USE_RAW_INTR 114 115 #include "../mrx/h/ipc.h" 116 117 #ifdef mips 118 # define FB_ADDR &IPC_ARG(&ipc_block, ARG_CPU, 4) 119 #else 120 # define FB_ADDR &IPC_ARG(&ipc_block, ARG_CPU0, 4) 121 # define volatile 122 #endif 123 124 typedef struct fbreg *fbregp; 125 int fb_waiting; 126 127 Xfb_intr(chan, arg) 128 int chan; 129 int arg; 130 { 131 132 intrcnt[INTR_BITMAP]++; 133 if (fb_waiting) { 134 fb_waiting = 0; 135 wakeup((caddr_t)&fb_waiting); 136 } 137 } 138 139 static void 140 fbwait() 141 { 142 int s = splfb(); 143 144 while (*(volatile fbregp *)FB_ADDR) { 145 fb_waiting = 1; 146 sleep((caddr_t)&fb_waiting, FBPRI); 147 } 148 (void) splx(s); 149 } 150 151 void 152 fbstart(fbp, wait) 153 struct fbreg *fbp; 154 int wait; 155 { 156 157 fbwait(); 158 *(volatile fbregp *)FB_ADDR = 159 #ifdef mips 160 (volatile fbregp)ipc_phys(MACH_UNCACHED_TO_CACHED(fbp)); 161 #else 162 (volatile fbregp)ipc_phys(fbp); 163 #endif 164 if (wait) 165 fbwait(); 166 } 167 168 #else /* USE_RAW_INTR */ 169 170 void 171 fbstart(fbp, wait) 172 register struct fbreg *fbp; 173 int wait; 174 { 175 int s = splfb(); 176 177 #ifdef IPC_MRX 178 msg_send(port_fb_iop, port_fb, fbp, sizeof(*fbp), MSG_INDIRECT); 179 #endif 180 181 last_fb = fbp; 182 if (wait) { 183 fbstate |= FB_WAIT; 184 sleep((caddr_t)fbreg, FBPRI); 185 } else { 186 fbstate |= FB_DELAY; 187 } 188 splx(s); 189 } 190 191 void 192 fbcint(arg) 193 int arg; 194 { 195 196 intrcnt[INTR_BITMAP]++; 197 198 #ifdef IPC_MRX 199 msg_recv(arg, NULL, NULL, NULL, 0); 200 #ifdef mips 201 clean_dcache((caddr_t)last_fb, sizeof(struct fbreg)); 202 #endif 203 #endif /* IPC_MRX */ 204 205 if (fbstate & FB_WAIT) { 206 fbstate &= ~FB_WAIT; 207 wakeup((caddr_t)fbreg); 208 } else if (fbstate & FB_DELAY) { 209 fbstate &= ~FB_DELAY; 210 } else if (fbstate & FB_DELAY2) { 211 fbstate &= ~(FB_BUSY|FB_DELAY2); 212 if (fbstate & FB_WANTED) { 213 fbstate &= ~FB_WANTED; 214 wakeup((caddr_t)&fbstate); 215 } 216 } 217 return; 218 } 219 #endif /* USE_RAW_INTR */ 220 #endif /* CPU_DOUBLE */ 221 222 /* ARGSUSED */ 223 fbprobe(ii) 224 struct iop_device *ii; 225 { 226 register int unit = ii->ii_unit; 227 register struct fb_softc *fb = &fb_softc[unit]; 228 #if defined(IPC_MRX) && defined(mips) 229 register struct fbreg *fbp = 230 (struct fbreg *)MACH_CACHED_TO_UNCACHED(&fbreg[unit]); 231 #else 232 register struct fbreg *fbp = &fbreg[unit]; 233 #endif 234 235 #ifdef CPU_SINGLE 236 if (unit == 0) 237 register_hb_intr2(rop_xint, ii->ii_unit, ii->ii_intr); 238 #endif 239 240 #ifdef IPC_MRX 241 if (port_fb_iop <= 0) { 242 #ifdef USE_RAW_INTR 243 register_ipcintr(4, Xfb_intr); 244 #endif 245 port_fb_iop = object_query("framebuf"); 246 if (port_fb_iop <= 0) { 247 return (0); 248 } 249 #ifndef USE_RAW_INTR 250 port_fb = port_create("@port_fb", fbcint, -1); 251 #endif 252 } 253 #endif /* IPC_MRX */ 254 255 fbp->fb_command = FB_CPROBE; 256 fbp->fb_device = 0; 257 fbp->fb_unit = unit; 258 fbp->fb_data = -1; 259 fbstart(fbp, 1); 260 261 if ((fb->fbs_device = fbp->fb_data) == -1) 262 return (0); 263 else 264 return (-1); 265 } 266 267 /* ARGSUSED */ 268 fbattach(ii) 269 struct iop_device *ii; 270 { 271 register int unit = ii->ii_unit; 272 register struct fb_softc *fb = &fb_softc[unit]; 273 #if defined(IPC_MRX) && defined(mips) 274 register struct fbreg *fbp = 275 (struct fbreg *)MACH_CACHED_TO_UNCACHED(&fbreg[unit]); 276 #else 277 register struct fbreg *fbp = &fbreg[unit]; 278 #endif 279 280 fbp->fb_command = FB_CATTACH; 281 fbp->fb_device = fb->fbs_device; 282 fbstart(fbp, 1); 283 fb->fbs_type = fbp->fb_scrtype; 284 285 if (fb->fbs_type.type) { 286 fb->fbs_state = 0; 287 fb->fbs_flag = 0; 288 printf("fb%d: %s", unit, 289 (fb->fbs_type.type < sizeof(devname)/sizeof(*devname)) 290 ? devname[fb->fbs_type.type] : "UNKNOWN"); 291 printf(" (%d x %d %d plane)\n", 292 fb->fbs_type.visiblerect.extent.x, 293 fb->fbs_type.visiblerect.extent.y, 294 fb->fbs_type.plane); 295 } 296 } 297 298 /*ARGSUSED*/ 299 fbopen(dev, flag) 300 dev_t dev; 301 int flag; 302 { 303 register int unit = FBUNIT(dev); 304 register struct fb_softc *fb = &fb_softc[unit]; 305 register struct iop_device *ii; 306 #if defined(IPC_MRX) && defined(mips) 307 register struct fbreg *fbp = 308 (struct fbreg *)MACH_CACHED_TO_UNCACHED(&fbreg[unit]); 309 #else 310 register struct fbreg *fbp = &fbreg[unit]; 311 #endif 312 313 if (unit >= NFB || (ii = fbinfo[unit]) == 0 || ii->ii_alive == 0) 314 return (ENXIO); 315 if (fb->fbs_flag && !FBVIDEO(dev)) 316 return (EBUSY); 317 318 if (fb->fbs_state == 0) { 319 fbp->fb_device = fb->fbs_device; 320 if(fbinit(fbp)) 321 return (EBUSY); 322 } 323 324 fb->fbs_state |= FBVIDEO(dev) ? VIDEO_USED : FB_USED; 325 326 return (0); 327 } 328 329 /*ARGSUSED*/ 330 fbclose(dev, flag) 331 dev_t dev; 332 int flag; 333 { 334 register int unit = FBUNIT(dev); 335 register struct fb_softc *fb = &fb_softc[unit]; 336 register struct iop_device *ii; 337 #if defined(IPC_MRX) && defined(mips) 338 register struct fbreg *fbp = 339 (struct fbreg *)MACH_CACHED_TO_UNCACHED(&fbreg[unit]); 340 #else 341 register struct fbreg *fbp = &fbreg[unit]; 342 #endif 343 344 if (unit >= NFB || (ii = fbinfo[unit]) == 0 || ii->ii_alive == 0) 345 return (ENXIO); 346 347 if (fb->fbs_state == 0) 348 return(0); 349 350 if(!FBVIDEO(dev)) 351 fb->fbs_flag = 0; 352 353 fb->fbs_state &= ~(FBVIDEO(dev) ? VIDEO_USED : FB_USED); 354 355 if (fb->fbs_state == 0) { 356 fbp->fb_device = fb->fbs_device; 357 fbreset(fbp); 358 } 359 360 return (0); 361 } 362 363 fbioctl(dev, cmd, data, flag) 364 dev_t dev; 365 caddr_t data; 366 { 367 register int unit = FBUNIT(dev); 368 register struct fb_softc *fb = &fb_softc[unit]; 369 register struct iop_device *ii; 370 register int error = 0; 371 #if defined(IPC_MRX) && defined(mips) 372 register struct fbreg *fbp = 373 (struct fbreg *)MACH_CACHED_TO_UNCACHED(&fbreg[unit]); 374 #else 375 register struct fbreg *fbp = &fbreg[unit]; 376 #endif 377 378 if (unit >= NFB || (ii = fbinfo[unit]) == 0 || ii->ii_alive == 0) 379 return (ENXIO); 380 381 fblock(); 382 383 fbp->fb_device = fb->fbs_device; 384 385 switch (cmd) { 386 case FBIOCENABLE: 387 fb->fbs_flag = 0; 388 break; 389 case FBIOCDISABLE: 390 fb->fbs_flag = 1; 391 break; 392 case FBIOCAUTODIM: 393 fbp->fb_command = FB_CAUTODIM; 394 fbp->fb_data = *((int *)data); 395 fbstart(fbp, 0); 396 break; 397 case FBIOCSETDIM: 398 fbp->fb_command = FB_CSETDIM; 399 fbp->fb_data = *((int*)data); 400 fbstart(fbp, 0); 401 break; 402 case FBIOCGETDIM: 403 fbp->fb_command = FB_CGETDIM; 404 fbstart(fbp, 1); 405 *((int*)data) = fbp->fb_data; 406 break; 407 case FBIOCBITBLT: 408 error = fbbitblt(fbp, (sBitblt *)data); 409 break; 410 case FBIOCNBITBLT: 411 error = fbnbitblt(fbp, (lBitblt *)data, UIO_USERSPACE); 412 break; 413 case FBIOCBATCHBITBLT: 414 error = fbbatchbitblt(fbp, (sBatchBitblt*)data, UIO_USERSPACE); 415 break; 416 case FBIOCNBATCHBITBLT: 417 error = fbnbatchbitblt(fbp, (lBatchBitblt*)data, UIO_USERSPACE); 418 break; 419 case FBIOCTILEBITBLT: 420 error = fbtilebitblt(fbp, (sTileBitblt *)data); 421 break; 422 case FBIOCNTILEBITBLT: 423 error = fbntilebitblt(fbp, (lTileBitblt *)data); 424 break; 425 case FBIOCBITBLT3: 426 error = fbbitblt3(fbp, (sBitblt3 *)data); 427 break; 428 case FBIOCNBITBLT3: 429 error = fbnbitblt3(fbp, (lBitblt3 *)data); 430 break; 431 case FBIOCPOLYLINE: 432 error = fbpolyline(fbp, (sPrimLine *)data, 0); 433 break; 434 case FBIOCNPOLYLINE: 435 error = fbnpolyline(fbp, (lPrimLine *)data, 0, UIO_USERSPACE); 436 break; 437 case FBIOCDJPOLYLINE: 438 error = fbpolyline(fbp, (sPrimLine *)data, 1); 439 break; 440 case FBIOCNDJPOLYLINE: 441 error = fbnpolyline(fbp, (lPrimLine *)data, 1, UIO_USERSPACE); 442 break; 443 case FBIOCPOLYMARKER: 444 error = fbpolymarker(fbp, (sPrimMarker *)data); 445 break; 446 case FBIOCNPOLYMARKER: 447 error = fbnpolymarker(fbp, (lPrimMarker *)data, UIO_USERSPACE); 448 break; 449 case FBIOCRECTANGLE: 450 error = fbrectangle(fbp, (sPrimRect *)data); 451 break; 452 case FBIOCNRECTANGLE: 453 error = fbnrectangle(fbp, (lPrimRect *)data); 454 break; 455 case FBIOCFILLSCAN: 456 error = fbfillscan(fbp, (sPrimFill *)data); 457 break; 458 case FBIOCNFILLSCAN: 459 error = fbnfillscan(fbp, (lPrimFill *)data, UIO_USERSPACE); 460 break; 461 case FBIOCTEXT: 462 error = fbtext(fbp, (sPrimText *)data); 463 break; 464 case FBIOCNTEXT: 465 error = fbntext(fbp, (lPrimText *)data); 466 break; 467 case FBIOCPOLYDOT: 468 error = fbpolydot(fbp, (sPrimDot *)data); 469 break; 470 case FBIOCNPOLYDOT: 471 error = fbnpolydot(fbp, (lPrimDot *)data, UIO_USERSPACE); 472 break; 473 474 case FBIOCGETSCRTYPE: 475 fbgetscrtype(fbp, (sScrType *)data); 476 break; 477 case FBIOCNGETSCRTYPE: 478 fbp->fb_command = FB_CGETSCRTYPE; 479 fbstart(fbp, 1); 480 *((lScrType*)data) = fbp->fb_scrtype; 481 break; 482 case FBIOCSETPALETTE: 483 fbsetpalette(fbp, (sPalette *)data); 484 break; 485 case FBIOCNSETPALETTE: 486 error = fbnsetpalette(fbp, (lPalette *)data); 487 break; 488 case FBIOCGETPALETTE: 489 fbgetpalette(fbp, (sPalette *)data); 490 break; 491 case FBIOCNGETPALETTE: 492 error = fbngetpalette(fbp, (lPalette *)data); 493 break; 494 case FBIOCSETCURSOR: 495 fbsetcursor(fbp, (sCursor *)data); 496 break; 497 case FBIOCNSETCURSOR: 498 fbnsetcursor(fbp, (lCursor *)data); 499 break; 500 case FBIOCNSETCURSOR2: 501 fbp->fb_command = FB_CSETCURSOR; 502 fbp->fb_cursor = *((lCursor2 *)data); 503 fbstart(fbp, 0); 504 break; 505 case FBIOCUNSETCURSOR: 506 fbp->fb_command = FB_CUNSETCURSOR; 507 fbstart(fbp, 0); 508 break; 509 case FBIOCNUNSETCURSOR: 510 fbp->fb_command = FB_CUNSETCURSOR; 511 fbstart(fbp, 0); 512 break; 513 case FBIOCSHOWCURSOR: 514 fbp->fb_command = FB_CSHOWCURSOR; 515 fbstart(fbp, 0); 516 break; 517 case FBIOCNSHOWCURSOR: 518 fbp->fb_command = FB_CSHOWCURSOR; 519 fbstart(fbp, 0); 520 break; 521 case FBIOCHIDECURSOR: 522 fbp->fb_command = FB_CHIDECURSOR; 523 fbstart(fbp, 0); 524 break; 525 case FBIOCNHIDECURSOR: 526 fbp->fb_command = FB_CHIDECURSOR; 527 fbstart(fbp, 0); 528 break; 529 case FBIOCSETXY: 530 fbsetxy(fbp, (sPoint *)data); 531 break; 532 case FBIOCNSETXY: 533 fbp->fb_command = FB_CSETXY; 534 fbp->fb_point = *((lPoint *)data); 535 fbstart(fbp, 0); 536 break; 537 case FBIOCNSETPALETTEMODE: 538 fbp->fb_command = FB_CSETPMODE; 539 fbp->fb_data = *((int*)data); 540 fbstart(fbp, 0); 541 break; 542 case FBIOCNGETPALETTEMODE: 543 fbp->fb_command = FB_CGETPMODE; 544 fbstart(fbp, 1); 545 *((int*)data) = fbp->fb_data; 546 break; 547 case FBIOCNSETVIDEO: 548 fbp->fb_command = FB_CSETVIDEO; 549 fbp->fb_videoctl = *((lVideoCtl*)data); 550 fbstart(fbp, 0); 551 break; 552 case FBIOCNGETVIDEO: 553 fbp->fb_command = FB_CGETVIDEO; 554 fbp->fb_videostatus.request = VIDEO_STATUS; 555 fbstart(fbp, 1); 556 *((lVideoStatus*)data) = fbp->fb_videostatus; 557 error = fbp->fb_result; 558 break; 559 case FBIOCNIOCTL: 560 fbp->fb_command = FB_CIOCTL; 561 fbp->fb_fbioctl = *((lFbIoctl*)data); 562 fbstart(fbp, 1); 563 *((lFbIoctl*)data) = fbp->fb_fbioctl; 564 if (fbp->fb_result == FB_RERROR) 565 error = EINVAL; 566 break; 567 568 default: 569 error = ENXIO; 570 break; 571 } 572 573 fbunlock(error); 574 575 return (error); 576 } 577 578 fbmmap(dev, off, prot) 579 dev_t dev; 580 off_t off; 581 int prot; 582 { 583 register int unit = FBUNIT(dev); 584 register struct fb_softc *fb = &fb_softc[unit]; 585 register struct iop_device *ii; 586 register int page; 587 register struct fbreg *fbp = &fbreg[unit]; 588 589 if (unit >= NFB || (ii = fbinfo[unit]) == 0 || ii->ii_alive == 0) 590 return (-1); 591 592 fblock(); 593 fbp->fb_device = fb->fbs_device; 594 fbp->fb_command = FB_CGETPAGE; 595 fbp->fb_data = off; 596 fbstart(fbp, 1); 597 page = fbp->fb_data; 598 if (fbp->fb_result == FB_RERROR) 599 page = -1; 600 else 601 fb->fbs_flag = 1; 602 fbunlock(fbp->fb_result); 603 604 return (page); 605 } 606 607 static void 608 fblock() 609 { 610 int s; 611 612 #ifdef USE_RAW_INTR 613 fbwait(); 614 #endif 615 s = splfb(); 616 while (fbstate & FB_BUSY) { 617 fbstate |= FB_WANTED; 618 sleep((caddr_t)&fbstate, FBPRI); 619 } 620 fbstate |= FB_BUSY; 621 splx(s); 622 } 623 624 static void 625 fbunlock(error) 626 int error; 627 { 628 int s = splfb(); 629 630 #ifdef CPU_SINGLE 631 fbstate &= ~FB_BUSY; 632 if (fbstate & FB_WANTED) { 633 fbstate &= ~FB_WANTED; 634 wakeup((caddr_t)&fbstate); 635 } 636 #else 637 #ifdef USE_RAW_INTR 638 fbstate &= ~FB_BUSY; 639 if (fbstate & FB_WANTED) { 640 fbstate &= ~FB_WANTED; 641 wakeup((caddr_t)&fbstate); 642 } 643 #else 644 if (error || (fbstate & FB_DELAY) == 0) { 645 fbstate &= ~(FB_BUSY | FB_WAIT | FB_DELAY); 646 if (fbstate & FB_WANTED) { 647 fbstate &= ~FB_WANTED; 648 wakeup((caddr_t)&fbstate); 649 } 650 } 651 if (fbstate & FB_DELAY) { 652 fbstate &= ~FB_DELAY; 653 fbstate |= FB_DELAY2; 654 } 655 #endif 656 #endif /* CPU_SINGLE */ 657 splx(s); 658 } 659 660 static int 661 fbinit(fbp) 662 struct fbreg *fbp; 663 { 664 fblock(); 665 666 fbp->fb_command = FB_COPEN; 667 fbstart(fbp, 1); 668 if (fbp->fb_result != FB_ROK) { 669 fbunlock(0); 670 return (FB_RERROR); 671 } 672 673 fbp->fb_command = FB_CUNSETCURSOR; 674 fbstart(fbp, 0); 675 676 fbunlock(0); 677 678 return (FB_ROK); 679 } 680 681 static void 682 fbreset(fbp) 683 struct fbreg *fbp; 684 { 685 fblock(); 686 687 fbp->fb_command = FB_CUNSETCURSOR; 688 fbstart(fbp, 1); 689 690 fbp->fb_command = FB_CCLOSE; 691 fbstart(fbp, 0); 692 693 fbunlock(0); 694 } 695 #endif /* NFB */ 696