File: /usr/src/linux/include/video/fbcon.h

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