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__) || \
210       defined(__x86_64__) || defined(__hppa__) || \
211       defined(__powerpc64__)
212 
213 #define fb_readb __raw_readb
214 #define fb_readw __raw_readw
215 #define fb_readl __raw_readl
216 #define fb_writeb __raw_writeb
217 #define fb_writew __raw_writew
218 #define fb_writel __raw_writel
219 #define fb_memset memset_io
220 
221 #else
222 
223 #define fb_readb(addr) (*(volatile u8 *) (addr))
224 #define fb_readw(addr) (*(volatile u16 *) (addr))
225 #define fb_readl(addr) (*(volatile u32 *) (addr))
226 #define fb_writeb(b,addr) (*(volatile u8 *) (addr) = (b))
227 #define fb_writew(b,addr) (*(volatile u16 *) (addr) = (b))
228 #define fb_writel(b,addr) (*(volatile u32 *) (addr) = (b))
229 #define fb_memset memset
230 
231 #endif
232 
233 
234 extern void fbcon_redraw_clear(struct vc_data *, struct display *, int, int, int, int);
235 extern void fbcon_redraw_bmove(struct display *, int, int, int, int, int, int);
236 
237 
238 /* ================================================================= */
239 /*                      Utility Assembler Functions                  */
240 /* ================================================================= */
241 
242 
243 #if defined(__mc68000__)
244 
245 /* ====================================================================== */
246 
247 /* Those of a delicate disposition might like to skip the next couple of
248  * pages.
249  *
250  * These functions are drop in replacements for memmove and
251  * memset(_, 0, _). However their five instances add at least a kilobyte
252  * to the object file. You have been warned.
253  *
254  * Not a great fan of assembler for the sake of it, but I think
255  * that these routines are at least 10 times faster than their C
256  * equivalents for large blits, and that's important to the lowest level of
257  * a graphics driver. Question is whether some scheme with the blitter
258  * would be faster. I suspect not for simple text system - not much
259  * asynchrony.
260  *
261  * Code is very simple, just gruesome expansion. Basic strategy is to
262  * increase data moved/cleared at each step to 16 bytes to reduce
263  * instruction per data move overhead. movem might be faster still
264  * For more than 15 bytes, we try to align the write direction on a
265  * longword boundary to get maximum speed. This is even more gruesome.
266  * Unaligned read/write used requires 68020+ - think this is a problem?
267  *
268  * Sorry!
269  */
270 
271 
272 /* ++roman: I've optimized Robert's original versions in some minor
273  * aspects, e.g. moveq instead of movel, let gcc choose the registers,
274  * use movem in some places...
275  * For other modes than 1 plane, lots of more such assembler functions
276  * were needed (e.g. the ones using movep or expanding color values).
277  */
278 
279 /* ++andreas: more optimizations:
280    subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc
281    addal is faster than addaw
282    movep is rather expensive compared to ordinary move's
283    some functions rewritten in C for clarity, no speed loss */
284 
fb_memclear_small(void * s,size_t count)285 static __inline__ void *fb_memclear_small(void *s, size_t count)
286 {
287    if (!count)
288       return(0);
289 
290    __asm__ __volatile__(
291          "lsrl   #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t"
292       "1: lsrl   #1,%1 ; jcc 1f ; movew %2,%0@-\n\t"
293       "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@-\n\t"
294       "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t"
295       "1:"
296          : "=a" (s), "=d" (count)
297          : "d" (0), "0" ((char *)s+count), "1" (count)
298    );
299    __asm__ __volatile__(
300          "subql  #1,%1 ; jcs 3f\n\t"
301 	 "movel %2,%%d4; movel %2,%%d5; movel %2,%%d6\n\t"
302       "2: moveml %2/%%d4/%%d5/%%d6,%0@-\n\t"
303          "dbra %1,2b\n\t"
304       "3:"
305          : "=a" (s), "=d" (count)
306          : "d" (0), "0" (s), "1" (count)
307 	 : "d4", "d5", "d6"
308   );
309 
310    return(0);
311 }
312 
313 
fb_memclear(void * s,size_t count)314 static __inline__ void *fb_memclear(void *s, size_t count)
315 {
316    if (!count)
317       return(0);
318 
319    if (count < 16) {
320       __asm__ __volatile__(
321             "lsrl   #1,%1 ; jcc 1f ; clrb %0@+\n\t"
322          "1: lsrl   #1,%1 ; jcc 1f ; clrw %0@+\n\t"
323          "1: lsrl   #1,%1 ; jcc 1f ; clrl %0@+\n\t"
324          "1: lsrl   #1,%1 ; jcc 1f ; clrl %0@+ ; clrl %0@+\n\t"
325          "1:"
326             : "=a" (s), "=d" (count)
327             : "0" (s), "1" (count)
328      );
329    } else {
330       long tmp;
331       __asm__ __volatile__(
332             "movel %1,%2\n\t"
333             "lsrl   #1,%2 ; jcc 1f ; clrb %0@+ ; subqw #1,%1\n\t"
334             "lsrl   #1,%2 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
335             "clrw   %0@+  ; subqw  #2,%1 ; jra 2f\n\t"
336          "1: lsrl   #1,%2 ; jcc 2f\n\t"
337             "clrw   %0@+  ; subqw  #2,%1\n\t"
338          "2: movew %1,%2; lsrl #2,%1 ; jeq 6f\n\t"
339             "lsrl   #1,%1 ; jcc 3f ; clrl %0@+\n\t"
340          "3: lsrl   #1,%1 ; jcc 4f ; clrl %0@+ ; clrl %0@+\n\t"
341          "4: subql  #1,%1 ; jcs 6f\n\t"
342          "5: clrl %0@+; clrl %0@+ ; clrl %0@+ ; clrl %0@+\n\t"
343             "dbra %1,5b   ; clrw %1; subql #1,%1; jcc 5b\n\t"
344          "6: movew %2,%1; btst #1,%1 ; jeq 7f ; clrw %0@+\n\t"
345          "7:            ; btst #0,%1 ; jeq 8f ; clrb %0@+\n\t"
346          "8:"
347             : "=a" (s), "=d" (count), "=d" (tmp)
348             : "0" (s), "1" (count)
349      );
350    }
351 
352    return(0);
353 }
354 
355 
fb_memset255(void * s,size_t count)356 static __inline__ void *fb_memset255(void *s, size_t count)
357 {
358    if (!count)
359       return(0);
360 
361    __asm__ __volatile__(
362          "lsrl   #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t"
363       "1: lsrl   #1,%1 ; jcc 1f ; movew %2,%0@-\n\t"
364       "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@-\n\t"
365       "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t"
366       "1:"
367          : "=a" (s), "=d" (count)
368          : "d" (-1), "0" ((char *)s+count), "1" (count)
369    );
370    __asm__ __volatile__(
371          "subql  #1,%1 ; jcs 3f\n\t"
372 	 "movel %2,%%d4; movel %2,%%d5; movel %2,%%d6\n\t"
373       "2: moveml %2/%%d4/%%d5/%%d6,%0@-\n\t"
374          "dbra %1,2b\n\t"
375       "3:"
376          : "=a" (s), "=d" (count)
377          : "d" (-1), "0" (s), "1" (count)
378 	 : "d4", "d5", "d6"
379   );
380 
381    return(0);
382 }
383 
384 
fb_memmove(void * d,const void * s,size_t count)385 static __inline__ void *fb_memmove(void *d, const void *s, size_t count)
386 {
387    if (d < s) {
388       if (count < 16) {
389          __asm__ __volatile__(
390                "lsrl   #1,%2 ; jcc 1f ; moveb %1@+,%0@+\n\t"
391             "1: lsrl   #1,%2 ; jcc 1f ; movew %1@+,%0@+\n\t"
392             "1: lsrl   #1,%2 ; jcc 1f ; movel %1@+,%0@+\n\t"
393             "1: lsrl   #1,%2 ; jcc 1f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t"
394             "1:"
395                : "=a" (d), "=a" (s), "=d" (count)
396                : "0" (d), "1" (s), "2" (count)
397         );
398       } else {
399          long tmp;
400          __asm__ __volatile__(
401                "movel  %0,%3\n\t"
402                "lsrl   #1,%3 ; jcc 1f ; moveb %1@+,%0@+ ; subqw #1,%2\n\t"
403                "lsrl   #1,%3 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
404                "movew  %1@+,%0@+  ; subqw  #2,%2 ; jra 2f\n\t"
405             "1: lsrl   #1,%3 ; jcc 2f\n\t"
406                "movew  %1@+,%0@+  ; subqw  #2,%2\n\t"
407             "2: movew  %2,%-; lsrl #2,%2 ; jeq 6f\n\t"
408                "lsrl   #1,%2 ; jcc 3f ; movel %1@+,%0@+\n\t"
409             "3: lsrl   #1,%2 ; jcc 4f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t"
410             "4: subql  #1,%2 ; jcs 6f\n\t"
411             "5: movel  %1@+,%0@+;movel %1@+,%0@+\n\t"
412                "movel  %1@+,%0@+;movel %1@+,%0@+\n\t"
413                "dbra   %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t"
414             "6: movew  %+,%2; btst #1,%2 ; jeq 7f ; movew %1@+,%0@+\n\t"
415             "7:              ; btst #0,%2 ; jeq 8f ; moveb %1@+,%0@+\n\t"
416             "8:"
417                : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
418                : "0" (d), "1" (s), "2" (count)
419         );
420       }
421    } else {
422       if (count < 16) {
423          __asm__ __volatile__(
424                "lsrl   #1,%2 ; jcc 1f ; moveb %1@-,%0@-\n\t"
425             "1: lsrl   #1,%2 ; jcc 1f ; movew %1@-,%0@-\n\t"
426             "1: lsrl   #1,%2 ; jcc 1f ; movel %1@-,%0@-\n\t"
427             "1: lsrl   #1,%2 ; jcc 1f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t"
428             "1:"
429                : "=a" (d), "=a" (s), "=d" (count)
430                : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)
431         );
432       } else {
433          long tmp;
434          __asm__ __volatile__(
435                "movel %0,%3\n\t"
436                "lsrl   #1,%3 ; jcc 1f ; moveb %1@-,%0@- ; subqw #1,%2\n\t"
437                "lsrl   #1,%3 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
438                "movew  %1@-,%0@-  ; subqw  #2,%2 ; jra 2f\n\t"
439             "1: lsrl   #1,%3 ; jcc 2f\n\t"
440                "movew  %1@-,%0@-  ; subqw  #2,%2\n\t"
441             "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t"
442                "lsrl   #1,%2 ; jcc 3f ; movel %1@-,%0@-\n\t"
443             "3: lsrl   #1,%2 ; jcc 4f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t"
444             "4: subql  #1,%2 ; jcs 6f\n\t"
445             "5: movel %1@-,%0@-;movel %1@-,%0@-\n\t"
446                "movel %1@-,%0@-;movel %1@-,%0@-\n\t"
447                "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t"
448             "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@-,%0@-\n\t"
449             "7:              ; btst #0,%2 ; jeq 8f ; moveb %1@-,%0@-\n\t"
450             "8:"
451                : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
452                : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)
453         );
454       }
455    }
456 
457    return(0);
458 }
459 
460 
461 /* ++andreas: Simple and fast version of memmove, assumes size is
462    divisible by 16, suitable for moving the whole screen bitplane */
fast_memmove(char * dst,const char * src,size_t size)463 static __inline__ void fast_memmove(char *dst, const char *src, size_t size)
464 {
465   if (!size)
466     return;
467   if (dst < src)
468     __asm__ __volatile__
469       ("1:"
470        "  moveml %0@+,%/d0/%/d1/%/a0/%/a1\n"
471        "  moveml %/d0/%/d1/%/a0/%/a1,%1@\n"
472        "  addql #8,%1; addql #8,%1\n"
473        "  dbra %2,1b\n"
474        "  clrw %2; subql #1,%2\n"
475        "  jcc 1b"
476        : "=a" (src), "=a" (dst), "=d" (size)
477        : "0" (src), "1" (dst), "2" (size / 16 - 1)
478        : "d0", "d1", "a0", "a1", "memory");
479   else
480     __asm__ __volatile__
481       ("1:"
482        "  subql #8,%0; subql #8,%0\n"
483        "  moveml %0@,%/d0/%/d1/%/a0/%/a1\n"
484        "  moveml %/d0/%/d1/%/a0/%/a1,%1@-\n"
485        "  dbra %2,1b\n"
486        "  clrw %2; subql #1,%2\n"
487        "  jcc 1b"
488        : "=a" (src), "=a" (dst), "=d" (size)
489        : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1)
490        : "d0", "d1", "a0", "a1", "memory");
491 }
492 
493 #elif defined(CONFIG_SUN4)
494 
495 /* You may think that I'm crazy and that I should use generic
496    routines.  No, I'm not: sun4's framebuffer crashes if we std
497    into it, so we cannot use memset.  */
498 
sun4_memset(void * s,char val,size_t count)499 static __inline__ void *sun4_memset(void *s, char val, size_t count)
500 {
501     int i;
502     for(i=0; i<count;i++)
503         ((char *) s) [i] = val;
504     return s;
505 }
506 
fb_memset255(void * s,size_t count)507 static __inline__ void *fb_memset255(void *s, size_t count)
508 {
509     return sun4_memset(s, 255, count);
510 }
511 
fb_memclear(void * s,size_t count)512 static __inline__ void *fb_memclear(void *s, size_t count)
513 {
514     return sun4_memset(s, 0, count);
515 }
516 
fb_memclear_small(void * s,size_t count)517 static __inline__ void *fb_memclear_small(void *s, size_t count)
518 {
519     return sun4_memset(s, 0, count);
520 }
521 
522 /* To be honest, this is slow_memmove :). But sun4 is crappy, so what we can do. */
fast_memmove(void * d,const void * s,size_t count)523 static __inline__ void fast_memmove(void *d, const void *s, size_t count)
524 {
525     int i;
526     if (d<s) {
527 	for (i=0; i<count; i++)
528 	    ((char *) d)[i] = ((char *) s)[i];
529     } else
530 	for (i=0; i<count; i++)
531 	    ((char *) d)[count-i-1] = ((char *) s)[count-i-1];
532 }
533 
fb_memmove(char * dst,const char * src,size_t size)534 static __inline__ void *fb_memmove(char *dst, const char *src, size_t size)
535 {
536     fast_memmove(dst, src, size);
537     return dst;
538 }
539 
540 #else
541 
fb_memclear_small(void * s,size_t count)542 static __inline__ void *fb_memclear_small(void *s, size_t count)
543 {
544     char *xs = (char *) s;
545 
546     while (count--)
547 	fb_writeb(0, xs++);
548 
549     return s;
550 }
551 
fb_memclear(void * s,size_t count)552 static __inline__ void *fb_memclear(void *s, size_t count)
553 {
554     unsigned long xs = (unsigned long) s;
555 
556     if (count < 8)
557 	goto rest;
558 
559     if (xs & 1) {
560 	fb_writeb(0, xs++);
561 	count--;
562     }
563     if (xs & 2) {
564 	fb_writew(0, xs);
565 	xs += 2;
566 	count -= 2;
567     }
568     while (count > 3) {
569 	fb_writel(0, xs);
570 	xs += 4;
571 	count -= 4;
572     }
573 rest:
574     while (count--)
575 	fb_writeb(0, xs++);
576 
577     return s;
578 }
579 
fb_memset255(void * s,size_t count)580 static __inline__ void *fb_memset255(void *s, size_t count)
581 {
582     unsigned long xs = (unsigned long) s;
583 
584     if (count < 8)
585 	goto rest;
586 
587     if (xs & 1) {
588 	fb_writeb(0xff, xs++);
589 	count--;
590     }
591     if (xs & 2) {
592 	fb_writew(0xffff, xs);
593 	xs += 2;
594 	count -= 2;
595     }
596     while (count > 3) {
597 	fb_writel(0xffffffff, xs);
598 	xs += 4;
599 	count -= 4;
600     }
601 rest:
602     while (count--)
603 	fb_writeb(0xff, xs++);
604 
605     return s;
606 }
607 
608 #if defined(__i386__)
609 
fast_memmove(void * d,const void * s,size_t count)610 static __inline__ void fast_memmove(void *d, const void *s, size_t count)
611 {
612   int d0, d1, d2, d3;
613     if (d < s) {
614 __asm__ __volatile__ (
615 	"cld\n\t"
616 	"shrl $1,%%ecx\n\t"
617 	"jnc 1f\n\t"
618 	"movsb\n"
619 	"1:\tshrl $1,%%ecx\n\t"
620 	"jnc 2f\n\t"
621 	"movsw\n"
622 	"2:\trep\n\t"
623 	"movsl"
624 	: "=&c" (d0), "=&D" (d1), "=&S" (d2)
625 	:"0"(count),"1"((long)d),"2"((long)s)
626 	:"memory");
627     } else {
628 __asm__ __volatile__ (
629 	"std\n\t"
630 	"shrl $1,%%ecx\n\t"
631 	"jnc 1f\n\t"
632 	"movb 3(%%esi),%%al\n\t"
633 	"movb %%al,3(%%edi)\n\t"
634 	"decl %%esi\n\t"
635 	"decl %%edi\n"
636 	"1:\tshrl $1,%%ecx\n\t"
637 	"jnc 2f\n\t"
638 	"movw 2(%%esi),%%ax\n\t"
639 	"movw %%ax,2(%%edi)\n\t"
640 	"decl %%esi\n\t"
641 	"decl %%edi\n\t"
642 	"decl %%esi\n\t"
643 	"decl %%edi\n"
644 	"2:\trep\n\t"
645 	"movsl\n\t"
646 	"cld"
647 	: "=&c" (d0), "=&D" (d1), "=&S" (d2), "=&a" (d3)
648 	:"0"(count),"1"(count-4+(long)d),"2"(count-4+(long)s)
649 	:"memory");
650     }
651 }
652 
fb_memmove(char * dst,const char * src,size_t size)653 static __inline__ void *fb_memmove(char *dst, const char *src, size_t size)
654 {
655     fast_memmove(dst, src, size);
656     return dst;
657 }
658 
659 #else /* !__i386__ */
660 
661     /*
662      *  Anyone who'd like to write asm functions for other CPUs?
663      *   (Why are these functions better than those from include/asm/string.h?)
664      */
665 
fb_memmove(void * d,const void * s,size_t count)666 static __inline__ void *fb_memmove(void *d, const void *s, size_t count)
667 {
668     unsigned long dst, src;
669 
670     if (d < s) {
671 	dst = (unsigned long) d;
672 	src = (unsigned long) s;
673 
674 	if ((count < 8) || ((dst ^ src) & 3))
675 	    goto restup;
676 
677 	if (dst & 1) {
678 	    fb_writeb(fb_readb(src++), dst++);
679 	    count--;
680 	}
681 	if (dst & 2) {
682 	    fb_writew(fb_readw(src), dst);
683 	    src += 2;
684 	    dst += 2;
685 	    count -= 2;
686 	}
687 	while (count > 3) {
688 	    fb_writel(fb_readl(src), dst);
689 	    src += 4;
690 	    dst += 4;
691 	    count -= 4;
692 	}
693 
694     restup:
695 	while (count--)
696 	    fb_writeb(fb_readb(src++), dst++);
697     } else {
698 	dst = (unsigned long) d + count;
699 	src = (unsigned long) s + count;
700 
701 	if ((count < 8) || ((dst ^ src) & 3))
702 	    goto restdown;
703 
704 	if (dst & 1) {
705 	    src--;
706 	    dst--;
707 	    count--;
708 	    fb_writeb(fb_readb(src), dst);
709 	}
710 	if (dst & 2) {
711 	    src -= 2;
712 	    dst -= 2;
713 	    count -= 2;
714 	    fb_writew(fb_readw(src), dst);
715 	}
716 	while (count > 3) {
717 	    src -= 4;
718 	    dst -= 4;
719 	    count -= 4;
720 	    fb_writel(fb_readl(src), dst);
721 	}
722 
723     restdown:
724 	while (count--) {
725 	    src--;
726 	    dst--;
727 	    fb_writeb(fb_readb(src), dst);
728 	}
729     }
730 
731     return d;
732 }
733 
fast_memmove(char * d,const char * s,size_t count)734 static __inline__ void fast_memmove(char *d, const char *s, size_t count)
735 {
736     unsigned long dst, src;
737 
738     if (d < s) {
739 	dst = (unsigned long) d;
740 	src = (unsigned long) s;
741 
742 	if ((count < 8) || ((dst ^ src) & 3))
743 	    goto restup;
744 
745 	if (dst & 1) {
746 	    fb_writeb(fb_readb(src++), dst++);
747 	    count--;
748 	}
749 	if (dst & 2) {
750 	    fb_writew(fb_readw(src), dst);
751 	    src += 2;
752 	    dst += 2;
753 	    count -= 2;
754 	}
755 	while (count > 3) {
756 	    fb_writel(fb_readl(src), dst);
757 	    src += 4;
758 	    dst += 4;
759 	    count -= 4;
760 	}
761 
762     restup:
763 	while (count--)
764 	    fb_writeb(fb_readb(src++), dst++);
765     } else {
766 	dst = (unsigned long) d + count;
767 	src = (unsigned long) s + count;
768 
769 	if ((count < 8) || ((dst ^ src) & 3))
770 	    goto restdown;
771 
772 	if (dst & 1) {
773 	    src--;
774 	    dst--;
775 	    count--;
776 	    fb_writeb(fb_readb(src), dst);
777 	}
778 	if (dst & 2) {
779 	    src -= 2;
780 	    dst -= 2;
781 	    count -= 2;
782 	    fb_writew(fb_readw(src), dst);
783 	}
784 	while (count > 3) {
785 	    src -= 4;
786 	    dst -= 4;
787 	    count -= 4;
788 	    fb_writel(fb_readl(src), dst);
789 	}
790 
791     restdown:
792 	while (count--) {
793 	    src--;
794 	    dst--;
795 	    fb_writeb(fb_readb(src), dst);
796 	}
797     }
798 }
799 
800 #endif /* !__i386__ */
801 
802 #endif /* !__mc68000__ */
803 
804 #endif /* _VIDEO_FBCON_H */
805