]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bitsy/screen.c
fix kernel: pio()/mfreeseg() race
[plan9front.git] / sys / src / 9 / bitsy / screen.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "ureg.h"
8 #include "../port/error.h"
9
10 #define Image   IMAGE
11 #include <draw.h>
12 #include <memdraw.h>
13 #include <cursor.h>
14 #include "screen.h"
15 #include "gamma.h"
16
17 #define MINX    8
18
19 int landscape = 0;      /* orientation of the screen, default is 0: portait */
20
21 enum {
22         Wid             = 240,
23         Ht              = 320,
24         Pal0    = 0x2000,       /* 16-bit pixel data in active mode (12 in passive) */
25
26         hsw             = 0x00,
27         elw             = 0x0e,
28         blw             = 0x0d,
29
30         vsw             = 0x02,
31         efw             = 0x01,
32         bfw             = 0x0a,
33
34         pcd             = 0x10,
35 };
36
37 struct sa1110fb {
38         /* Frame buffer for 16-bit active color */
39         short   palette[16];            /* entry 0 set to Pal0, the rest to 0 */
40         ushort  pixel[Wid*Ht];          /* Pixel data */
41 } *framebuf;
42
43 enum {
44 /* LCD Control Register 0, lcd->lccr0 */
45         LEN     =  0,   /*  1 bit */
46         CMS     =  1,   /*  1 bit */
47         SDS     =  2,   /*  1 bit */
48         LDM     =  3,   /*  1 bit */
49         BAM     =  4,   /*  1 bit */
50         ERM     =  5,   /*  1 bit */
51         PAS     =  7,   /*  1 bit */
52         BLE     =  8,   /*  1 bit */
53         DPD     =  9,   /*  1 bit */
54         PDD     = 12,   /*  8 bits */
55 };
56
57 enum {
58 /* LCD Control Register 1, lcd->lccr1 */
59         PPL     =  0,   /* 10 bits */
60         HSW     = 10,   /*  6 bits */
61         ELW     = 16,   /*  8 bits */
62         BLW     = 24,   /*  8 bits */
63 };
64
65 enum {
66 /* LCD Control Register 2, lcd->lccr2 */
67         LPP     =  0,   /* 10 bits */
68         VSW     = 10,   /*  6 bits */
69         EFW     = 16,   /*  8 bits */
70         BFW     = 24,   /*  8 bits */
71 };
72
73 enum {
74 /* LCD Control Register 3, lcd->lccr3 */
75         PCD     =  0,   /*  8 bits */
76         ACB     =  8,   /*  8 bits */
77         API     = 16,   /*  4 bits */
78         VSP     = 20,   /*  1 bit */
79         HSP     = 21,   /*  1 bit */
80         PCP     = 22,   /*  1 bit */
81         OEP     = 23,   /*  1 bit */
82 };
83
84 enum {
85 /* LCD Status Register, lcd->lcsr */
86         LDD     =  0,   /*  1 bit */
87         BAU     =  1,   /*  1 bit */
88         BER     =  2,   /*  1 bit */
89         ABC     =  3,   /*  1 bit */
90         IOL     =  4,   /*  1 bit */
91         IUL     =  5,   /*  1 bit */
92         OIU     =  6,   /*  1 bit */
93         IUU     =  7,   /*  1 bit */
94         OOL     =  8,   /*  1 bit */
95         OUL     =  9,   /*  1 bit */
96         OOU     = 10,   /*  1 bit */
97         OUU     = 11,   /*  1 bit */
98 };
99
100 struct sa1110regs {
101         ulong   lccr0;
102         ulong   lcsr;
103         ulong   dummies[2];
104         short*  dbar1;
105         ulong   dcar1;
106         ulong   dbar2;
107         ulong   dcar2;
108         ulong   lccr1;
109         ulong   lccr2;
110         ulong   lccr3;
111 } *lcd;
112
113 Point   ZP = {0, 0};
114
115 static Memdata xgdata;
116
117 static Memimage xgscreen =
118 {
119         { 0, 0, Wid, Ht },              /* r */
120         { 0, 0, Wid, Ht },              /* clipr */
121         16,                             /* depth */
122         3,                              /* nchan */
123         RGB16,                  /* chan */
124         nil,                            /* cmap */
125         &xgdata,                        /* data */
126         0,                              /* zero */
127         Wid/2,                  /* width */
128         0,                              /* layer */
129         0,                              /* flags */
130 };
131
132 struct{
133         Point   pos;
134         int     bwid;
135 }out;
136
137 Memimage *gscreen;
138 Memimage *conscol;
139 Memimage *back;
140
141 Memsubfont      *memdefont;
142
143 Lock            screenlock;
144
145 Point           ZP = {0, 0};
146 ushort          *vscreen;       /* virtual screen */
147 Rectangle       window;
148 Point           curpos;
149 int                     h, w;
150 int                     drawdebug;
151
152 static  ulong   rep(ulong, int);
153 static  void    screenwin(void);
154 static  void    screenputc(char *buf);
155 static  void    bitsyscreenputs(char *s, int n);
156 static  void    scroll(void);
157
158 static void
159 lcdinit(void)
160 {
161         /* the following line works because main memory is direct mapped */
162         gpioregs->direction |= 
163                 GPIO_LDD8_o|GPIO_LDD9_o|GPIO_LDD10_o|GPIO_LDD11_o
164                 |GPIO_LDD12_o|GPIO_LDD13_o|GPIO_LDD14_o|GPIO_LDD15_o;
165         gpioregs->altfunc |= 
166                 GPIO_LDD8_o|GPIO_LDD9_o|GPIO_LDD10_o|GPIO_LDD11_o
167                 |GPIO_LDD12_o|GPIO_LDD13_o|GPIO_LDD14_o|GPIO_LDD15_o;
168         framebuf->palette[0] = Pal0;
169         lcd->dbar1 = framebuf->palette;
170         lcd->lccr3 = pcd<<PCD | 0<<ACB | 0<<API | 1<<VSP | 1<<HSP | 0<<PCP | 0<<OEP;
171         lcd->lccr2 = (Wid-1)<<LPP | vsw<<VSW | efw<<EFW | bfw<<BFW;
172         lcd->lccr1 = (Ht-16)<<PPL | hsw<<HSW | elw<<ELW | blw<<BLW;
173         lcd->lccr0 = 1<<LEN | 0<<CMS | 0<<SDS | 1<<LDM | 1<<BAM | 1<<ERM | 1<<PAS | 0<<BLE | 0<<DPD | 0<<PDD;
174 }
175
176 void
177 flipscreen(int ls) {
178         if (ls == landscape)
179                 return;
180         if (ls) {
181                 gscreen->r = Rect(0, 0, Ht, Wid);
182                 gscreen->clipr = gscreen->r;
183                 gscreen->width = Ht/2;
184                 xgdata.bdata = (uchar *)framebuf->pixel;
185         } else {
186                 gscreen->r = Rect(0, 0, Wid, Ht);
187                 gscreen->clipr = gscreen->r;
188                 gscreen->width = Wid/2;
189                 xgdata.bdata = (uchar *)vscreen;
190         }
191         landscape = ls;
192 }
193
194 void
195 lcdtweak(Cmdbuf *cmd)
196 {
197         if(cmd->nf < 4)
198                 return;
199         if(*cmd->f[0] == 'h')
200                 lcd->lccr1 = ((Ht-16)<<PPL)
201                         | (atoi(cmd->f[1])<<HSW)
202                         | (atoi(cmd->f[2])<<ELW)
203                         | (atoi(cmd->f[3])<<BLW);
204         if(*cmd->f[0] == 'v')
205                 lcd->lccr2 = ((Wid-1)<<LPP)
206                         | (atoi(cmd->f[1])<<VSW)
207                         | (atoi(cmd->f[2])<<EFW)
208                         | (atoi(cmd->f[3])<<BFW);
209 }
210
211 void
212 screenpower(int on)
213 {
214         blankscreen(on == 0);
215 }
216
217 void
218 screeninit(void)
219 {
220         int i;
221
222         /* map the lcd regs into the kernel's virtual space */
223         lcd = (struct sa1110regs*)mapspecial(LCDREGS, sizeof(struct sa1110regs));;
224
225         framebuf = xspanalloc(sizeof *framebuf, 0x100, 0);
226
227         vscreen = xalloc(sizeof(ushort)*Wid*Ht);
228
229         lcdpower(1);
230         lcdinit();
231
232         gscreen = &xgscreen;
233
234         xgdata.ref = 1;
235         i = 0;
236         if (landscape) {
237                 gscreen->r = Rect(0, 0, Ht, Wid);
238                 gscreen->clipr = gscreen->r;
239                 gscreen->width = Ht/2;
240                 xgdata.bdata = (uchar *)framebuf->pixel;
241                 while (i < Wid*Ht*1/3)  framebuf->pixel[i++] = 0xf800;  /* red */
242                 while (i < Wid*Ht*2/3)  framebuf->pixel[i++] = 0xffff;          /* white */
243                 while (i < Wid*Ht*3/3)  framebuf->pixel[i++] = 0x001f;  /* blue */
244         } else {
245                 gscreen->r = Rect(0, 0, Wid, Ht);
246                 gscreen->clipr = gscreen->r;
247                 gscreen->width = Wid/2;
248                 xgdata.bdata = (uchar *)vscreen;
249                 while (i < Wid*Ht*1/3)  vscreen[i++] = 0xf800;  /* red */
250                 while (i < Wid*Ht*2/3)  vscreen[i++] = 0xffff;  /* white */
251                 while (i < Wid*Ht*3/3)  vscreen[i++] = 0x001f;  /* blue */
252                 flushmemscreen(gscreen->r);
253         }
254         memimageinit();
255         memdefont = getmemdefont();
256
257         out.pos.x = MINX;
258         out.pos.y = 0;
259         out.bwid = memdefont->info[' '].width;
260
261         blanktime = 3;  /* minutes */
262
263         screenwin();
264 //      screenputs = bitsyscreenputs;
265         screenputs = nil;
266 }
267
268 void
269 flushmemscreen(Rectangle r)
270 {
271         int x, y;
272         ulong start, end;
273
274         if (landscape == 0) {
275                 if (r.min.x <   0) r.min.x = 0;
276                 if (r.max.x > Wid) r.max.x = Wid;
277                 if (r.min.y <   0) r.min.y = 0;
278                 if (r.max.y >  Ht) r.max.y = Ht;
279                 for (x = r.min.x; x < r.max.x; x++)
280                         for (y = r.min.y; y < r.max.y; y++)
281                                 framebuf->pixel[(x+1)*Ht-1-y] = gamma[vscreen[y*Wid+x]];
282                 start = (ulong)&framebuf->pixel[(r.min.x+1)*Ht-1-(r.max.y-1)];
283                 end = (ulong)&framebuf->pixel[(r.max.x-1+1)*Ht-1-(r.min.y)];
284         } else {
285                 start = (ulong)&framebuf->pixel[r.min.y*Ht + r.min.x];
286                 end = (ulong)&framebuf->pixel[(r.max.y-1)*Ht + r.max.x - 1];
287         }
288         cachewbregion(start, end-start);
289 }
290
291 /*
292  * export screen to devdraw
293  */
294 uchar*
295 attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
296 {
297         *r = gscreen->r;
298         *d = gscreen->depth;
299         *chan = gscreen->chan;
300         *width = gscreen->width;
301         *softscreen = (landscape == 0);
302
303         return (uchar*)gscreen->data->bdata;
304 }
305
306 void
307 getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
308 {
309         USED(p, pr, pg, pb);
310 }
311
312 int
313 setcolor(ulong p, ulong r, ulong g, ulong b)
314 {
315         USED(p,r,g,b);
316         return 0;
317 }
318
319 void
320 blankscreen(int blank)
321 {
322         int cnt;
323
324         if (blank) {
325                 lcd->lccr0 &= ~(1<<LEN);        /* disable the LCD */
326                 cnt = 0;
327                 while((lcd->lcsr & (1<<LDD)) == 0) {
328                         delay(10);
329                         if (++cnt == 100) {
330                                 iprint("LCD doesn't stop\n");
331                                 break;
332                         }
333                 }
334                 lcdpower(0);
335         } else {
336                 lcdpower(1);
337                 lcdinit();
338         }
339 }
340
341 static void
342 bitsyscreenputs(char *s, int n)
343 {
344         int i;
345         Rune r;
346         char buf[4];
347
348         if(!islo()) {
349                 /* don't deadlock trying to print in interrupt */
350                 if(!canlock(&screenlock))
351                         return; 
352         }
353         else
354                 lock(&screenlock);
355
356         while(n > 0){
357                 i = chartorune(&r, s);
358                 if(i == 0){
359                         s++;
360                         --n;
361                         continue;
362                 }
363                 memmove(buf, s, i);
364                 buf[i] = 0;
365                 n -= i;
366                 s += i;
367                 screenputc(buf);
368         }
369         unlock(&screenlock);
370 }
371
372 static void
373 screenwin(void)
374 {
375         Point p, q;
376         char *greet;
377         Memimage *orange;
378         Rectangle r;
379
380         memsetchan(gscreen, RGB16);
381
382         back = memwhite;
383         conscol = memblack;
384
385         orange = allocmemimage(Rect(0,0,1,1), RGB16);
386         orange->flags |= Frepl;
387         orange->clipr = gscreen->r;
388         orange->data->bdata[0] = 0x40;
389         orange->data->bdata[1] = 0xfd;
390
391         w = memdefont->info[' '].width;
392         h = memdefont->height;
393
394         r = insetrect(gscreen->r, 4);
395
396         memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
397         window = insetrect(r, 4);
398         memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
399
400         memimagedraw(gscreen, Rect(window.min.x, window.min.y,
401                         window.max.x, window.min.y+h+5+6), orange, ZP, nil, ZP, S);
402         freememimage(orange);
403         window = insetrect(window, 5);
404
405         greet = " Plan 9 Console ";
406         p = addpt(window.min, Pt(10, 0));
407         q = memsubfontwidth(memdefont, greet);
408         memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
409         flushmemscreen(r);
410         window.min.y += h+6;
411         curpos = window.min;
412         window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
413 }
414
415 static void
416 screenputc(char *buf)
417 {
418         Point p;
419         int w, pos;
420         Rectangle r;
421         static int *xp;
422         static int xbuf[256];
423
424         if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
425                 xp = xbuf;
426
427         switch(buf[0]) {
428         case '\n':
429                 if(curpos.y+h >= window.max.y)
430                         scroll();
431                 curpos.y += h;
432                 screenputc("\r");
433                 break;
434         case '\r':
435                 xp = xbuf;
436                 curpos.x = window.min.x;
437                 break;
438         case '\t':
439                 p = memsubfontwidth(memdefont, " ");
440                 w = p.x;
441                 if(curpos.x >= window.max.x-4*w)
442                         screenputc("\n");
443
444                 pos = (curpos.x-window.min.x)/w;
445                 pos = 4-(pos%4);
446                 *xp++ = curpos.x;
447                 r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
448                 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
449                 flushmemscreen(r);
450                 curpos.x += pos*w;
451                 break;
452         case '\b':
453                 if(xp <= xbuf)
454                         break;
455                 xp--;
456                 r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
457                 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
458                 flushmemscreen(r);
459                 curpos.x = *xp;
460                 break;
461         case '\0':
462                 break;
463         default:
464                 p = memsubfontwidth(memdefont, buf);
465                 w = p.x;
466
467                 if(curpos.x >= window.max.x-w)
468                         screenputc("\n");
469
470                 *xp++ = curpos.x;
471                 r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y + h);
472                 memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
473                 memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
474                 flushmemscreen(r);
475                 curpos.x += w;
476         }
477 }
478
479 static void
480 scroll(void)
481 {
482         int o;
483         Point p;
484         Rectangle r;
485
486         o = 8*h;
487         r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
488         p = Pt(window.min.x, window.min.y+o);
489         memimagedraw(gscreen, r, gscreen, p, nil, p, S);
490         flushmemscreen(r);
491         r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
492         memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
493         flushmemscreen(r);
494
495         curpos.y -= o;
496 }