1 /*
2 * radeon frame buffer
3 * currently use all PMON defaults
4 */
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11
12 #define Image IMAGE
13 #include <draw.h>
14 #include <memdraw.h>
15 #include <cursor.h>
16 #include "screen.h"
17
18 enum {
19 Tabstop = 4,
20 Scroll = 8,
21 Wid = 640,
22 Ht = 480,
23 Depth = 16,
24 };
25
26 Cursor arrow = {
27 { -1, -1 },
28 { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
29 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
30 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
31 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
32 },
33 { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
34 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
35 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
36 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
37 },
38 };
39
40 Memimage *gscreen;
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 int screenwid;
70 int screenht;
71 int screendepth;
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 static int
screensize(void)273 screensize(void)
274 {
275 char *p;
276 char *f[3];
277 int width, height, depth;
278
279 p = getconf("vgasize");
280 if(p == nil || getfields(p, f, nelem(f), 0, "x") != nelem(f) ||
281 (width = atoi(f[0])) < 16 || (height = atoi(f[1])) <= 0 ||
282 (depth = atoi(f[2])) <= 0) {
283 width = screenwid? screenwid: Wid;
284 height = screenht? screenht: Ht;
285 depth = screendepth? screendepth: Depth;
286 }
287
288 xgscreen.r.max = Pt(width, height);
289 xgscreen.depth = depth;
290 return 0;
291 }
292
293 void
flushmemscreen(Rectangle)294 flushmemscreen(Rectangle)
295 {
296 }
297
298 static void
screenwin(void)299 screenwin(void)
300 {
301 char *greet;
302 Memimage *orange;
303 Point p, q;
304 Rectangle r;
305
306 back = memwhite;
307 conscol = memblack;
308
309 orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
310 orange->flags |= Frepl;
311 orange->clipr = gscreen->r;
312 orange->data->bdata[0] = 0x40; /* magic: colour? */
313 orange->data->bdata[1] = 0xfd; /* magic: colour? */
314
315 w = memdefont->info[' '].width;
316 h = memdefont->height;
317
318 r = insetrect(gscreen->r, 0);
319
320 memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
321 window = insetrect(r, 0);
322 memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
323
324 memimagedraw(gscreen, Rect(window.min.x, window.min.y,
325 window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
326 freememimage(orange);
327 window = insetrect(window, 5);
328
329 greet = " Plan 9 Console ";
330 p = addpt(window.min, Pt(10, 0));
331 q = memsubfontwidth(memdefont, greet);
332 memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
333 flushmemscreen(r);
334 window.min.y += h + 6;
335 curpos = window.min;
336 window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
337 }
338
339 static void
scroll(void)340 scroll(void)
341 {
342 int o;
343 Point p;
344 Rectangle r;
345
346 o = Scroll*h;
347 r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
348 p = Pt(window.min.x, window.min.y+o);
349 memimagedraw(gscreen, r, gscreen, p, nil, p, S);
350 flushmemscreen(r);
351 r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
352 memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
353 flushmemscreen(r);
354
355 curpos.y -= o;
356 }
357
358 static void
screenputc(char * buf)359 screenputc(char *buf)
360 {
361 int w;
362 uint pos;
363 Point p;
364 Rectangle r;
365 static int *xp;
366 static int xbuf[256];
367
368 if (xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
369 xp = xbuf;
370
371 switch (buf[0]) {
372 case '\n':
373 if (curpos.y + h >= window.max.y)
374 scroll();
375 curpos.y += h;
376 screenputc("\r");
377 break;
378 case '\r':
379 xp = xbuf;
380 curpos.x = window.min.x;
381 break;
382 case '\t':
383 p = memsubfontwidth(memdefont, " ");
384 w = p.x;
385 if (curpos.x >= window.max.x - Tabstop * w)
386 screenputc("\n");
387
388 pos = (curpos.x - window.min.x) / w;
389 pos = Tabstop - pos % Tabstop;
390 *xp++ = curpos.x;
391 r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
392 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
393 flushmemscreen(r);
394 curpos.x += pos * w;
395 break;
396 case '\b':
397 if (xp <= xbuf)
398 break;
399 xp--;
400 r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
401 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
402 flushmemscreen(r);
403 curpos.x = *xp;
404 break;
405 case '\0':
406 break;
407 default:
408 p = memsubfontwidth(memdefont, buf);
409 w = p.x;
410
411 if (curpos.x >= window.max.x - w)
412 screenputc("\n");
413
414 *xp++ = curpos.x;
415 r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
416 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
417 memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
418 flushmemscreen(r);
419 curpos.x += w;
420 break;
421 }
422 }
423
424 static void
myscreenputs(char * s,int n)425 myscreenputs(char *s, int n)
426 {
427 int i;
428 Rune r;
429 char buf[4];
430
431 if(!islo()) {
432 /* don't deadlock trying to print in interrupt */
433 if(!canlock(&screenlock))
434 return;
435 }
436 else
437 lock(&screenlock);
438
439 while(n > 0){
440 i = chartorune(&r, s);
441 if(i == 0){
442 s++;
443 --n;
444 continue;
445 }
446 memmove(buf, s, i);
447 buf[i] = 0;
448 n -= i;
449 s += i;
450 screenputc(buf);
451 }
452 unlock(&screenlock);
453 }
454
455 void
screeninit(void)456 screeninit(void)
457 {
458 ulong chan;
459 uchar *fb;
460
461 screensize();
462 fb = (uchar*)fbinit();
463 if(fb == nil){
464 print("can't initialise %dx%dx%d framebuffer \n",
465 xgscreen.r.max.x, xgscreen.r.max.y, xgscreen.depth);
466 return;
467 }
468
469 xgscreen.clipr = xgscreen.r;
470 switch(xgscreen.depth){
471 default:
472 print("unsupported screen depth %d\n", xgscreen.depth);
473 xgscreen.depth = 16;
474 /* fall through */
475 case 16:
476 chan = RGB16;
477 break;
478 case 24:
479 chan = BGR24;
480 break;
481 case 32:
482 chan = ARGB32;
483 break;
484 }
485 memsetchan(&xgscreen, chan);
486 conf.monitor = 1;
487 xgdata.bdata = fb;
488 xgdata.ref = 1;
489 gscreen = &xgscreen;
490 gscreen->width = wordsperline(gscreen->r, gscreen->depth);
491
492 memimageinit();
493 memdefont = getmemdefont();
494 screenwin();
495 screenputs = myscreenputs;
496 }
497
498 uchar*
attachscreen(Rectangle * r,ulong * chan,int * d,int * width,int * softscreen)499 attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
500 {
501 *r = gscreen->r;
502 *d = gscreen->depth;
503 *chan = gscreen->chan;
504 *width = gscreen->width;
505 *softscreen = 0;
506
507 return gscreen->data->bdata;
508 }
509
510 void
getcolor(ulong p,ulong * pr,ulong * pg,ulong * pb)511 getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
512 {
513 USED(p, pr, pg, pb);
514 }
515
516 int
setcolor(ulong p,ulong r,ulong g,ulong b)517 setcolor(ulong p, ulong r, ulong g, ulong b)
518 {
519 USED(p, r, g, b);
520 return 0;
521 }
522
523 void
blankscreen(int blank)524 blankscreen(int blank)
525 {
526 USED(blank);
527 }
528
529 int
hwdraw(Memdrawparam * par)530 hwdraw(Memdrawparam *par)
531 {
532 Memimage *dst, *src, *mask;
533
534 if((dst=par->dst) == nil || dst->data == nil)
535 return 0;
536 if((src=par->src) == nil || src->data == nil)
537 return 0;
538 if((mask=par->mask) == nil || mask->data == nil)
539 return 0;
540
541 if(dst->data->bdata == xgdata.bdata)
542 swcursoravoid(par->r);
543 if(src->data->bdata == xgdata.bdata)
544 swcursoravoid(par->sr);
545 if(mask->data->bdata == xgdata.bdata)
546 swcursoravoid(par->mr);
547
548 return 0;
549 }
550
551 /* radeon frame buffer control */
552 typedef struct Ctlr {
553 Pcidev* pcidev;
554 int port;
555 void* mmio;
556 ulong paddr;
557 void* vaddr;
558 } Ctlr;
559
560 static Ctlr *ctlr;
561
562 static Pcidev*
videopci(void)563 videopci(void)
564 {
565 static Pcidev *p = nil;
566
567 while((p = pcimatch(p, 0, 0)) != nil){
568 if(p->ccrb != Pcibcdisp || p->ccru != 0)
569 continue;
570 return p;
571 }
572 return nil;
573 }
574
575 static void
fbenable(void)576 fbenable(void)
577 {
578 Pcidev *p;
579
580 if(ctlr)
581 return;
582 p = videopci();
583 if(p == nil)
584 return;
585 ctlr = malloc(sizeof(Ctlr));
586 ctlr->pcidev = p;
587 ctlr->paddr = PCIMEMADDR(p->mem[0].bar & ~0x0f);
588 ctlr->vaddr = KSEG1ADDR(ctlr->paddr);
589 ctlr->port = p->mem[1].bar & ~0x01;
590 ctlr->mmio = KSEG1ADDR(PCIMEMADDR(p->mem[2].bar & ~0x0f));
591 }
592
593 void*
fbinit(void)594 fbinit(void)
595 {
596 if(!ctlr)
597 fbenable();
598
599 if(!ctlr)
600 return nil;
601 else
602 return ctlr->vaddr;
603 }
604