1 /*
2 * bcm2385 framebuffer
3 */
4
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10
11 #define Image IMAGE
12 #include <draw.h>
13 #include <memdraw.h>
14 #include <cursor.h>
15 #include "screen.h"
16
17 enum {
18 Tabstop = 4,
19 Scroll = 8,
20 Wid = 1024,
21 Ht = 768,
22 Depth = 16,
23 };
24
25 Cursor arrow = {
26 { -1, -1 },
27 { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
28 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
29 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
30 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
31 },
32 { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
33 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
34 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
35 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
36 },
37 };
38
39 Memimage *gscreen;
40 Lcd *lcd;
41
42 static Memdata xgdata;
43
44 /*static*/ Memimage xgscreen =
45 {
46 { 0, 0, Wid, Ht }, /* r */
47 { 0, 0, Wid, Ht }, /* clipr */
48 Depth, /* depth */
49 3, /* nchan */
50 RGB16, /* chan */
51 nil, /* cmap */
52 &xgdata, /* data */
53 0, /* zero */
54 0, /* width in words of a single scan line */
55 0, /* layer */
56 0, /* flags */
57 };
58
59 static Memimage *conscol;
60 static Memimage *back;
61 static Memsubfont *memdefont;
62
63 static Lock screenlock;
64
65 static Point curpos;
66 static int h, w;
67 static Rectangle window;
68
69 static void myscreenputs(char *s, int n);
70 static void screenputc(char *buf);
71 static void screenwin(void);
72
73 /*
74 * Software cursor.
75 */
76 static int swvisible; /* is the cursor visible? */
77 static int swenabled; /* is the cursor supposed to be on the screen? */
78 static Memimage *swback; /* screen under cursor */
79 static Memimage *swimg; /* cursor image */
80 static Memimage *swmask; /* cursor mask */
81 static Memimage *swimg1;
82 static Memimage *swmask1;
83
84 static Point swoffset;
85 static Rectangle swrect; /* screen rectangle in swback */
86 static Point swpt; /* desired cursor location */
87 static Point swvispt; /* actual cursor location */
88 static int swvers; /* incremented each time cursor image changes */
89 static int swvisvers; /* the version on the screen */
90
91 /*
92 * called with drawlock locked for us, most of the time.
93 * kernel prints at inopportune times might mean we don't
94 * hold the lock, but memimagedraw is now reentrant so
95 * that should be okay: worst case we get cursor droppings.
96 */
97 static void
swcursorhide(void)98 swcursorhide(void)
99 {
100 if(swvisible == 0)
101 return;
102 if(swback == nil)
103 return;
104 swvisible = 0;
105 memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
106 flushmemscreen(swrect);
107 }
108
109 static void
swcursoravoid(Rectangle r)110 swcursoravoid(Rectangle r)
111 {
112 if(swvisible && rectXrect(r, swrect))
113 swcursorhide();
114 }
115
116 static void
swcursordraw(void)117 swcursordraw(void)
118 {
119 int dounlock;
120
121 if(swvisible)
122 return;
123 if(swenabled == 0)
124 return;
125 if(swback == nil || swimg1 == nil || swmask1 == nil)
126 return;
127 dounlock = canqlock(&drawlock);
128 swvispt = swpt;
129 swvisvers = swvers;
130 swrect = rectaddpt(Rect(0,0,16,16), swvispt);
131 memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
132 memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
133 flushmemscreen(swrect);
134 swvisible = 1;
135 if(dounlock)
136 qunlock(&drawlock);
137 }
138
139 int
cursoron(int dolock)140 cursoron(int dolock)
141 {
142 int retry;
143
144 if (dolock)
145 lock(&cursor);
146 if (canqlock(&drawlock)) {
147 retry = 0;
148 swcursorhide();
149 swcursordraw();
150 qunlock(&drawlock);
151 } else
152 retry = 1;
153 if (dolock)
154 unlock(&cursor);
155 return retry;
156 }
157
158 void
cursoroff(int dolock)159 cursoroff(int dolock)
160 {
161 if (dolock)
162 lock(&cursor);
163 swcursorhide();
164 if (dolock)
165 unlock(&cursor);
166 }
167
168 static void
swload(Cursor * curs)169 swload(Cursor *curs)
170 {
171 uchar *ip, *mp;
172 int i, j, set, clr;
173
174 if(!swimg || !swmask || !swimg1 || !swmask1)
175 return;
176 /*
177 * Build cursor image and mask.
178 * Image is just the usual cursor image
179 * but mask is a transparent alpha mask.
180 *
181 * The 16x16x8 memimages do not have
182 * padding at the end of their scan lines.
183 */
184 ip = byteaddr(swimg, ZP);
185 mp = byteaddr(swmask, ZP);
186 for(i=0; i<32; i++){
187 set = curs->set[i];
188 clr = curs->clr[i];
189 for(j=0x80; j; j>>=1){
190 *ip++ = set&j ? 0x00 : 0xFF;
191 *mp++ = (clr|set)&j ? 0xFF : 0x00;
192 }
193 }
194 swoffset = curs->offset;
195 swvers++;
196 memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
197 memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
198 }
199
200 /* called from devmouse */
201 void
setcursor(Cursor * curs)202 setcursor(Cursor* curs)
203 {
204 cursoroff(0);
205 swload(curs);
206 cursoron(0);
207 }
208
209 static int
swmove(Point p)210 swmove(Point p)
211 {
212 swpt = addpt(p, swoffset);
213 return 0;
214 }
215
216 static void
swcursorclock(void)217 swcursorclock(void)
218 {
219 int x;
220
221 if(!swenabled)
222 return;
223 swmove(mousexy());
224 if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
225 return;
226
227 x = splhi();
228 if(swenabled)
229 if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
230 if(canqlock(&drawlock)){
231 swcursorhide();
232 swcursordraw();
233 qunlock(&drawlock);
234 }
235 splx(x);
236 }
237
238 void
swcursorinit(void)239 swcursorinit(void)
240 {
241 static int init;
242
243 if(!init){
244 init = 1;
245 addclock0link(swcursorclock, 10);
246 swenabled = 1;
247 }
248 if(swback){
249 freememimage(swback);
250 freememimage(swmask);
251 freememimage(swmask1);
252 freememimage(swimg);
253 freememimage(swimg1);
254 }
255
256 swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
257 swmask = allocmemimage(Rect(0,0,16,16), GREY8);
258 swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
259 swimg = allocmemimage(Rect(0,0,16,16), GREY8);
260 swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
261 if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
262 print("software cursor: allocmemimage fails\n");
263 return;
264 }
265
266 memfillcolor(swmask, DOpaque);
267 memfillcolor(swmask1, DOpaque);
268 memfillcolor(swimg, DBlack);
269 memfillcolor(swimg1, DBlack);
270 }
271
272 int
hwdraw(Memdrawparam * par)273 hwdraw(Memdrawparam *par)
274 {
275 Memimage *dst, *src, *mask;
276
277 if((dst=par->dst) == nil || dst->data == nil)
278 return 0;
279 if((src=par->src) == nil || src->data == nil)
280 return 0;
281 if((mask=par->mask) == nil || mask->data == nil)
282 return 0;
283
284 if(dst->data->bdata == xgdata.bdata)
285 swcursoravoid(par->r);
286 if(src->data->bdata == xgdata.bdata)
287 swcursoravoid(par->sr);
288 if(mask->data->bdata == xgdata.bdata)
289 swcursoravoid(par->mr);
290
291 if(lcd)
292 lcd->draw(par->r);
293
294 return 0;
295 }
296
297 static int
screensize(void)298 screensize(void)
299 {
300 char *p, buf[32];
301 char *f[3];
302 int width, height, depth;
303
304 p = getconf("vgasize");
305 if(p == nil || memccpy(buf, p, '\0', sizeof buf) == nil)
306 return -1;
307
308 if(getfields(buf, f, nelem(f), 0, "x") != nelem(f) ||
309 (width = atoi(f[0])) < 16 ||
310 (height = atoi(f[1])) <= 0 ||
311 (depth = atoi(f[2])) <= 0)
312 return -1;
313 xgscreen.r.max = Pt(width, height);
314 xgscreen.depth = depth;
315 return 0;
316 }
317
318 void
screeninit(void)319 screeninit(void)
320 {
321 uchar *fb;
322 char *p;
323 int set, rgbswap;
324 ulong chan;
325
326 set = screensize() == 0;
327 fb = fbinit(set, &xgscreen.r.max.x, &xgscreen.r.max.y, &xgscreen.depth);
328 if(fb == nil){
329 xgscreen.r.max = Pt(640, 480);
330 xgscreen.depth = 16;
331 fb = fbinit(set, &xgscreen.r.max.x, &xgscreen.r.max.y, &xgscreen.depth);
332 }
333 if(fb == nil){
334 print("can't initialise %dx%dx%d framebuffer \n",
335 xgscreen.r.max.x, xgscreen.r.max.y, xgscreen.depth);
336 return;
337 }
338 rgbswap = ((p = getconf("bcm2708_fb.fbswap")) != nil && *p == '1');
339 xgscreen.clipr = xgscreen.r;
340 switch(xgscreen.depth){
341 default:
342 print("unsupported screen depth %d\n", xgscreen.depth);
343 xgscreen.depth = 16;
344 /* fall through */
345 case 16:
346 chan = RGB16;
347 break;
348 case 24:
349 chan = rgbswap? RGB24 : BGR24;
350 break;
351 case 32:
352 chan = rgbswap? XRGB32 : XBGR32;
353 break;
354 }
355 memsetchan(&xgscreen, chan);
356 conf.monitor = 1;
357 xgdata.bdata = fb;
358 xgdata.ref = 1;
359 gscreen = &xgscreen;
360 gscreen->width = wordsperline(gscreen->r, gscreen->depth);
361
362 memimageinit();
363 memdefont = getmemdefont();
364 screenwin();
365 screenputs = myscreenputs;
366 }
367
368 void
flushmemscreen(Rectangle)369 flushmemscreen(Rectangle)
370 {
371 }
372
373 uchar*
attachscreen(Rectangle * r,ulong * chan,int * d,int * width,int * softscreen)374 attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
375 {
376 *r = gscreen->r;
377 *d = gscreen->depth;
378 *chan = gscreen->chan;
379 *width = gscreen->width;
380 *softscreen = 0;
381
382 return gscreen->data->bdata;
383 }
384
385 void
getcolor(ulong p,ulong * pr,ulong * pg,ulong * pb)386 getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
387 {
388 USED(p, pr, pg, pb);
389 }
390
391 int
setcolor(ulong p,ulong r,ulong g,ulong b)392 setcolor(ulong p, ulong r, ulong g, ulong b)
393 {
394 USED(p, r, g, b);
395 return 0;
396 }
397
398 void
blankscreen(int blank)399 blankscreen(int blank)
400 {
401 fbblank(blank);
402 if(lcd)
403 lcd->blank(blank);
404 }
405
406 static void
myscreenputs(char * s,int n)407 myscreenputs(char *s, int n)
408 {
409 int i;
410 Rune r;
411 char buf[4];
412
413 if(!islo()) {
414 /* don't deadlock trying to print in interrupt */
415 if(!canlock(&screenlock))
416 return;
417 }
418 else
419 lock(&screenlock);
420
421 while(n > 0){
422 i = chartorune(&r, s);
423 if(i == 0){
424 s++;
425 --n;
426 continue;
427 }
428 memmove(buf, s, i);
429 buf[i] = 0;
430 n -= i;
431 s += i;
432 screenputc(buf);
433 }
434 unlock(&screenlock);
435 }
436
437 static void
screenwin(void)438 screenwin(void)
439 {
440 char *greet;
441 Memimage *orange;
442 Point p, q;
443 Rectangle r;
444
445 back = memwhite;
446 conscol = memblack;
447
448 orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
449 orange->flags |= Frepl;
450 orange->clipr = gscreen->r;
451 orange->data->bdata[0] = 0x40; /* magic: colour? */
452 orange->data->bdata[1] = 0xfd; /* magic: colour? */
453
454 w = memdefont->info[' '].width;
455 h = memdefont->height;
456
457 r = insetrect(gscreen->r, 4);
458
459 memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
460 window = insetrect(r, 4);
461 memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
462
463 memimagedraw(gscreen, Rect(window.min.x, window.min.y,
464 window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
465 freememimage(orange);
466 window = insetrect(window, 5);
467
468 greet = " Plan 9 Console ";
469 p = addpt(window.min, Pt(10, 0));
470 q = memsubfontwidth(memdefont, greet);
471 memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
472 flushmemscreen(r);
473 window.min.y += h + 6;
474 curpos = window.min;
475 window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
476 }
477
478 static void
scroll(void)479 scroll(void)
480 {
481 int o;
482 Point p;
483 Rectangle r;
484
485 o = Scroll*h;
486 r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
487 p = Pt(window.min.x, window.min.y+o);
488 memimagedraw(gscreen, r, gscreen, p, nil, p, S);
489 flushmemscreen(r);
490 if(lcd)
491 lcd->draw(r);
492 r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
493 memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
494 flushmemscreen(r);
495 if(lcd)
496 lcd->draw(r);
497
498 curpos.y -= o;
499 }
500
501 static void
screenputc(char * buf)502 screenputc(char *buf)
503 {
504 int w;
505 uint pos;
506 Point p;
507 Rectangle r;
508 static int *xp;
509 static int xbuf[256];
510
511 if (xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
512 xp = xbuf;
513
514 switch (buf[0]) {
515 case '\n':
516 if (curpos.y + h >= window.max.y)
517 scroll();
518 curpos.y += h;
519 screenputc("\r");
520 break;
521 case '\r':
522 xp = xbuf;
523 curpos.x = window.min.x;
524 break;
525 case '\t':
526 p = memsubfontwidth(memdefont, " ");
527 w = p.x;
528 if (curpos.x >= window.max.x - Tabstop * w)
529 screenputc("\n");
530
531 pos = (curpos.x - window.min.x) / w;
532 pos = Tabstop - pos % Tabstop;
533 *xp++ = curpos.x;
534 r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
535 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
536 flushmemscreen(r);
537 curpos.x += pos * w;
538 break;
539 case '\b':
540 if (xp <= xbuf)
541 break;
542 xp--;
543 r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
544 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
545 flushmemscreen(r);
546 curpos.x = *xp;
547 break;
548 case '\0':
549 break;
550 default:
551 p = memsubfontwidth(memdefont, buf);
552 w = p.x;
553
554 if (curpos.x >= window.max.x - w)
555 screenputc("\n");
556
557 *xp++ = curpos.x;
558 r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
559 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
560 memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
561 flushmemscreen(r);
562 curpos.x += w;
563 break;
564 }
565 }
566