1/* 2 * linux/drivers/video/fbcon.h -- Low level frame buffer based console driver 3 * 4 * Copyright (C) 1997 Geert Uytterhoeven 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file COPYING in the main directory of this archive 8 * for more details. 9 */ 10 11#ifndef _VIDEO_FBCON_H 12#define _VIDEO_FBCON_H 13 14#include <linux/config.h> 15#include <linux/types.h> 16#include <linux/console_struct.h> 17#include <linux/vt_buffer.h> 18 19#include <asm/io.h> 20 21 22 /* 23 * `switch' for the Low Level Operations 24 */ 25 26struct display_switch { 27 void (*setup)(struct display *p); 28 void (*bmove)(struct display *p, int sy, int sx, int dy, int dx, 29 int height, int width); 30 /* for clear, conp may be NULL, which means use a blanking (black) color */ 31 void (*clear)(struct vc_data *conp, struct display *p, int sy, int sx, 32 int height, int width); 33 void (*putc)(struct vc_data *conp, struct display *p, int c, int yy, 34 int xx); 35 void (*putcs)(struct vc_data *conp, struct display *p, const unsigned short *s, 36 int count, int yy, int xx); 37 void (*revc)(struct display *p, int xx, int yy); 38 void (*cursor)(struct display *p, int mode, int xx, int yy); 39 int (*set_font)(struct display *p, int width, int height); 40 void (*clear_margins)(struct vc_data *conp, struct display *p, 41 int bottom_only); 42 unsigned int fontwidthmask; /* 1 at (1 << (width - 1)) if width is supported */ 43}; 44 45extern struct display_switch fbcon_dummy; 46 47 /* 48 * This is the interface between the low-level console driver and the 49 * low-level frame buffer device 50 */ 51 52struct display { 53 /* Filled in by the frame buffer device */ 54 55 struct fb_var_screeninfo var; /* variable infos. yoffset and vmode */ 56 /* are updated by fbcon.c */ 57 struct fb_cmap cmap; /* colormap */ 58 char *screen_base; /* pointer to top of virtual screen */ 59 /* (virtual address) */ 60 int visual; 61 int type; /* see FB_TYPE_* */ 62 int type_aux; /* Interleave for interleaved Planes */ 63 u_short ypanstep; /* zero if no hardware ypan */ 64 u_short ywrapstep; /* zero if no hardware ywrap */ 65 u_long line_length; /* length of a line in bytes */ 66 u_short can_soft_blank; /* zero if no hardware blanking */ 67 u_short inverse; /* != 0 text black on white as default */ 68 struct display_switch *dispsw; /* low level operations */ 69 void *dispsw_data; /* optional dispsw helper data */ 70 71 72 /* Filled in by the low-level console driver */ 73 74 struct vc_data *conp; /* pointer to console data */ 75 struct fb_info *fb_info; /* frame buffer for this console */ 76 int vrows; /* number of virtual rows */ 77 unsigned short cursor_x; /* current cursor position */ 78 unsigned short cursor_y; 79 int fgcol; /* text colors */ 80 int bgcol; 81 u_long next_line; /* offset to one line below */ 82 u_long next_plane; /* offset to next plane */ 83 u_char *fontdata; /* Font associated to this display */ 84 unsigned short _fontheightlog; 85 unsigned short _fontwidthlog; 86 unsigned short _fontheight; 87 unsigned short _fontwidth; 88 int userfont; /* != 0 if fontdata kmalloc()ed */ 89 u_short scrollmode; /* Scroll Method */ 90 short yscroll; /* Hardware scrolling */ 91 unsigned char fgshift, bgshift; 92 unsigned short charmask; /* 0xff or 0x1ff */ 93}; 94 95/* drivers/video/fbcon.c */ 96extern struct display fb_display[MAX_NR_CONSOLES]; 97extern char con2fb_map[MAX_NR_CONSOLES]; 98extern int PROC_CONSOLE(const struct fb_info *info); 99extern void set_con2fb_map(int unit, int newidx); 100extern int set_all_vcs(int fbidx, struct fb_ops *fb, 101 struct fb_var_screeninfo *var, struct fb_info *info); 102 103#define fontheight(p) ((p)->_fontheight) 104#define fontheightlog(p) ((p)->_fontheightlog) 105 106#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY 107 108/* fontwidth w is supported by dispsw */ 109#define FONTWIDTH(w) (1 << ((8) - 1)) 110/* fontwidths w1-w2 inclusive are supported by dispsw */ 111#define FONTWIDTHRANGE(w1,w2) FONTWIDTH(8) 112 113#define fontwidth(p) (8) 114#define fontwidthlog(p) (0) 115 116#else 117 118/* fontwidth w is supported by dispsw */ 119#define FONTWIDTH(w) (1 << ((w) - 1)) 120/* fontwidths w1-w2 inclusive are supported by dispsw */ 121#define FONTWIDTHRANGE(w1,w2) (FONTWIDTH(w2+1) - FONTWIDTH(w1)) 122 123#define fontwidth(p) ((p)->_fontwidth) 124#define fontwidthlog(p) ((p)->_fontwidthlog) 125 126#endif 127 128 /* 129 * Attribute Decoding 130 */ 131 132/* Color */ 133#define attr_fgcol(p,s) \ 134 (((s) >> ((p)->fgshift)) & 0x0f) 135#define attr_bgcol(p,s) \ 136 (((s) >> ((p)->bgshift)) & 0x0f) 137#define attr_bgcol_ec(p,conp) \ 138 ((conp) ? (((conp)->vc_video_erase_char >> ((p)->bgshift)) & 0x0f) : 0) 139 140/* Monochrome */ 141#define attr_bold(p,s) \ 142 ((s) & 0x200) 143#define attr_reverse(p,s) \ 144 (((s) & 0x800) ^ ((p)->inverse ? 0x800 : 0)) 145#define attr_underline(p,s) \ 146 ((s) & 0x400) 147#define attr_blink(p,s) \ 148 ((s) & 0x8000) 149 150 /* 151 * Scroll Method 152 */ 153 154/* Internal flags */ 155#define __SCROLL_YPAN 0x001 156#define __SCROLL_YWRAP 0x002 157#define __SCROLL_YMOVE 0x003 158#define __SCROLL_YREDRAW 0x004 159#define __SCROLL_YMASK 0x00f 160#define __SCROLL_YFIXED 0x010 161#define __SCROLL_YNOMOVE 0x020 162#define __SCROLL_YPANREDRAW 0x040 163#define __SCROLL_YNOPARTIAL 0x080 164 165/* Only these should be used by the drivers */ 166/* Which one should you use? If you have a fast card and slow bus, 167 then probably just 0 to indicate fbcon should choose between 168 YWRAP/YPAN+MOVE/YMOVE. On the other side, if you have a fast bus 169 and even better if your card can do fonting (1->8/32bit painting), 170 you should consider either SCROLL_YREDRAW (if your card is 171 able to do neither YPAN/YWRAP), or SCROLL_YNOMOVE. 172 The best is to test it with some real life scrolling (usually, not 173 all lines on the screen are filled completely with non-space characters, 174 and REDRAW performs much better on such lines, so don't cat a file 175 with every line covering all screen columns, it would not be the right 176 benchmark). 177 */ 178#define SCROLL_YREDRAW (__SCROLL_YFIXED|__SCROLL_YREDRAW) 179#define SCROLL_YNOMOVE (__SCROLL_YNOMOVE|__SCROLL_YPANREDRAW) 180 181/* SCROLL_YNOPARTIAL, used in combination with the above, is for video 182 cards which can not handle using panning to scroll a portion of the 183 screen without excessive flicker. Panning will only be used for 184 whole screens. 185 */ 186/* Namespace consistency */ 187#define SCROLL_YNOPARTIAL __SCROLL_YNOPARTIAL 188 189 190#if defined(__sparc__) 191 192/* We map all of our framebuffers such that big-endian accesses 193 * are what we want, so the following is sufficient. 194 */ 195 196#define fb_readb sbus_readb 197#define fb_readw sbus_readw 198#define fb_readl sbus_readl 199#define fb_writeb sbus_writeb 200#define fb_writew sbus_writew 201#define fb_writel sbus_writel 202#define fb_memset sbus_memset_io 203 204#elif defined(__i386__) || defined(__alpha__) || \ 205 defined(__x86_64__) || defined(__hppa__) 206 207#define fb_readb __raw_readb 208#define fb_readw __raw_readw 209#define fb_readl __raw_readl 210#define fb_writeb __raw_writeb 211#define fb_writew __raw_writew 212#define fb_writel __raw_writel 213#define fb_memset memset_io 214 215#else 216 217#define fb_readb(addr) (*(volatile u8 *) (addr)) 218#define fb_readw(addr) (*(volatile u16 *) (addr)) 219#define fb_readl(addr) (*(volatile u32 *) (addr)) 220#define fb_writeb(b,addr) (*(volatile u8 *) (addr) = (b)) 221#define fb_writew(b,addr) (*(volatile u16 *) (addr) = (b)) 222#define fb_writel(b,addr) (*(volatile u32 *) (addr) = (b)) 223#define fb_memset memset 224 225#endif 226 227 228extern void fbcon_redraw_clear(struct vc_data *, struct display *, int, int, int, int); 229extern void fbcon_redraw_bmove(struct display *, int, int, int, int, int, int); 230 231 232/* ================================================================= */ 233/* Utility Assembler Functions */ 234/* ================================================================= */ 235 236 237#if defined(__mc68000__) 238 239/* ====================================================================== */ 240 241/* Those of a delicate disposition might like to skip the next couple of 242 * pages. 243 * 244 * These functions are drop in replacements for memmove and 245 * memset(_, 0, _). However their five instances add at least a kilobyte 246 * to the object file. You have been warned. 247 * 248 * Not a great fan of assembler for the sake of it, but I think 249 * that these routines are at least 10 times faster than their C 250 * equivalents for large blits, and that's important to the lowest level of 251 * a graphics driver. Question is whether some scheme with the blitter 252 * would be faster. I suspect not for simple text system - not much 253 * asynchrony. 254 * 255 * Code is very simple, just gruesome expansion. Basic strategy is to 256 * increase data moved/cleared at each step to 16 bytes to reduce 257 * instruction per data move overhead. movem might be faster still 258 * For more than 15 bytes, we try to align the write direction on a 259 * longword boundary to get maximum speed. This is even more gruesome. 260 * Unaligned read/write used requires 68020+ - think this is a problem? 261 * 262 * Sorry! 263 */ 264 265 266/* ++roman: I've optimized Robert's original versions in some minor 267 * aspects, e.g. moveq instead of movel, let gcc choose the registers, 268 * use movem in some places... 269 * For other modes than 1 plane, lots of more such assembler functions 270 * were needed (e.g. the ones using movep or expanding color values). 271 */ 272 273/* ++andreas: more optimizations: 274 subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc 275 addal is faster than addaw 276 movep is rather expensive compared to ordinary move's 277 some functions rewritten in C for clarity, no speed loss */ 278 279static __inline__ void *fb_memclear_small(void *s, size_t count) 280{ 281 if (!count) 282 return(0); 283 284 __asm__ __volatile__( 285 "lsrl #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t" 286 "1: lsrl #1,%1 ; jcc 1f ; movew %2,%0@-\n\t" 287 "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@-\n\t" 288 "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t" 289 "1:" 290 : "=a" (s), "=d" (count) 291 : "d" (0), "0" ((char *)s+count), "1" (count) 292 ); 293 __asm__ __volatile__( 294 "subql #1,%1 ; jcs 3f\n\t" 295 "movel %2,%%d4; movel %2,%%d5; movel %2,%%d6\n\t" 296 "2: moveml %2/%%d4/%%d5/%%d6,%0@-\n\t" 297 "dbra %1,2b\n\t" 298 "3:" 299 : "=a" (s), "=d" (count) 300 : "d" (0), "0" (s), "1" (count) 301 : "d4", "d5", "d6" 302 ); 303 304 return(0); 305} 306 307 308static __inline__ void *fb_memclear(void *s, size_t count) 309{ 310 if (!count) 311 return(0); 312 313 if (count < 16) { 314 __asm__ __volatile__( 315 "lsrl #1,%1 ; jcc 1f ; clrb %0@+\n\t" 316 "1: lsrl #1,%1 ; jcc 1f ; clrw %0@+\n\t" 317 "1: lsrl #1,%1 ; jcc 1f ; clrl %0@+\n\t" 318 "1: lsrl #1,%1 ; jcc 1f ; clrl %0@+ ; clrl %0@+\n\t" 319 "1:" 320 : "=a" (s), "=d" (count) 321 : "0" (s), "1" (count) 322 ); 323 } else { 324 long tmp; 325 __asm__ __volatile__( 326 "movel %1,%2\n\t" 327 "lsrl #1,%2 ; jcc 1f ; clrb %0@+ ; subqw #1,%1\n\t" 328 "lsrl #1,%2 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ 329 "clrw %0@+ ; subqw #2,%1 ; jra 2f\n\t" 330 "1: lsrl #1,%2 ; jcc 2f\n\t" 331 "clrw %0@+ ; subqw #2,%1\n\t" 332 "2: movew %1,%2; lsrl #2,%1 ; jeq 6f\n\t" 333 "lsrl #1,%1 ; jcc 3f ; clrl %0@+\n\t" 334 "3: lsrl #1,%1 ; jcc 4f ; clrl %0@+ ; clrl %0@+\n\t" 335 "4: subql #1,%1 ; jcs 6f\n\t" 336 "5: clrl %0@+; clrl %0@+ ; clrl %0@+ ; clrl %0@+\n\t" 337 "dbra %1,5b ; clrw %1; subql #1,%1; jcc 5b\n\t" 338 "6: movew %2,%1; btst #1,%1 ; jeq 7f ; clrw %0@+\n\t" 339 "7: ; btst #0,%1 ; jeq 8f ; clrb %0@+\n\t" 340 "8:" 341 : "=a" (s), "=d" (count), "=d" (tmp) 342 : "0" (s), "1" (count) 343 ); 344 } 345 346 return(0); 347} 348 349 350static __inline__ void *fb_memset255(void *s, size_t count) 351{ 352 if (!count) 353 return(0); 354 355 __asm__ __volatile__( 356 "lsrl #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t" 357 "1: lsrl #1,%1 ; jcc 1f ; movew %2,%0@-\n\t" 358 "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@-\n\t" 359 "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t" 360 "1:" 361 : "=a" (s), "=d" (count) 362 : "d" (-1), "0" ((char *)s+count), "1" (count) 363 ); 364 __asm__ __volatile__( 365 "subql #1,%1 ; jcs 3f\n\t" 366 "movel %2,%%d4; movel %2,%%d5; movel %2,%%d6\n\t" 367 "2: moveml %2/%%d4/%%d5/%%d6,%0@-\n\t" 368 "dbra %1,2b\n\t" 369 "3:" 370 : "=a" (s), "=d" (count) 371 : "d" (-1), "0" (s), "1" (count) 372 : "d4", "d5", "d6" 373 ); 374 375 return(0); 376} 377 378 379static __inline__ void *fb_memmove(void *d, const void *s, size_t count) 380{ 381 if (d < s) { 382 if (count < 16) { 383 __asm__ __volatile__( 384 "lsrl #1,%2 ; jcc 1f ; moveb %1@+,%0@+\n\t" 385 "1: lsrl #1,%2 ; jcc 1f ; movew %1@+,%0@+\n\t" 386 "1: lsrl #1,%2 ; jcc 1f ; movel %1@+,%0@+\n\t" 387 "1: lsrl #1,%2 ; jcc 1f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t" 388 "1:" 389 : "=a" (d), "=a" (s), "=d" (count) 390 : "0" (d), "1" (s), "2" (count) 391 ); 392 } else { 393 long tmp; 394 __asm__ __volatile__( 395 "movel %0,%3\n\t" 396 "lsrl #1,%3 ; jcc 1f ; moveb %1@+,%0@+ ; subqw #1,%2\n\t" 397 "lsrl #1,%3 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ 398 "movew %1@+,%0@+ ; subqw #2,%2 ; jra 2f\n\t" 399 "1: lsrl #1,%3 ; jcc 2f\n\t" 400 "movew %1@+,%0@+ ; subqw #2,%2\n\t" 401 "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t" 402 "lsrl #1,%2 ; jcc 3f ; movel %1@+,%0@+\n\t" 403 "3: lsrl #1,%2 ; jcc 4f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t" 404 "4: subql #1,%2 ; jcs 6f\n\t" 405 "5: movel %1@+,%0@+;movel %1@+,%0@+\n\t" 406 "movel %1@+,%0@+;movel %1@+,%0@+\n\t" 407 "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t" 408 "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@+,%0@+\n\t" 409 "7: ; btst #0,%2 ; jeq 8f ; moveb %1@+,%0@+\n\t" 410 "8:" 411 : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) 412 : "0" (d), "1" (s), "2" (count) 413 ); 414 } 415 } else { 416 if (count < 16) { 417 __asm__ __volatile__( 418 "lsrl #1,%2 ; jcc 1f ; moveb %1@-,%0@-\n\t" 419 "1: lsrl #1,%2 ; jcc 1f ; movew %1@-,%0@-\n\t" 420 "1: lsrl #1,%2 ; jcc 1f ; movel %1@-,%0@-\n\t" 421 "1: lsrl #1,%2 ; jcc 1f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t" 422 "1:" 423 : "=a" (d), "=a" (s), "=d" (count) 424 : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count) 425 ); 426 } else { 427 long tmp; 428 __asm__ __volatile__( 429 "movel %0,%3\n\t" 430 "lsrl #1,%3 ; jcc 1f ; moveb %1@-,%0@- ; subqw #1,%2\n\t" 431 "lsrl #1,%3 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ 432 "movew %1@-,%0@- ; subqw #2,%2 ; jra 2f\n\t" 433 "1: lsrl #1,%3 ; jcc 2f\n\t" 434 "movew %1@-,%0@- ; subqw #2,%2\n\t" 435 "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t" 436 "lsrl #1,%2 ; jcc 3f ; movel %1@-,%0@-\n\t" 437 "3: lsrl #1,%2 ; jcc 4f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t" 438 "4: subql #1,%2 ; jcs 6f\n\t" 439 "5: movel %1@-,%0@-;movel %1@-,%0@-\n\t" 440 "movel %1@-,%0@-;movel %1@-,%0@-\n\t" 441 "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t" 442 "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@-,%0@-\n\t" 443 "7: ; btst #0,%2 ; jeq 8f ; moveb %1@-,%0@-\n\t" 444 "8:" 445 : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) 446 : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count) 447 ); 448 } 449 } 450 451 return(0); 452} 453 454 455/* ++andreas: Simple and fast version of memmove, assumes size is 456 divisible by 16, suitable for moving the whole screen bitplane */ 457static __inline__ void fast_memmove(char *dst, const char *src, size_t size) 458{ 459 if (!size) 460 return; 461 if (dst < src) 462 __asm__ __volatile__ 463 ("1:" 464 " moveml %0@+,%/d0/%/d1/%/a0/%/a1\n" 465 " moveml %/d0/%/d1/%/a0/%/a1,%1@\n" 466 " addql #8,%1; addql #8,%1\n" 467 " dbra %2,1b\n" 468 " clrw %2; subql #1,%2\n" 469 " jcc 1b" 470 : "=a" (src), "=a" (dst), "=d" (size) 471 : "0" (src), "1" (dst), "2" (size / 16 - 1) 472 : "d0", "d1", "a0", "a1", "memory"); 473 else 474 __asm__ __volatile__ 475 ("1:" 476 " subql #8,%0; subql #8,%0\n" 477 " moveml %0@,%/d0/%/d1/%/a0/%/a1\n" 478 " moveml %/d0/%/d1/%/a0/%/a1,%1@-\n" 479 " dbra %2,1b\n" 480 " clrw %2; subql #1,%2\n" 481 " jcc 1b" 482 : "=a" (src), "=a" (dst), "=d" (size) 483 : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1) 484 : "d0", "d1", "a0", "a1", "memory"); 485} 486 487#elif defined(CONFIG_SUN4) 488 489/* You may think that I'm crazy and that I should use generic 490 routines. No, I'm not: sun4's framebuffer crashes if we std 491 into it, so we cannot use memset. */ 492 493static __inline__ void *sun4_memset(void *s, char val, size_t count) 494{ 495 int i; 496 for(i=0; i<count;i++) 497 ((char *) s) [i] = val; 498 return s; 499} 500 501static __inline__ void *fb_memset255(void *s, size_t count) 502{ 503 return sun4_memset(s, 255, count); 504} 505 506static __inline__ void *fb_memclear(void *s, size_t count) 507{ 508 return sun4_memset(s, 0, count); 509} 510 511static __inline__ void *fb_memclear_small(void *s, size_t count) 512{ 513 return sun4_memset(s, 0, count); 514} 515 516/* To be honest, this is slow_memmove :). But sun4 is crappy, so what we can do. */ 517static __inline__ void fast_memmove(void *d, const void *s, size_t count) 518{ 519 int i; 520 if (d<s) { 521 for (i=0; i<count; i++) 522 ((char *) d)[i] = ((char *) s)[i]; 523 } else 524 for (i=0; i<count; i++) 525 ((char *) d)[count-i-1] = ((char *) s)[count-i-1]; 526} 527 528static __inline__ void *fb_memmove(char *dst, const char *src, size_t size) 529{ 530 fast_memmove(dst, src, size); 531 return dst; 532} 533 534#else 535 536static __inline__ void *fb_memclear_small(void *s, size_t count) 537{ 538 char *xs = (char *) s; 539 540 while (count--) 541 fb_writeb(0, xs++); 542 543 return s; 544} 545 546static __inline__ void *fb_memclear(void *s, size_t count) 547{ 548 unsigned long xs = (unsigned long) s; 549 550 if (count < 8) 551 goto rest; 552 553 if (xs & 1) { 554 fb_writeb(0, xs++); 555 count--; 556 } 557 if (xs & 2) { 558 fb_writew(0, xs); 559 xs += 2; 560 count -= 2; 561 } 562 while (count > 3) { 563 fb_writel(0, xs); 564 xs += 4; 565 count -= 4; 566 } 567rest: 568 while (count--) 569 fb_writeb(0, xs++); 570 571 return s; 572} 573 574static __inline__ void *fb_memset255(void *s, size_t count) 575{ 576 unsigned long xs = (unsigned long) s; 577 578 if (count < 8) 579 goto rest; 580 581 if (xs & 1) { 582 fb_writeb(0xff, xs++); 583 count--; 584 } 585 if (xs & 2) { 586 fb_writew(0xffff, xs); 587 xs += 2; 588 count -= 2; 589 } 590 while (count > 3) { 591 fb_writel(0xffffffff, xs); 592 xs += 4; 593 count -= 4; 594 } 595rest: 596 while (count--) 597 fb_writeb(0xff, xs++); 598 599 return s; 600} 601 602#if defined(__i386__) 603 604static __inline__ void fast_memmove(void *d, const void *s, size_t count) 605{ 606 int d0, d1, d2, d3; 607 if (d < s) { 608__asm__ __volatile__ ( 609 "cld\n\t" 610 "shrl $1,%%ecx\n\t" 611 "jnc 1f\n\t" 612 "movsb\n" 613 "1:\tshrl $1,%%ecx\n\t" 614 "jnc 2f\n\t" 615 "movsw\n" 616 "2:\trep\n\t" 617 "movsl" 618 : "=&c" (d0), "=&D" (d1), "=&S" (d2) 619 :"0"(count),"1"((long)d),"2"((long)s) 620 :"memory"); 621 } else { 622__asm__ __volatile__ ( 623 "std\n\t" 624 "shrl $1,%%ecx\n\t" 625 "jnc 1f\n\t" 626 "movb 3(%%esi),%%al\n\t" 627 "movb %%al,3(%%edi)\n\t" 628 "decl %%esi\n\t" 629 "decl %%edi\n" 630 "1:\tshrl $1,%%ecx\n\t" 631 "jnc 2f\n\t" 632 "movw 2(%%esi),%%ax\n\t" 633 "movw %%ax,2(%%edi)\n\t" 634 "decl %%esi\n\t" 635 "decl %%edi\n\t" 636 "decl %%esi\n\t" 637 "decl %%edi\n" 638 "2:\trep\n\t" 639 "movsl\n\t" 640 "cld" 641 : "=&c" (d0), "=&D" (d1), "=&S" (d2), "=&a" (d3) 642 :"0"(count),"1"(count-4+(long)d),"2"(count-4+(long)s) 643 :"memory"); 644 } 645} 646 647static __inline__ void *fb_memmove(char *dst, const char *src, size_t size) 648{ 649 fast_memmove(dst, src, size); 650 return dst; 651} 652 653#else /* !__i386__ */ 654 655 /* 656 * Anyone who'd like to write asm functions for other CPUs? 657 * (Why are these functions better than those from include/asm/string.h?) 658 */ 659 660static __inline__ void *fb_memmove(void *d, const void *s, size_t count) 661{ 662 unsigned long dst, src; 663 664 if (d < s) { 665 dst = (unsigned long) d; 666 src = (unsigned long) s; 667 668 if ((count < 8) || ((dst ^ src) & 3)) 669 goto restup; 670 671 if (dst & 1) { 672 fb_writeb(fb_readb(src++), dst++); 673 count--; 674 } 675 if (dst & 2) { 676 fb_writew(fb_readw(src), dst); 677 src += 2; 678 dst += 2; 679 count -= 2; 680 } 681 while (count > 3) { 682 fb_writel(fb_readl(src), dst); 683 src += 4; 684 dst += 4; 685 count -= 4; 686 } 687 688 restup: 689 while (count--) 690 fb_writeb(fb_readb(src++), dst++); 691 } else { 692 dst = (unsigned long) d + count; 693 src = (unsigned long) s + count; 694 695 if ((count < 8) || ((dst ^ src) & 3)) 696 goto restdown; 697 698 if (dst & 1) { 699 src--; 700 dst--; 701 count--; 702 fb_writeb(fb_readb(src), dst); 703 } 704 if (dst & 2) { 705 src -= 2; 706 dst -= 2; 707 count -= 2; 708 fb_writew(fb_readw(src), dst); 709 } 710 while (count > 3) { 711 src -= 4; 712 dst -= 4; 713 count -= 4; 714 fb_writel(fb_readl(src), dst); 715 } 716 717 restdown: 718 while (count--) { 719 src--; 720 dst--; 721 fb_writeb(fb_readb(src), dst); 722 } 723 } 724 725 return d; 726} 727 728static __inline__ void fast_memmove(char *d, const char *s, size_t count) 729{ 730 unsigned long dst, src; 731 732 if (d < s) { 733 dst = (unsigned long) d; 734 src = (unsigned long) s; 735 736 if ((count < 8) || ((dst ^ src) & 3)) 737 goto restup; 738 739 if (dst & 1) { 740 fb_writeb(fb_readb(src++), dst++); 741 count--; 742 } 743 if (dst & 2) { 744 fb_writew(fb_readw(src), dst); 745 src += 2; 746 dst += 2; 747 count -= 2; 748 } 749 while (count > 3) { 750 fb_writel(fb_readl(src), dst); 751 src += 4; 752 dst += 4; 753 count -= 4; 754 } 755 756 restup: 757 while (count--) 758 fb_writeb(fb_readb(src++), dst++); 759 } else { 760 dst = (unsigned long) d + count; 761 src = (unsigned long) s + count; 762 763 if ((count < 8) || ((dst ^ src) & 3)) 764 goto restdown; 765 766 if (dst & 1) { 767 src--; 768 dst--; 769 count--; 770 fb_writeb(fb_readb(src), dst); 771 } 772 if (dst & 2) { 773 src -= 2; 774 dst -= 2; 775 count -= 2; 776 fb_writew(fb_readw(src), dst); 777 } 778 while (count > 3) { 779 src -= 4; 780 dst -= 4; 781 count -= 4; 782 fb_writel(fb_readl(src), dst); 783 } 784 785 restdown: 786 while (count--) { 787 src--; 788 dst--; 789 fb_writeb(fb_readb(src), dst); 790 } 791 } 792} 793 794#endif /* !__i386__ */ 795 796#endif /* !__mc68000__ */ 797 798#endif /* _VIDEO_FBCON_H */ 799