make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / 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);