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