File: /usr/src/linux/drivers/video/fbcon-mac.c

1     /*
2      *  linux/drivers/video/fbcon-mac.c -- Low level frame buffer operations for 
3      *				       x bpp packed pixels, font width != 8
4      *
5      *	Created 26 Dec 1997 by Michael Schmitz
6      *	Based on the old macfb.c 6x11 code by Randy Thelen
7      *
8      *	This driver is significantly slower than the 8bit font drivers 
9      *	and would probably benefit from splitting into drivers for each depth.
10      *
11      *  This file is subject to the terms and conditions of the GNU General Public
12      *  License.  See the file COPYING in the main directory of this archive for
13      */
14     
15     #include <linux/module.h>
16     #include <linux/tty.h>
17     #include <linux/console.h>
18     #include <linux/string.h>
19     #include <linux/fb.h>
20     #include <linux/delay.h>
21     
22     #include <video/fbcon.h>
23     #include <video/fbcon-mac.h>
24     
25     
26         /*
27          *  variable bpp packed pixels
28          */
29     
30     static void plot_pixel_mac(struct display *p, int bw, int pixel_x,
31     			   int pixel_y);
32     static int get_pixel_mac(struct display *p, int pixel_x, int pixel_y);
33     
34     void fbcon_mac_setup(struct display *p)
35     {
36         if (p->line_length)
37     	p->next_line = p->line_length;
38         else
39         	p->next_line = p->var.xres_virtual>>3;
40         p->next_plane = 0;
41     }
42     
43     
44        /*
45         *    Macintosh
46         */
47     #define PIXEL_BLACK_MAC          0
48     #define PIXEL_WHITE_MAC          1
49     #define PIXEL_INVERT_MAC         2
50     
51     void fbcon_mac_bmove(struct display *p, int sy, int sx, int dy, int dx,
52     		     int height, int width)
53     {
54        int i, j;
55        u8 *dest, *src;
56        int l,r,t,b,w,lo,s;
57        int dl,dr,dt,db,dw,dlo;
58        int move_up;
59     
60        src = (u8 *) (p->screen_base + sy * fontheight(p) * p->next_line);
61        dest = (u8 *) (p->screen_base + dy * fontheight(p) * p->next_line);
62     
63        if( sx == 0 && width == p->conp->vc_cols) {
64          s = height * fontheight(p) * p->next_line;
65          fb_memmove(dest, src, s);
66          return;
67        }
68        
69        l = sx * fontwidth(p);
70        r = l + width * fontwidth(p);
71        t = sy * fontheight(p);
72        b = t + height * fontheight(p);
73     
74        dl = dx * fontwidth(p);
75        dr = dl + width * fontwidth(p);
76        dt = dy * fontheight(p);
77        db = dt + height * fontheight(p);
78     
79        /* w is the # pixels between two long-aligned points, left and right */
80        w = (r&~31) - ((l+31)&~31);
81        dw = (dr&~31) - ((dl+31)&~31);
82        /* lo is the # pixels between the left edge and a long-aligned left pixel */
83        lo = ((l+31)&~31) - l;
84        dlo = ((dl+31)&~31) - dl;
85        
86        /* if dx != sx then, logic has to align the left and right edges for fast moves */
87        if (lo != dlo) {
88          lo = ((l+7)&~7) - l;
89          dlo = ((dl+7)&~7) - dl;
90          w = (r&~7) - ((l+7)&~7);
91          dw = (dr&~7) - ((dl+7)&~7);
92          if (lo != dlo) {
93            unsigned char err_str[128];
94            unsigned short err_buf[256];
95            unsigned long cnt, len;
96            sprintf( err_str, "ERROR: Shift algorithm: sx=%d,sy=%d,dx=%d,dy=%d,w=%d,h=%d,bpp=%d",
97     		sx,sy,dx,dy,width,height,p->var.bits_per_pixel);
98            len = strlen(err_str);
99            for (cnt = 0; cnt < len; cnt++)
100              err_buf[cnt] = 0x700 | err_str[cnt];
101            fbcon_mac_putcs(p->conp, p, err_buf, len, 0, 0);
102            /* pause for the user */
103            printk( "ERROR: shift algorithm...\n" );
104            mdelay(5000);
105            return;
106          }
107        }
108     
109        s = 0;
110        switch (p->var.bits_per_pixel) {
111        case 1:
112          s = w >> 3;
113          src += lo >> 3;
114          dest += lo >> 3;
115          break;
116        case 2:
117          s = w >> 2;
118          src += lo >> 2;
119          dest += lo >> 2;
120          break;
121        case 4:
122          s = w >> 1;
123          src += lo >> 1;
124          dest += lo >> 1;
125          break;
126        case 8:
127          s = w;
128          src += lo;
129          dest += lo;
130          break;
131        case 16:
132          s = w << 1;
133          src += lo << 1;
134          dest += lo << 1;
135          break;
136        case 32:
137          s = w << 2;
138          src += lo << 2;
139          dest += lo << 2;
140          break;
141        }
142     
143        if (sy <= sx) {
144          i = b;
145          move_up = 0;
146          src += height * fontheight(p);
147          dest += height * fontheight(p);
148        } else {
149          i = t;
150          move_up = 1;
151        }
152     
153        while (1) {
154          for (i = t; i < b; i++) {
155            j = l;
156     
157            for (; j & 31 && j < r; j++)
158     	 plot_pixel_mac(p, get_pixel_mac(p, j+(dx-sx), i+(dy-sy)), j, i);
159     
160            if (j < r) {
161     	 fb_memmove(dest, src, s);
162     	 if (move_up) {
163     	   dest += p->next_line;
164     	   src += p->next_line;
165     	 } else {
166     	   dest -= p->next_line;
167     	   src -= p->next_line;
168     	 }
169     	 j += w;
170            }
171          
172            for (; j < r; j++)
173     	 plot_pixel_mac(p, get_pixel_mac(p, j+(dx-sx), i+(dy-sy)), j, i);
174          }
175     
176          if (move_up) {
177            i++;
178            if (i >= b)
179     	 break;
180          } else {
181            i--;
182            if (i < t)
183     	 break;
184          }
185        }
186     }
187     
188     
189     void fbcon_mac_clear(struct vc_data *conp, struct display *p, int sy, int sx,
190     		     int height, int width)
191     {
192        int pixel;
193        int i, j;
194        int inverse;
195        u8 *dest;
196        int l,r,t,b,w,lo,s;
197     
198        inverse = conp ? attr_reverse(p,conp->vc_attr) : 0;
199        pixel = inverse ? PIXEL_WHITE_MAC : PIXEL_BLACK_MAC;
200        dest = (u8 *) (p->screen_base + sy * fontheight(p) * p->next_line);
201     
202        if( sx == 0 && width == p->conp->vc_cols) {
203          s = height * fontheight(p) * p->next_line;
204          if (inverse)
205            fb_memclear(dest, s);
206          else
207            fb_memset255(dest, s);
208        }
209        
210        l = sx * fontwidth(p);
211        r = l + width * fontwidth(p);
212        t = sy * fontheight(p);
213        b = t + height * fontheight(p);
214        /* w is the # pixels between two long-aligned points, left and right */
215        w = (r&~31) - ((l+31)&~31);
216        /* lo is the # pixels between the left edge and a long-aligned left pixel */
217        lo = ((l+31)&~31) - l;
218        s = 0;
219        switch (p->var.bits_per_pixel) {
220        case 1:
221          s = w >> 3;
222          dest += lo >> 3;
223          break;
224        case 2:
225          s = w >> 2;
226          dest += lo >> 2;
227          break;
228        case 4:
229          s = w >> 1;
230          dest += lo >> 1;
231          break;
232        case 8:
233          s = w;
234          dest += lo;
235          break;
236        case 16:
237          s = w << 1;
238          dest += lo << 1;
239          break;
240        case 32:
241          s = w << 2;
242          dest += lo << 2;
243          break;
244        }
245     
246        for (i = t; i < b; i++) {
247          j = l;
248     
249          for (; j & 31 && j < r; j++)
250            plot_pixel_mac(p, pixel, j, i);
251     
252          if (j < r) {
253            if (PIXEL_WHITE_MAC == pixel)
254     	 fb_memclear(dest, s);
255            else
256     	 fb_memset255(dest, s);
257            dest += p->next_line;
258            j += w;
259          }
260          
261          for (; j < r; j++)
262            plot_pixel_mac(p, pixel, j, i);
263        }
264     }
265     
266     
267     void fbcon_mac_putc(struct vc_data *conp, struct display *p, int c, int yy,
268     		    int xx)
269     {
270        u8 *cdat;
271        u_int rows, bold, ch_reverse, ch_underline;
272        u8 d;
273        int j;
274     
275        cdat = p->fontdata+(c&p->charmask)*fontheight(p);
276        bold = attr_bold(p,c);
277        ch_reverse = attr_reverse(p,c);
278        ch_underline = attr_underline(p,c);
279     
280        for (rows = 0; rows < fontheight(p); rows++) {
281           d = *cdat++;
282           if (!conp->vc_can_do_color) {
283     	if (ch_underline && rows == (fontheight(p)-2))
284     	  d = 0xff;
285     	else if (bold)
286     	  d |= d>>1;
287     	if (ch_reverse)
288     	  d = ~d;
289           }
290           for (j = 0; j < fontwidth(p); j++) {
291     	plot_pixel_mac(p, (d & 0x80) >> 7, (xx*fontwidth(p)) + j, (yy*fontheight(p)) + rows);
292     	d <<= 1;
293           }
294        }
295     }
296     
297     
298     void fbcon_mac_putcs(struct vc_data *conp, struct display *p, 
299     		     const unsigned short *s, int count, int yy, int xx)
300     {
301        u16 c;
302     
303        while (count--) {
304           c = scr_readw(s++);
305           fbcon_mac_putc(conp, p, c, yy, xx++);
306        }
307     }
308     
309     
310     void fbcon_mac_revc(struct display *p, int xx, int yy)
311     {
312        u_int rows, j;
313     
314        for (rows = 0; rows < fontheight(p); rows++) {
315          for (j = 0; j < fontwidth(p); j++) {
316            plot_pixel_mac (p, PIXEL_INVERT_MAC, (xx*fontwidth(p))+j, (yy*fontheight(p))+rows);
317          }
318        }
319     }
320     
321     static inline void plot_helper(u8 *dest, u8 bit, int bw)
322     {
323         switch (bw) {
324         case PIXEL_BLACK_MAC:
325           fb_writeb( fb_readb(dest) | bit, dest );
326           break;
327         case PIXEL_WHITE_MAC:
328           fb_writeb( fb_readb(dest) & (~bit), dest );
329           break;
330         case PIXEL_INVERT_MAC:
331           fb_writeb( fb_readb(dest) ^ bit, dest );
332           break;
333         default:
334           printk( "ERROR: Unknown pixel value in plot_pixel_mac\n");
335         }
336     }
337     
338     /*
339      * plot_pixel_mac
340      */
341     static void plot_pixel_mac(struct display *p, int bw, int pixel_x, int pixel_y)
342     {
343       u8 *dest, bit;
344       u16 *dest16, pix16;
345       u32 *dest32, pix32;
346     
347       /* There *are* 68k Macs that support more than 832x624, you know :-) */
348       if (pixel_x < 0 || pixel_y < 0 || pixel_x >= p->var.xres || pixel_y >= p->var.yres) {
349         printk ("ERROR: pixel_x == %d, pixel_y == %d", pixel_x, pixel_y);
350         mdelay(1000);
351         return;
352       }
353     
354       switch (p->var.bits_per_pixel) {
355       case 1:
356         dest = (u8 *) ((pixel_x >> 3) + p->screen_base + pixel_y * p->next_line);
357         bit = 0x80 >> (pixel_x & 7);
358         plot_helper(dest, bit, bw);
359         break;
360     
361       case 2:
362         dest = (u8 *) ((pixel_x >> 2) + p->screen_base + pixel_y * p->next_line);
363         bit = 0xC0 >> ((pixel_x & 3) << 1);
364         plot_helper(dest, bit, bw);
365         break;
366     
367       case 4:
368         dest = (u8 *) ((pixel_x >> 1) + p->screen_base + pixel_y * p->next_line);
369         bit = 0xF0 >> ((pixel_x & 1) << 2);
370         plot_helper(dest, bit, bw);
371         break;
372     
373       case 8:
374         dest = (u8 *) (pixel_x + p->screen_base + pixel_y * p->next_line);
375         bit = 0xFF;
376         plot_helper(dest, bit, bw);
377         break;
378     
379     /* FIXME: You can't access framebuffer directly like this! */
380       case 16:
381         dest16 = (u16 *) ((pixel_x *2) + p->screen_base + pixel_y * p->next_line);
382         pix16 = 0xFFFF;
383         switch (bw) {
384         case PIXEL_BLACK_MAC:  *dest16 = ~pix16; break;
385         case PIXEL_WHITE_MAC:  *dest16 = pix16;  break;
386         case PIXEL_INVERT_MAC: *dest16 ^= pix16; break;
387         default: printk( "ERROR: Unknown pixel value in plot_pixel_mac\n");
388         }
389         break;
390     
391       case 32:
392         dest32 = (u32 *) ((pixel_x *4) + p->screen_base + pixel_y * p->next_line);
393         pix32 = 0xFFFFFFFF;
394         switch (bw) {
395         case PIXEL_BLACK_MAC:  *dest32 = ~pix32; break;
396         case PIXEL_WHITE_MAC:  *dest32 = pix32;  break;
397         case PIXEL_INVERT_MAC: *dest32 ^= pix32; break;
398         default: printk( "ERROR: Unknown pixel value in plot_pixel_mac\n");
399         }
400         break;
401       }
402     }
403     
404     static int get_pixel_mac(struct display *p, int pixel_x, int pixel_y)
405     {
406       u8 *dest, bit;
407       u16 *dest16;
408       u32 *dest32;
409       u8 pixel=0;
410     
411       switch (p->var.bits_per_pixel) {
412       case 1:
413         dest = (u8 *) ((pixel_x / 8) + p->screen_base + pixel_y * p->next_line);
414         bit = 0x80 >> (pixel_x & 7);
415         pixel = *dest & bit;
416         break;
417       case 2:
418         dest = (u8 *) ((pixel_x / 4) + p->screen_base + pixel_y * p->next_line);
419         bit = 0xC0 >> (pixel_x & 3);
420         pixel = *dest & bit;
421         break;
422       case 4:
423         dest = (u8 *) ((pixel_x / 2) + p->screen_base + pixel_y * p->next_line);
424         bit = 0xF0 >> (pixel_x & 1);
425         pixel = *dest & bit;
426         break;
427       case 8:
428         dest = (u8 *) (pixel_x + p->screen_base + pixel_y * p->next_line);
429         pixel = *dest;
430         break;
431       case 16:
432         dest16 = (u16 *) ((pixel_x *2) + p->screen_base + pixel_y * p->next_line);
433         pixel = *dest16 ? 1 : 0;
434         break;
435       case 32:
436         dest32 = (u32 *) ((pixel_x *4) + p->screen_base + pixel_y * p->next_line);
437         pixel = *dest32 ? 1 : 0;
438         break;
439       }
440     
441       return pixel ? PIXEL_BLACK_MAC : PIXEL_WHITE_MAC;
442     }
443     
444     
445         /*
446          *  `switch' for the low level operations
447          */
448     
449     struct display_switch fbcon_mac = {
450         setup:		fbcon_mac_setup,
451         bmove:		fbcon_redraw_bmove,
452         clear:		fbcon_redraw_clear,
453         putc:		fbcon_mac_putc,
454         putcs:		fbcon_mac_putcs,
455         revc:		fbcon_mac_revc,
456         fontwidthmask:	FONTWIDTHRANGE(1,8)
457     };
458     
459     
460     #ifdef MODULE
461     MODULE_LICENSE("GPL");
462     
463     int init_module(void)
464     {
465         return 0;
466     }
467     
468     void cleanup_module(void)
469     {}
470     #endif /* MODULE */
471     
472     
473         /*
474          *  Visible symbols for modules
475          */
476     
477     EXPORT_SYMBOL(fbcon_mac);
478     EXPORT_SYMBOL(fbcon_mac_setup);
479     EXPORT_SYMBOL(fbcon_mac_bmove);
480     EXPORT_SYMBOL(fbcon_mac_clear);
481     EXPORT_SYMBOL(fbcon_mac_putc);
482     EXPORT_SYMBOL(fbcon_mac_putcs);
483     EXPORT_SYMBOL(fbcon_mac_revc);
484