2 * linux/drivers/video/sbusfb.c -- SBUS or UPA based frame buffer device 4 * Copyright (C) 1998 Jakub Jelinek 6 * This driver is partly based on the Open Firmware console driver 8 * Copyright (C) 1997 Geert Uytterhoeven 10 * and SPARC console subsystem 12 * Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su) 13 * Copyright (C) 1995-1997 David S. Miller (davem@caip.rutgers.edu) 14 * Copyright (C) 1995-1996 Miguel de Icaza (miguel@nuclecu.unam.mx) 15 * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) 16 * Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 17 * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) 19 * This file is subject to the terms and conditions of the GNU General Public 20 * License. See the file COPYING in the main directory of this archive for 24 #include <linux/config.h> 25 #include <linux/module.h> 26 #include <linux/kernel.h> 27 #include <linux/errno.h> 28 #include <linux/string.h> 30 #include <linux/tty.h> 31 #include <linux/malloc.h> 32 #include <linux/vmalloc.h> 33 #include <linux/delay.h> 34 #include <linux/interrupt.h> 36 #include <linux/selection.h> 37 #include <linux/init.h> 38 #include <linux/console.h> 40 #include <linux/vt_kern.h> 42 #include <asm/uaccess.h> 43 #include <asm/pgtable.h>/* io_remap_page_range() */ 45 #include <video/sbusfb.h> 47 #define DEFAULT_CURSOR_BLINK_RATE (2*HZ/5) 49 #define CURSOR_SHAPE 1 50 #define CURSOR_BLINK 2 53 * Interface used by the world 57 intsbusfb_setup(char*); 60 static int defx_margin
= -1, defy_margin
= -1; 61 static char fontname
[40] __initdata
= {0}; 62 static int curblink __initdata
=1; 66 int x_margin
, y_margin
; 78 static intsbusfb_open(struct fb_info
*info
,int user
); 79 static intsbusfb_release(struct fb_info
*info
,int user
); 80 static intsbusfb_mmap(struct fb_info
*info
,struct file
*file
, 81 struct vm_area_struct
*vma
); 82 static intsbusfb_get_fix(struct fb_fix_screeninfo
*fix
,int con
, 83 struct fb_info
*info
); 84 static intsbusfb_get_var(struct fb_var_screeninfo
*var
,int con
, 85 struct fb_info
*info
); 86 static intsbusfb_set_var(struct fb_var_screeninfo
*var
,int con
, 87 struct fb_info
*info
); 88 static intsbusfb_pan_display(struct fb_var_screeninfo
*var
,int con
, 89 struct fb_info
*info
); 90 static intsbusfb_get_cmap(struct fb_cmap
*cmap
,int kspc
,int con
, 91 struct fb_info
*info
); 92 static intsbusfb_set_cmap(struct fb_cmap
*cmap
,int kspc
,int con
, 93 struct fb_info
*info
); 94 static intsbusfb_ioctl(struct inode
*inode
,struct file
*file
, u_int cmd
, 95 u_long arg
,int con
,struct fb_info
*info
); 96 static voidsbusfb_cursor(struct display
*p
,int mode
,int x
,int y
); 97 static voidsbusfb_clear_margin(struct display
*p
,int s
); 101 * Interface to the low level console driver 104 static intsbusfbcon_switch(int con
,struct fb_info
*info
); 105 static intsbusfbcon_updatevar(int con
,struct fb_info
*info
); 106 static voidsbusfbcon_blank(int blank
,struct fb_info
*info
); 113 static intsbusfb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
, 114 u_int
*transp
,struct fb_info
*info
); 115 static intsbusfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
, 116 u_int transp
,struct fb_info
*info
); 117 static voiddo_install_cmap(int con
,struct fb_info
*info
); 119 static struct fb_ops sbusfb_ops
= { 120 sbusfb_open
, sbusfb_release
, sbusfb_get_fix
, sbusfb_get_var
, sbusfb_set_var
, 121 sbusfb_get_cmap
, sbusfb_set_cmap
, sbusfb_pan_display
, sbusfb_ioctl
, sbusfb_mmap
126 * Open/Release the frame buffer device 129 static intsbusfb_open(struct fb_info
*info
,int user
) 131 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 134 if(fb
->open
)return-EBUSY
; 144 static intsbusfb_release(struct fb_info
*info
,int user
) 146 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 149 if(fb
->vtconsole
!= -1) { 150 vt_cons
[fb
->vtconsole
]->vc_mode
= KD_TEXT
; 153 sbusfb_clear_margin(&fb_display
[fb
->vtconsole
],0); 165 static unsigned longsbusfb_mmapsize(struct fb_info_sbusfb
*fb
,long size
) 167 if(size
== SBUS_MMAP_EMPTY
)return0; 168 if(size
>=0)return size
; 169 return fb
->type
.fb_size
* (-size
); 172 static intsbusfb_mmap(struct fb_info
*info
,struct file
*file
, 173 struct vm_area_struct
*vma
) 175 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 176 unsigned int size
, page
, r
, map_size
; 177 unsigned long map_offset
=0; 180 size
= vma
->vm_end
- vma
->vm_start
; 181 if(vma
->vm_offset
& ~PAGE_MASK
) 184 /* To stop the swapper from even considering these pages */ 185 vma
->vm_flags
|= (VM_SHM
| VM_LOCKED
); 188 /* Align it as much as desirable */ 190 unsigned long j
, alignment
, s
=0; 193 map_offset
= vma
->vm_offset
+size
; 194 for(i
=0; fb
->mmap_map
[i
].size
; i
++) { 195 if(fb
->mmap_map
[i
].voff
< vma
->vm_offset
) 197 if(fb
->mmap_map
[i
].voff
>= map_offset
) 199 if(max
<0||sbusfb_mmapsize(fb
,fb
->mmap_map
[i
].size
) > s
) { 201 s
=sbusfb_mmapsize(fb
,fb
->mmap_map
[max
].size
); 206 if(fb
->mmap_map
[max
].voff
+ j
> map_offset
) 207 j
= map_offset
- fb
->mmap_map
[max
].voff
; 208 for(alignment
=0x400000; alignment
> PAGE_SIZE
; alignment
>>=3) 209 if(j
>= alignment
&& !(fb
->mmap_map
[max
].poff
& (alignment
-1))) 211 if(alignment
> PAGE_SIZE
) { 213 alignment
= j
- ((vma
->vm_start
+ fb
->mmap_map
[max
].voff
- vma
->vm_offset
) & (j
-1)); 215 struct vm_area_struct
*vmm
=find_vma(current
->mm
, vma
->vm_start
); 216 if(!vmm
|| vmm
->vm_start
>= vma
->vm_end
+ alignment
) { 217 vma
->vm_start
+= alignment
; 218 vma
->vm_end
+= alignment
; 226 /* Each page, see which map applies */ 227 for(page
=0; page
< size
; ){ 229 for(i
=0; fb
->mmap_map
[i
].size
; i
++) 230 if(fb
->mmap_map
[i
].voff
== vma
->vm_offset
+page
) { 231 map_size
=sbusfb_mmapsize(fb
,fb
->mmap_map
[i
].size
); 233 #define POFF_MASK (PAGE_MASK|0x1UL) 235 #define POFF_MASK (PAGE_MASK) 237 map_offset
= (fb
->physbase
+ fb
->mmap_map
[i
].poff
) & POFF_MASK
; 244 if(page
+ map_size
> size
) 245 map_size
= size
- page
; 246 r
=io_remap_page_range(vma
->vm_start
+page
, map_offset
, map_size
, vma
->vm_page_prot
, fb
->iospace
); 252 vma
->vm_flags
|= VM_IO
; 257 lastconsole
= info
->display_fg
->vc_num
; 259 if(fb
->consolecnt
&& fb_display
[lastconsole
].fb_info
== info
) { 260 fb
->vtconsole
= lastconsole
; 262 vt_cons
[lastconsole
]->vc_mode
= KD_GRAPHICS
; 263 vc_cons
[lastconsole
].d
->vc_sw
->con_cursor(vc_cons
[lastconsole
].d
,CM_ERASE
); 264 }else if(fb
->unblank
&& !fb
->blanked
) 270 static voidsbusfb_clear_margin(struct display
*p
,int s
) 272 struct fb_info_sbusfb
*fb
=sbusfbinfod(p
); 274 if(fb
->switch_from_graph
) 275 (*fb
->switch_from_graph
)(fb
); 277 unsigned short rects
[16]; 281 rects
[2] = fb
->var
.xres_virtual
; 282 rects
[3] = fb
->y_margin
; 284 rects
[5] = fb
->y_margin
; 285 rects
[6] = fb
->x_margin
; 286 rects
[7] = fb
->var
.yres_virtual
; 287 rects
[8] = fb
->var
.xres_virtual
- fb
->x_margin
; 288 rects
[9] = fb
->y_margin
; 289 rects
[10] = fb
->var
.xres_virtual
; 290 rects
[11] = fb
->var
.yres_virtual
; 291 rects
[12] = fb
->x_margin
; 292 rects
[13] = fb
->var
.yres_virtual
- fb
->y_margin
; 293 rects
[14] = fb
->var
.xres_virtual
- fb
->x_margin
; 294 rects
[15] = fb
->var
.yres_virtual
; 295 (*fb
->fill
)(fb
, p
, s
,4, rects
); 297 unsigned char*fb_base
= p
->screen_base
, *q
; 298 int skip_bytes
= fb
->y_margin
* fb
->var
.xres_virtual
; 299 int scr_size
= fb
->var
.xres_virtual
* fb
->var
.yres_virtual
; 300 int h
, he
, incr
, size
; 303 if(fb
->var
.bits_per_pixel
==1) { 304 fb_base
-= (skip_bytes
+ fb
->x_margin
) /8; 307 mymemset(fb_base
, skip_bytes
- fb
->x_margin
/8); 308 mymemset(fb_base
+ scr_size
- skip_bytes
+ fb
->x_margin
/8, skip_bytes
- fb
->x_margin
/8); 309 incr
= fb
->var
.xres_virtual
/8; 310 size
= fb
->x_margin
/8*2; 311 for(q
= fb_base
+ skip_bytes
- fb
->x_margin
/8, h
=0; 312 h
<= he
; q
+= incr
, h
++) 315 fb_base
-= (skip_bytes
+ fb
->x_margin
); 316 memset(fb_base
,attr_bgcol(p
,s
), skip_bytes
- fb
->x_margin
); 317 memset(fb_base
+ scr_size
- skip_bytes
+ fb
->x_margin
,attr_bgcol(p
,s
), skip_bytes
- fb
->x_margin
); 318 incr
= fb
->var
.xres_virtual
; 319 size
= fb
->x_margin
*2; 320 for(q
= fb_base
+ skip_bytes
- fb
->x_margin
, h
=0; 321 h
<= he
; q
+= incr
, h
++) 322 memset(q
,attr_bgcol(p
,s
), size
); 327 static voidsbusfb_disp_setup(struct display
*p
) 329 struct fb_info_sbusfb
*fb
=sbusfbinfod(p
); 333 sbusfb_clear_margin(p
,0); 337 * Get the Fixed Part of the Display 340 static intsbusfb_get_fix(struct fb_fix_screeninfo
*fix
,int con
, 341 struct fb_info
*info
) 343 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 345 memcpy(fix
, &fb
->fix
,sizeof(struct fb_fix_screeninfo
)); 350 * Get the User Defined Part of the Display 353 static intsbusfb_get_var(struct fb_var_screeninfo
*var
,int con
, 354 struct fb_info
*info
) 356 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 358 memcpy(var
, &fb
->var
,sizeof(struct fb_var_screeninfo
)); 363 * Set the User Defined Part of the Display 366 static intsbusfb_set_var(struct fb_var_screeninfo
*var
,int con
, 367 struct fb_info
*info
) 369 struct display
*display
; 370 int activate
= var
->activate
; 373 display
= &fb_display
[con
]; 375 display
= info
->disp
; 377 /* simple check for equality until fully implemented -E */ 378 if((activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) { 379 if(display
->var
.xres
!= var
->xres
|| 380 display
->var
.yres
!= var
->yres
|| 381 display
->var
.xres_virtual
!= var
->xres_virtual
|| 382 display
->var
.yres_virtual
!= var
->yres_virtual
|| 383 display
->var
.bits_per_pixel
!= var
->bits_per_pixel
|| 384 display
->var
.accel_flags
!= var
->accel_flags
) { 393 * Pan or Wrap the Display 395 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 398 static intsbusfb_pan_display(struct fb_var_screeninfo
*var
,int con
, 399 struct fb_info
*info
) 401 if(var
->xoffset
|| var
->yoffset
) 411 static intsbus_hw_scursor(struct fbcursor
*cursor
,struct fb_info_sbusfb
*fb
) 416 char red
[2], green
[2], blue
[2]; 418 if(copy_from_user(&f
, cursor
,sizeof(struct fbcursor
))) 421 if(op
& FB_CUR_SETSHAPE
){ 422 if((u32
) f
.size
.fbx
> fb
->cursor
.hwsize
.fbx
) 424 if((u32
) f
.size
.fby
> fb
->cursor
.hwsize
.fby
) 427 bytes
= f
.size
.fby
<<3; 429 bytes
= f
.size
.fby
<<2; 431 if(op
& FB_CUR_SETCMAP
){ 432 if(f
.cmap
.index
|| f
.cmap
.count
!=2) 434 if(copy_from_user(red
, f
.cmap
.red
,2) || 435 copy_from_user(green
, f
.cmap
.green
,2) || 436 copy_from_user(blue
, f
.cmap
.blue
,2)) 439 if(op
& FB_CUR_SETCMAP
) 440 (*fb
->setcursormap
) (fb
, red
, green
, blue
); 441 if(op
& FB_CUR_SETSHAPE
){ 444 fb
->cursor
.size
= f
.size
; 445 memset((void*)&fb
->cursor
.bits
,0,sizeof(fb
->cursor
.bits
)); 446 if(copy_from_user(fb
->cursor
.bits
[0], f
.mask
, bytes
) || 447 copy_from_user(fb
->cursor
.bits
[1], f
.image
, bytes
)) 449 if(f
.size
.fbx
<=32) { 450 u
=0xffffffff<< (32- f
.size
.fbx
); 451 for(i
= fb
->cursor
.size
.fby
-1; i
>=0; i
--) { 452 fb
->cursor
.bits
[0][i
] &= u
; 453 fb
->cursor
.bits
[1][i
] &= fb
->cursor
.bits
[0][i
]; 456 u
=0xffffffff<< (64- f
.size
.fbx
); 457 for(i
= fb
->cursor
.size
.fby
-1; i
>=0; i
--) { 458 fb
->cursor
.bits
[0][2*i
+1] &= u
; 459 fb
->cursor
.bits
[1][2*i
] &= fb
->cursor
.bits
[0][2*i
]; 460 fb
->cursor
.bits
[1][2*i
+1] &= fb
->cursor
.bits
[0][2*i
+1]; 463 (*fb
->setcurshape
) (fb
); 465 if(op
& (FB_CUR_SETCUR
| FB_CUR_SETPOS
| FB_CUR_SETHOT
)){ 466 if(op
& FB_CUR_SETCUR
) 467 fb
->cursor
.enable
= f
.enable
; 468 if(op
& FB_CUR_SETPOS
) 469 fb
->cursor
.cpos
= f
.pos
; 470 if(op
& FB_CUR_SETHOT
) 471 fb
->cursor
.chot
= f
.hot
; 472 (*fb
->setcursor
) (fb
); 477 static unsigned char hw_cursor_cmap
[2] = {0,0xff}; 480 sbusfb_cursor_timer_handler(unsigned long dev_addr
) 482 struct fb_info_sbusfb
*fb
= (struct fb_info_sbusfb
*)dev_addr
; 484 if(!fb
->setcursor
)return; 486 if(fb
->cursor
.mode
& CURSOR_BLINK
) { 487 fb
->cursor
.enable
^=1; 491 fb
->cursor
.timer
.expires
= jiffies
+ fb
->cursor
.blink_rate
; 492 add_timer(&fb
->cursor
.timer
); 495 static voidsbusfb_cursor(struct display
*p
,int mode
,int x
,int y
) 497 struct fb_info_sbusfb
*fb
=sbusfbinfod(p
); 501 fb
->cursor
.mode
&= ~CURSOR_BLINK
; 502 fb
->cursor
.enable
=0; 503 (*fb
->setcursor
)(fb
); 508 if(fb
->cursor
.mode
& CURSOR_SHAPE
) { 509 fb
->cursor
.size
.fbx
=fontwidth(p
); 510 fb
->cursor
.size
.fby
=fontheight(p
); 511 fb
->cursor
.chot
.fbx
=0; 512 fb
->cursor
.chot
.fby
=0; 513 fb
->cursor
.enable
=1; 514 memset(fb
->cursor
.bits
,0,sizeof(fb
->cursor
.bits
)); 515 fb
->cursor
.bits
[0][fontheight(p
) -2] = (0xffffffff<< (32-fontwidth(p
))); 516 fb
->cursor
.bits
[1][fontheight(p
) -2] = (0xffffffff<< (32-fontwidth(p
))); 517 fb
->cursor
.bits
[0][fontheight(p
) -1] = (0xffffffff<< (32-fontwidth(p
))); 518 fb
->cursor
.bits
[1][fontheight(p
) -1] = (0xffffffff<< (32-fontwidth(p
))); 519 (*fb
->setcursormap
) (fb
, hw_cursor_cmap
, hw_cursor_cmap
, hw_cursor_cmap
); 520 (*fb
->setcurshape
) (fb
); 522 fb
->cursor
.mode
= CURSOR_BLINK
; 524 fb
->cursor
.cpos
.fbx
= (x
<<fontwidthlog(p
)) + fb
->x_margin
; 526 fb
->cursor
.cpos
.fbx
= (x
*fontwidth(p
)) + fb
->x_margin
; 528 fb
->cursor
.cpos
.fby
= (y
<<fontheightlog(p
)) + fb
->y_margin
; 530 fb
->cursor
.cpos
.fby
= (y
*fontheight(p
)) + fb
->y_margin
; 531 (*fb
->setcursor
)(fb
); 540 static intsbusfb_get_cmap(struct fb_cmap
*cmap
,int kspc
,int con
, 541 struct fb_info
*info
) 543 if(!info
->display_fg
|| con
== info
->display_fg
->vc_num
)/* current console? */ 544 returnfb_get_cmap(cmap
, kspc
, sbusfb_getcolreg
, info
); 545 else if(fb_display
[con
].cmap
.len
)/* non default colormap? */ 546 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
?0:2); 548 fb_copy_cmap(fb_default_cmap(1<<fb_display
[con
].var
.bits_per_pixel
), cmap
, kspc
?0:2); 556 static intsbusfb_set_cmap(struct fb_cmap
*cmap
,int kspc
,int con
, 557 struct fb_info
*info
) 560 struct display
*disp
; 563 disp
= &fb_display
[con
]; 566 if(!disp
->cmap
.len
) {/* no colormap allocated? */ 567 if((err
=fb_alloc_cmap(&disp
->cmap
,1<<disp
->var
.bits_per_pixel
,0))) 570 if(con
== currcon
) {/* current console? */ 571 err
=fb_set_cmap(cmap
, kspc
, sbusfb_setcolreg
, info
); 573 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 576 (*fb
->loadcmap
)(fb
, &fb_display
[con
], cmap
->start
, cmap
->len
); 580 fb_copy_cmap(cmap
, &disp
->cmap
, kspc
?0:1); 584 static intsbusfb_ioctl(struct inode
*inode
,struct file
*file
, u_int cmd
, 585 u_long arg
,int con
,struct fb_info
*info
) 587 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 592 case FBIOGTYPE
:/* return frame buffer type */ 593 copy_to_user_ret((struct fbtype
*)arg
, &fb
->type
,sizeof(struct fbtype
), -EFAULT
); 596 struct fbgattr
*fba
= (struct fbgattr
*) arg
; 598 i
=verify_area(VERIFY_WRITE
, (void*) arg
,sizeof(struct fbgattr
)); 600 __put_user_ret(fb
->emulations
[0], &fba
->real_type
, -EFAULT
); 601 __put_user_ret(0, &fba
->owner
, -EFAULT
); 602 __copy_to_user_ret(&fba
->fbtype
, &fb
->type
, 603 sizeof(struct fbtype
), -EFAULT
); 604 __put_user_ret(0, &fba
->sattr
.flags
, -EFAULT
); 605 __put_user_ret(fb
->type
.fb_type
, &fba
->sattr
.emu_type
, -EFAULT
); 606 __put_user_ret(-1, &fba
->sattr
.dev_specific
[0], -EFAULT
); 608 put_user_ret(fb
->emulations
[i
], &fba
->emu_types
[i
], -EFAULT
); 612 i
=verify_area(VERIFY_READ
, (void*) arg
,sizeof(struct fbsattr
)); 617 lastconsole
= info
->display_fg
->vc_num
; 618 if(vt_cons
[lastconsole
]->vc_mode
== KD_TEXT
) 621 get_user_ret(i
, (int*)arg
, -EFAULT
); 623 if(!fb
->blanked
|| !fb
->unblank
) 625 if(fb
->consolecnt
|| (fb
->open
&& fb
->mmaped
)) 629 if(fb
->blanked
|| !fb
->blank
) 636 put_user_ret(fb
->blanked
, (int*) arg
, -EFAULT
); 638 case FBIOGETCMAP_SPARC
: { 640 int end
, count
, index
; 645 i
=verify_area(VERIFY_READ
, (void*) arg
,sizeof(struct fbcmap
)); 647 cmap
= (struct fbcmap
*) arg
; 648 __get_user_ret(count
, &cmap
->count
, -EFAULT
); 649 __get_user_ret(index
, &cmap
->index
, -EFAULT
); 650 if((index
<0) || (index
>255)) 652 if(index
+ count
>256) 654 __get_user_ret(rp
, &cmap
->red
, -EFAULT
); 655 __get_user_ret(gp
, &cmap
->green
, -EFAULT
); 656 __get_user_ret(bp
, &cmap
->blue
, -EFAULT
); 657 if(verify_area(VERIFY_WRITE
, rp
, count
))return-EFAULT
; 658 if(verify_area(VERIFY_WRITE
, gp
, count
))return-EFAULT
; 659 if(verify_area(VERIFY_WRITE
, bp
, count
))return-EFAULT
; 661 for(i
= index
; i
< end
; i
++){ 662 __put_user_ret(fb
->color_map
CM(i
,0), rp
, -EFAULT
); 663 __put_user_ret(fb
->color_map
CM(i
,1), gp
, -EFAULT
); 664 __put_user_ret(fb
->color_map
CM(i
,2), bp
, -EFAULT
); 667 (*fb
->loadcmap
)(fb
, NULL
, index
, count
); 670 case FBIOPUTCMAP_SPARC
: {/* load color map entries */ 672 int end
, count
, index
; 677 i
=verify_area(VERIFY_READ
, (void*) arg
,sizeof(struct fbcmap
)); 679 cmap
= (struct fbcmap
*) arg
; 680 __get_user_ret(count
, &cmap
->count
, -EFAULT
); 681 __get_user_ret(index
, &cmap
->index
, -EFAULT
); 682 if((index
<0) || (index
>255)) 684 if(index
+ count
>256) 686 __get_user_ret(rp
, &cmap
->red
, -EFAULT
); 687 __get_user_ret(gp
, &cmap
->green
, -EFAULT
); 688 __get_user_ret(bp
, &cmap
->blue
, -EFAULT
); 689 if(verify_area(VERIFY_READ
, rp
, count
))return-EFAULT
; 690 if(verify_area(VERIFY_READ
, gp
, count
))return-EFAULT
; 691 if(verify_area(VERIFY_READ
, bp
, count
))return-EFAULT
; 694 for(i
= index
; i
< end
; i
++){ 695 __get_user_ret(fb
->color_map
CM(i
,0), rp
, -EFAULT
); 696 __get_user_ret(fb
->color_map
CM(i
,1), gp
, -EFAULT
); 697 __get_user_ret(fb
->color_map
CM(i
,2), bp
, -EFAULT
); 700 (*fb
->loadcmap
)(fb
, NULL
, index
, count
); 704 struct fbcurpos
*p
= (struct fbcurpos
*) arg
; 705 if(!fb
->setcursor
)return-EINVAL
; 706 if(verify_area(VERIFY_WRITE
, p
,sizeof(struct fbcurpos
))) 708 __put_user_ret(fb
->cursor
.hwsize
.fbx
, &p
->fbx
, -EFAULT
); 709 __put_user_ret(fb
->cursor
.hwsize
.fby
, &p
->fby
, -EFAULT
); 713 if(!fb
->setcursor
)return-EINVAL
; 715 lastconsole
= info
->display_fg
->vc_num
; 716 if(vt_cons
[lastconsole
]->vc_mode
== KD_TEXT
) 717 return-EINVAL
;/* Don't let graphics programs hide our nice text cursor */ 718 fb
->cursor
.mode
= CURSOR_SHAPE
;/* Forget state of our text cursor */ 720 returnsbus_hw_scursor((struct fbcursor
*) arg
, fb
); 723 if(!fb
->setcursor
)return-EINVAL
; 724 /* Don't let graphics programs move our nice text cursor */ 726 lastconsole
= info
->display_fg
->vc_num
; 727 if(vt_cons
[lastconsole
]->vc_mode
== KD_TEXT
) 728 return-EINVAL
;/* Don't let graphics programs move our nice text cursor */ 730 if(copy_from_user(&fb
->cursor
.cpos
, (void*)arg
,sizeof(struct fbcurpos
))) 732 (*fb
->setcursor
) (fb
); 736 return fb
->ioctl(fb
, cmd
, arg
); 743 * Setup: parse used options 746 int __init
sbusfb_setup(char*options
) 751 if(!strncmp(p
,"nomargins",9)) { 752 defx_margin
=0; defy_margin
=0; 753 }else if(!strncmp(p
,"margins=",8)) { 757 i
=simple_strtoul(p
+8,&q
,10); 758 if(i
>=0&& *q
=='x') { 759 j
=simple_strtoul(q
+1,&q
,10); 760 if(j
>=0&& (*q
==' '|| !*q
)) { 761 defx_margin
= i
; defy_margin
= j
; 764 }else if(!strncmp(p
,"font=",5)) { 767 for(i
=0; i
<sizeof(fontname
) -1; i
++) 768 if(p
[i
+5] ==' '|| !p
[i
+5]) 770 memcpy(fontname
, p
+5, i
); 772 }else if(!strncmp(p
,"noblink",7)) 774 while(*p
&& *p
!=' '&& *p
!=',') p
++; 781 static intsbusfbcon_switch(int con
,struct fb_info
*info
) 783 int x_margin
, y_margin
; 784 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 787 /* Do we have to save the colormap? */ 788 if(fb_display
[currcon
].cmap
.len
) 789 fb_get_cmap(&fb_display
[currcon
].cmap
,1, sbusfb_getcolreg
, info
); 791 if(info
->display_fg
) { 792 lastconsole
= info
->display_fg
->vc_num
; 793 if(lastconsole
!= con
&& 794 (fontwidth(&fb_display
[lastconsole
]) !=fontwidth(&fb_display
[con
]) || 795 fontheight(&fb_display
[lastconsole
]) !=fontheight(&fb_display
[con
]))) 796 fb
->cursor
.mode
|= CURSOR_SHAPE
; 798 x_margin
= (fb_display
[con
].var
.xres_virtual
- fb_display
[con
].var
.xres
) /2; 799 y_margin
= (fb_display
[con
].var
.yres_virtual
- fb_display
[con
].var
.yres
) /2; 801 fb
->margins(fb
, &fb_display
[con
], x_margin
, y_margin
); 802 if(fb
->graphmode
|| fb
->x_margin
!= x_margin
|| fb
->y_margin
!= y_margin
) { 803 fb
->x_margin
= x_margin
; fb
->y_margin
= y_margin
; 804 sbusfb_clear_margin(&fb_display
[con
],0); 807 /* Install new colormap */ 808 do_install_cmap(con
, info
); 813 * Update the `var' structure (called by fbcon.c) 816 static intsbusfbcon_updatevar(int con
,struct fb_info
*info
) 826 static voidsbusfbcon_blank(int blank
,struct fb_info
*info
) 828 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 830 if(blank
&& fb
->blank
) 831 return fb
->blank(fb
); 832 else if(!blank
&& fb
->unblank
) 833 return fb
->unblank(fb
); 837 * Read a single color register and split it into 838 * colors/transparent. Return != 0 for invalid regno. 841 static intsbusfb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
, 842 u_int
*transp
,struct fb_info
*info
) 844 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 846 if(!fb
->color_map
|| regno
>255) 848 *red
= (fb
->color_map
CM(regno
,0)<<8) | fb
->color_map
CM(regno
,0); 849 *green
= (fb
->color_map
CM(regno
,1)<<8) | fb
->color_map
CM(regno
,1); 850 *blue
= (fb
->color_map
CM(regno
,2)<<8) | fb
->color_map
CM(regno
,2); 857 * Set a single color register. The values supplied are already 858 * rounded down to the hardware's capabilities (according to the 859 * entries in the var structure). Return != 0 for invalid regno. 862 static intsbusfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
, 863 u_int transp
,struct fb_info
*info
) 865 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 867 if(!fb
->color_map
|| regno
>255) 872 fb
->color_map
CM(regno
,0) = red
; 873 fb
->color_map
CM(regno
,1) = green
; 874 fb
->color_map
CM(regno
,2) = blue
; 879 static voiddo_install_cmap(int con
,struct fb_info
*info
) 881 struct fb_info_sbusfb
*fb
=sbusfbinfo(info
); 885 if(fb_display
[con
].cmap
.len
) 886 fb_set_cmap(&fb_display
[con
].cmap
,1, sbusfb_setcolreg
, info
); 888 fb_set_cmap(fb_default_cmap(1<<fb_display
[con
].var
.bits_per_pixel
), 889 1, sbusfb_setcolreg
, info
); 891 (*fb
->loadcmap
)(fb
, &fb_display
[con
],0,256); 894 static intsbusfb_set_font(struct display
*p
,int width
,int height
) 897 int w
= p
->var
.xres_virtual
, h
= p
->var
.yres_virtual
; 898 int depth
= p
->var
.bits_per_pixel
; 899 struct fb_info_sbusfb
*fb
=sbusfbinfod(p
); 900 int x_margin
, y_margin
; 902 if(depth
>8) depth
=8; 905 if(defx_margin
<0|| defy_margin
<0) { 906 for(margin
=0; def_margins
[margin
].depth
; margin
++) 907 if(w
== def_margins
[margin
].xres
&& 908 h
== def_margins
[margin
].yres
&& 909 depth
== def_margins
[margin
].depth
) { 910 x_margin
= def_margins
[margin
].x_margin
; 911 y_margin
= def_margins
[margin
].y_margin
; 915 x_margin
= defx_margin
; 916 y_margin
= defy_margin
; 918 x_margin
+= ((w
-2*x_margin
) % width
) /2; 919 y_margin
+= ((h
-2*y_margin
) % height
) /2; 921 p
->var
.xres
= w
-2*x_margin
; 922 p
->var
.yres
= h
-2*y_margin
; 924 fb
->cursor
.mode
|= CURSOR_SHAPE
; 927 fb
->margins(fb
, p
, x_margin
, y_margin
); 928 if(fb
->x_margin
!= x_margin
|| fb
->y_margin
!= y_margin
) { 929 fb
->x_margin
= x_margin
; fb
->y_margin
= y_margin
; 930 sbusfb_clear_margin(p
,0); 936 voidsbusfb_palette(int enter
) 941 for(i
=0; i
< MAX_NR_CONSOLES
; i
++) { 943 if(p
->dispsw
&& p
->dispsw
->setup
== sbusfb_disp_setup
&& 944 p
->fb_info
->display_fg
&& 945 p
->fb_info
->display_fg
->vc_num
== i
) { 946 struct fb_info_sbusfb
*fb
=sbusfbinfod(p
); 948 if(fb
->restore_palette
) { 950 fb
->restore_palette(fb
); 951 else if(vt_cons
[i
]->vc_mode
!= KD_GRAPHICS
) 952 vc_cons
[i
].d
->vc_sw
->con_set_palette(vc_cons
[i
].d
, color_table
); 962 externvoid(*prom_palette
)(int); 964 static void __init
sbusfb_init_fb(int node
,int parent
,int fbtype
, 965 struct linux_sbus_device
*sbdp
) 967 struct fb_fix_screeninfo
*fix
; 968 struct fb_var_screeninfo
*var
; 969 struct display
*disp
; 970 struct fb_info_sbusfb
*fb
; 972 int linebytes
, w
, h
, depth
; 976 fb
=kmalloc(sizeof(struct fb_info_sbusfb
), GFP_ATOMIC
); 978 prom_printf("Could not allocate sbusfb structure\n"); 983 prom_palette
= sbusfb_palette
; 985 memset(fb
,0,sizeof(struct fb_info_sbusfb
)); 991 fb
->prom_node
= node
; 992 fb
->prom_parent
= parent
; 995 fb
->iospace
= sbdp
->reg_addrs
[0].which_io
; 997 type
->fb_type
= fbtype
; 998 memset(&fb
->emulations
,0xff,sizeof(fb
->emulations
)); 999 fb
->emulations
[0] = fbtype
; 1001 #ifndef __sparc_v9__ 1002 disp
->screen_base
= (unsigned char*)prom_getintdefault(node
,"address",0); 1005 type
->fb_height
= h
=prom_getintdefault(node
,"height",900); 1006 type
->fb_width
= w
=prom_getintdefault(node
,"width",1152); 1008 type
->fb_depth
= depth
= (fbtype
== FBTYPE_SUN2BW
) ?1:8; 1009 linebytes
=prom_getintdefault(node
,"linebytes", w
* depth
/8); 1010 type
->fb_size
=PAGE_ALIGN((linebytes
) * h
); 1012 if(defx_margin
<0|| defy_margin
<0) { 1013 for(margin
=0; def_margins
[margin
].depth
; margin
++) 1014 if(w
== def_margins
[margin
].xres
&& 1015 h
== def_margins
[margin
].yres
&& 1016 depth
== def_margins
[margin
].depth
) { 1017 fb
->x_margin
= def_margins
[margin
].x_margin
; 1018 fb
->y_margin
= def_margins
[margin
].y_margin
; 1022 fb
->x_margin
= defx_margin
; 1023 fb
->y_margin
= defy_margin
; 1025 fb
->x_margin
+= ((w
-2*fb
->x_margin
) &7) /2; 1026 fb
->y_margin
+= ((h
-2*fb
->y_margin
) &15) /2; 1028 var
->xres_virtual
= w
; 1029 var
->yres_virtual
= h
; 1030 var
->xres
= w
-2*fb
->x_margin
; 1031 var
->yres
= h
-2*fb
->y_margin
; 1033 var
->bits_per_pixel
= depth
; 1034 var
->height
= var
->width
= -1; 1035 var
->pixclock
=10000; 1036 var
->vmode
= FB_VMODE_NONINTERLACED
; 1037 var
->red
.length
= var
->green
.length
= var
->blue
.length
=8; 1039 fix
->line_length
= linebytes
; 1040 fix
->smem_len
= type
->fb_size
; 1041 fix
->type
= FB_TYPE_PACKED_PIXELS
; 1042 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
; 1045 fb
->info
.fbops
= &sbusfb_ops
; 1046 fb
->info
.disp
= disp
; 1047 strcpy(fb
->info
.fontname
, fontname
); 1048 fb
->info
.changevar
= NULL
; 1049 fb
->info
.switch_con
= &sbusfbcon_switch
; 1050 fb
->info
.updatevar
= &sbusfbcon_updatevar
; 1051 fb
->info
.blank
= &sbusfbcon_blank
; 1052 fb
->info
.flags
= FBINFO_FLAG_DEFAULT
; 1054 fb
->cursor
.hwsize
.fbx
=32; 1055 fb
->cursor
.hwsize
.fby
=32; 1057 if(depth
>1&& !fb
->color_map
) 1058 fb
->color_map
=kmalloc(256*3, GFP_ATOMIC
); 1061 #ifdef CONFIG_FB_CREATOR 1062 case FBTYPE_CREATOR
: 1063 p
=creatorfb_init(fb
);break; 1065 #ifdef CONFIG_FB_CGSIX 1066 case FBTYPE_SUNFAST_COLOR
: 1067 p
=cgsixfb_init(fb
);break; 1069 #ifdef CONFIG_FB_CGTHREE 1070 case FBTYPE_SUN3COLOR
: 1071 p
=cgthreefb_init(fb
);break; 1073 #ifdef CONFIG_FB_TCX 1074 case FBTYPE_TCXCOLOR
: 1075 p
=tcxfb_init(fb
);break; 1077 #ifdef CONFIG_FB_LEO 1079 p
=leofb_init(fb
);break; 1081 #ifdef CONFIG_FB_BWTWO 1083 p
=bwtwofb_init(fb
);break; 1085 #ifdef CONFIG_FB_CGFOURTEEN 1086 case FBTYPE_MDICOLOR
: 1087 p
=cgfourteenfb_init(fb
);break; 1089 #ifdef CONFIG_FB_P9100 1090 case FBTYPE_P9100COLOR
: 1091 /* Temporary crock. For now we are a cg3 */ 1092 p
=p9100fb_init(fb
); type
->fb_type
= FBTYPE_SUN3COLOR
;break; 1101 if(p
== SBUSFBINIT_SIZECHANGE
) 1104 disp
->dispsw
= &fb
->dispsw
; 1106 fb
->dispsw
.cursor
= sbusfb_cursor
; 1108 fb
->cursor
.blink_rate
= DEFAULT_CURSOR_BLINK_RATE
; 1109 init_timer(&fb
->cursor
.timer
); 1110 fb
->cursor
.timer
.expires
= jiffies
+ fb
->cursor
.blink_rate
; 1111 fb
->cursor
.timer
.data
= (unsigned long)fb
; 1112 fb
->cursor
.timer
.function
= sbusfb_cursor_timer_handler
; 1113 add_timer(&fb
->cursor
.timer
); 1116 fb
->cursor
.mode
= CURSOR_SHAPE
; 1117 fb
->dispsw
.set_font
= sbusfb_set_font
; 1118 fb
->setup
= fb
->dispsw
.setup
; 1119 fb
->dispsw
.setup
= sbusfb_disp_setup
; 1120 fb
->dispsw
.clear_margins
= NULL
; 1123 disp
->visual
= fix
->visual
; 1124 disp
->type
= fix
->type
; 1125 disp
->type_aux
= fix
->type_aux
; 1126 disp
->line_length
= fix
->line_length
; 1129 disp
->can_soft_blank
=1; 1131 sbusfb_set_var(var
, -1, &fb
->info
); 1133 if(register_framebuffer(&fb
->info
) <0) { 1137 printk(KERN_INFO
"fb%d: %s\n",GET_FB_IDX(fb
->info
.node
), p
); 1140 staticinlineintknown_card(char*name
) 1143 for(p
= name
; *p
&& *p
!=','; p
++); 1144 if(*p
==',') name
= p
+1; 1145 if(!strcmp(name
,"cgsix") || !strcmp(name
,"cgthree+")) 1146 return FBTYPE_SUNFAST_COLOR
; 1147 if(!strcmp(name
,"cgthree") || !strcmp(name
,"cgRDI")) 1148 return FBTYPE_SUN3COLOR
; 1149 if(!strcmp(name
,"cgfourteen")) 1150 return FBTYPE_MDICOLOR
; 1151 if(!strcmp(name
,"leo")) 1152 return FBTYPE_SUNLEO
; 1153 if(!strcmp(name
,"bwtwo")) 1154 return FBTYPE_SUN2BW
; 1155 if(!strcmp(name
,"tcx")) 1156 return FBTYPE_TCXCOLOR
; 1157 if(!strcmp(name
,"p9100")) 1158 return FBTYPE_P9100COLOR
; 1159 return FBTYPE_NOTYPE
; 1162 int __init
sbusfb_init(void) 1165 struct linux_sbus_device
*sbdp
; 1166 struct linux_sbus
*sbus
; 1168 externintcon_is_present(void); 1170 if(!con_is_present())return-ENXIO
; 1172 #ifdef CONFIG_FB_CREATOR 1175 root
=prom_getchild(prom_root_node
); 1176 for(node
=prom_searchsiblings(root
,"SUNW,ffb"); node
; 1177 node
=prom_searchsiblings(prom_getsibling(node
),"SUNW,ffb")) 1178 sbusfb_init_fb(node
, prom_root_node
, FBTYPE_CREATOR
, NULL
); 1179 for(node
=prom_searchsiblings(root
,"SUNW,afb"); node
; 1180 node
=prom_searchsiblings(prom_getsibling(node
),"SUNW,afb")) 1181 sbusfb_init_fb(node
, prom_root_node
, FBTYPE_CREATOR
, NULL
); 1185 sbusfb_init_fb(0,0, FBTYPE_SUN2BW
, NULL
); 1187 #if defined(CONFIG_FB_CGFOURTEEN) && !defined(__sparc_v9__) 1190 root
=prom_getchild(prom_root_node
); 1191 root
=prom_searchsiblings(root
,"obio"); 1193 (node
=prom_searchsiblings(prom_getchild(root
),"cgfourteen"))) { 1194 sbusfb_init_fb(node
, root
, FBTYPE_MDICOLOR
, NULL
); 1198 if(!SBus_chain
)return0; 1199 for_all_sbusdev(sbdp
, sbus
) { 1200 type
=known_card(sbdp
->prom_name
); 1201 if(type
== FBTYPE_NOTYPE
)continue; 1202 if(prom_getproperty(sbdp
->prom_node
,"emulation", prom_name
,sizeof(prom_name
)) >0) { 1203 type
=known_card(prom_name
); 1204 if(type
== FBTYPE_NOTYPE
) type
=known_card(sbdp
->prom_name
); 1206 prom_apply_sbus_ranges(sbdp
->my_bus
, &sbdp
->reg_addrs
[0], 1207 sbdp
->num_registers
, sbdp
); 1208 sbusfb_init_fb(sbdp
->prom_node
, sbdp
->my_bus
->prom_node
, type
, sbdp
);