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
fbcon_mac_setup(struct display * p)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
fbcon_mac_bmove(struct display * p,int sy,int sx,int dy,int dx,int height,int width)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
fbcon_mac_clear(struct vc_data * conp,struct display * p,int sy,int sx,int height,int width)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
fbcon_mac_putc(struct vc_data * conp,struct display * p,int c,int yy,int xx)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
fbcon_mac_putcs(struct vc_data * conp,struct display * p,const unsigned short * s,int count,int yy,int xx)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
fbcon_mac_revc(struct display * p,int xx,int yy)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
plot_helper(u8 * dest,u8 bit,int bw)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 */
plot_pixel_mac(struct display * p,int bw,int pixel_x,int pixel_y)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
get_pixel_mac(struct display * p,int pixel_x,int pixel_y)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
init_module(void)463 int init_module(void)
464 {
465 return 0;
466 }
467
cleanup_module(void)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