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