xref: /plan9/sys/src/9/omap/screen.c (revision 5efba40621eb0e8502497b8c98fd368f3bc4d354)
193631029SDavid du Colombier /*
293631029SDavid du Colombier  * ti omap35 display subsystem (dss)
393631029SDavid du Colombier  *
493631029SDavid du Colombier  * can handle 2ⁿ bits per pixel for 0 < n ≤ 4, and 12 and 24 bits.
593631029SDavid du Colombier  * can handle	1024×768 at 60 Hz with pixel clock of 63.5 MHz
693631029SDavid du Colombier  *		1280×800 at 59.91 Hz with pixel clock of 71 MHz
793631029SDavid du Colombier  *		1400×1050 lcd at 50 MHz with pixel clock of 75 MHz
893631029SDavid du Colombier  * has 256 24-bit entries in RGB palette
993631029SDavid du Colombier  */
1093631029SDavid du Colombier #include "u.h"
1193631029SDavid du Colombier #include "../port/lib.h"
1293631029SDavid du Colombier #include "mem.h"
1393631029SDavid du Colombier #include "dat.h"
1493631029SDavid du Colombier #include "fns.h"
1593631029SDavid du Colombier #include "io.h"
1693631029SDavid du Colombier #include "ureg.h"
1793631029SDavid du Colombier #include "../port/error.h"
1893631029SDavid du Colombier 
1993631029SDavid du Colombier #define	Image	IMAGE
2093631029SDavid du Colombier #include <draw.h>
2193631029SDavid du Colombier #include <memdraw.h>
2293631029SDavid du Colombier #include <cursor.h>
2393631029SDavid du Colombier #include "screen.h"
2493631029SDavid du Colombier // #include "gamma.h"
2593631029SDavid du Colombier 
2693631029SDavid du Colombier enum {
2793631029SDavid du Colombier 	Tabstop	= 4,		/* should be 8 */
28634d7e5aSDavid du Colombier 	Scroll	= 8,		/* lines to scroll at one time */
2993631029SDavid du Colombier 	/*
3093631029SDavid du Colombier 	 * screen settings for Wid and Ht, should a bit more dynamic?
3193631029SDavid du Colombier 	 * http://www.epanorama.net/faq/vga2rgb/calc.html
3293631029SDavid du Colombier 	 * used to calculate settings.
3393631029SDavid du Colombier 	 */
3493631029SDavid du Colombier 
3593631029SDavid du Colombier //	Hbp     = (248-1) << 20,
3693631029SDavid du Colombier //	Hfp     = (48-1) << 8,
3793631029SDavid du Colombier //	Hsw     = 112-1,
3893631029SDavid du Colombier 
3993631029SDavid du Colombier //	Vbp     = 38 << 20,
4093631029SDavid du Colombier //	Vfp     = 1 << 8,
4193631029SDavid du Colombier //	Vsw     = 3,
4293631029SDavid du Colombier 
4393631029SDavid du Colombier 	Tft	= 0x60,
4493631029SDavid du Colombier 
4593631029SDavid du Colombier 	Loadmode = 2 << 1,
4693631029SDavid du Colombier 	Fifosize = 0x400,
4793631029SDavid du Colombier 
4893631029SDavid du Colombier 	/* dispc sysconfig */
4993631029SDavid du Colombier 	Midlemode	= 2 << 12,
5093631029SDavid du Colombier 	Sidlemode	= 2 << 3,
5193631029SDavid du Colombier 	EnableWakeup	= 1 << 2,
5293631029SDavid du Colombier 	Autoidle	= 1 << 0,
5393631029SDavid du Colombier 
5493631029SDavid du Colombier 	/* dispc pool_freq */
5593631029SDavid du Colombier 	Ipc		= 1 << 14,
5693631029SDavid du Colombier 	Ihs		= 1 << 13,
5793631029SDavid du Colombier 	Ivs		= 1 << 12,
5893631029SDavid du Colombier 	Acb		= 0x28,
5993631029SDavid du Colombier 
6093631029SDavid du Colombier 	/* gfx attribs */
6193631029SDavid du Colombier 	Burstsize	= 2 << 6,
6293631029SDavid du Colombier 	Format		= 6 << 1,
6393631029SDavid du Colombier 	Gfxenable	= 1 << 0,
6493631029SDavid du Colombier 
6593631029SDavid du Colombier 	/* dispc control */
6693631029SDavid du Colombier 	Gpout1		= 1 << 16,
6793631029SDavid du Colombier 	Gpout0		= 1 << 15,
6893631029SDavid du Colombier 	Tftdata		= 3 << 8,
6993631029SDavid du Colombier 	Digital		= 1 << 6,
7093631029SDavid du Colombier 	Lcd		= 1 << 5,
7193631029SDavid du Colombier 	Stntft		= 1 << 3,
7293631029SDavid du Colombier 	Digitalen	= 1 << 1,
7393631029SDavid du Colombier //	Lcden		= 1 << 0,	/* unused */
7493631029SDavid du Colombier };
7593631029SDavid du Colombier 
7693631029SDavid du Colombier typedef struct Dispcregs Dispc;
7793631029SDavid du Colombier typedef struct Dssregs Dss;
7893631029SDavid du Colombier typedef struct Ioregs Ioregs;
7993631029SDavid du Colombier 
8093631029SDavid du Colombier struct Ioregs {				/* common registers, 68 (0x44) bytes */
8193631029SDavid du Colombier 	ulong 	rev;
8293631029SDavid du Colombier 	uchar	_pad0[0x10-0x4];
8393631029SDavid du Colombier 	ulong	sysconf;
8493631029SDavid du Colombier 	ulong	sysstat;
8593631029SDavid du Colombier 	ulong	irqstat1;
8693631029SDavid du Colombier 
8793631029SDavid du Colombier 	/* Dispc only regs */
8893631029SDavid du Colombier 	ulong	irqen1;
8993631029SDavid du Colombier 	ulong	wkupen;
9093631029SDavid du Colombier 	ulong	_pad1;
9193631029SDavid du Colombier 	ulong	irqsts2;
9293631029SDavid du Colombier 	ulong	irqen2;
9393631029SDavid du Colombier 	ulong	_pad2[4];
9493631029SDavid du Colombier 
9593631029SDavid du Colombier 	ulong	ctrl;
9693631029SDavid du Colombier };
9793631029SDavid du Colombier 
9893631029SDavid du Colombier struct Dssregs {			/* display subsys at 0x48050000 */
9993631029SDavid du Colombier 	Ioregs;
10093631029SDavid du Colombier 	ulong	sdicrtl;
10193631029SDavid du Colombier 	ulong	pllcrtl;
10293631029SDavid du Colombier 	uchar	_pad3[0x5c-0x4c];
10393631029SDavid du Colombier 	ulong	sdistat;
10493631029SDavid du Colombier };
10593631029SDavid du Colombier 
10693631029SDavid du Colombier struct Dispcregs {			/* display ctlr at 0x48050400 */
10793631029SDavid du Colombier 	Ioregs;
10893631029SDavid du Colombier 	ulong	config;
10993631029SDavid du Colombier 	ulong	_pad3;
11093631029SDavid du Colombier 	ulong 	defaultcolor[2];
11193631029SDavid du Colombier 	ulong	transcolor[2];
11293631029SDavid du Colombier 	ulong	linestat;
11393631029SDavid du Colombier 	ulong	linenum;
11493631029SDavid du Colombier 	ulong	timing_h;
11593631029SDavid du Colombier 	ulong	timing_v;
11693631029SDavid du Colombier 	ulong	pol_req;
11793631029SDavid du Colombier 	ulong	divisor;
11893631029SDavid du Colombier 	ulong	alpha;
11993631029SDavid du Colombier 	ulong	digsize;
12093631029SDavid du Colombier 	ulong	lcdsize;
12193631029SDavid du Colombier 
12293631029SDavid du Colombier 	ulong	base[2];	/* should allocate both to avoid dithering */
12393631029SDavid du Colombier 	ulong	pos;
12493631029SDavid du Colombier 	ulong	size;
12593631029SDavid du Colombier 	ulong	_pad4[4];
12693631029SDavid du Colombier 	ulong	attrib;
12793631029SDavid du Colombier 	ulong	fifothr;
12893631029SDavid du Colombier 	ulong	fifosize;
12993631029SDavid du Colombier 	ulong	rowinc;
13093631029SDavid du Colombier 	ulong	pixelinc;
13193631029SDavid du Colombier 	ulong	winskip;
13293631029SDavid du Colombier 	ulong	palette;		/* gfx_table_ba */
13393631029SDavid du Colombier 	uchar	_pad5[0x5d4 - 0x4bc];
13493631029SDavid du Colombier 
13593631029SDavid du Colombier 	ulong	datacycle[3];
13693631029SDavid du Colombier 	uchar	_pad5[0x620 - 0x5e0];
13793631029SDavid du Colombier 
13893631029SDavid du Colombier 	ulong	cprcoefr;
13993631029SDavid du Colombier 	ulong	cprcoefg;
14093631029SDavid du Colombier 	ulong	cprcoefb;
14193631029SDavid du Colombier 	ulong	preload;
14293631029SDavid du Colombier };
14393631029SDavid du Colombier 
14493631029SDavid du Colombier int	drawdebug;
14593631029SDavid du Colombier Point	ZP = {0, 0};
14693631029SDavid du Colombier Cursor	arrow = {
14793631029SDavid du Colombier 	{ -1, -1 },
14893631029SDavid du Colombier 	{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
14993631029SDavid du Colombier 	  0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
15093631029SDavid du Colombier 	  0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
15193631029SDavid du Colombier 	  0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
15293631029SDavid du Colombier 	},
15393631029SDavid du Colombier 	{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
15493631029SDavid du Colombier 	  0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
15593631029SDavid du Colombier 	  0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
15693631029SDavid du Colombier 	  0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
15793631029SDavid du Colombier 	},
15893631029SDavid du Colombier };
15993631029SDavid du Colombier 
16093631029SDavid du Colombier OScreen oscreen;
161*5efba406SDavid du Colombier Settings settings[] = {
162*5efba406SDavid du Colombier [Res800x600]   {  800,  600, 60, RGB16,  40000,	 88, 40, 128,	23, 1, 5, },
163*5efba406SDavid du Colombier [Res1024x768]  { 1024,  768, 60, RGB16,  65000,	160, 24, 136,	29, 3, 7, },
164*5efba406SDavid du Colombier [Res1280x1024] { 1280, 1024, 60, RGB16, 108000,	248, 48, 112,	38, 1, 4, },
165*5efba406SDavid du Colombier [Res1400x1050] { 1400, 1050, 50, RGB16, 108000, 248, 48, 112,	38, 1, 4, }, // TODO
16693631029SDavid du Colombier };
167bacfa46cSDavid du Colombier Omap3fb *framebuf;
16893631029SDavid du Colombier Memimage *gscreen;
16993631029SDavid du Colombier 
17093631029SDavid du Colombier static Memdata xgdata;
17193631029SDavid du Colombier 
17293631029SDavid du Colombier static Memimage xgscreen =
17393631029SDavid du Colombier {
17493631029SDavid du Colombier 	{ 0, 0, Wid, Ht },	/* r */
17593631029SDavid du Colombier 	{ 0, 0, Wid, Ht },	/* clipr */
17693631029SDavid du Colombier 	Depth,			/* depth */
17793631029SDavid du Colombier 	3,			/* nchan */
17893631029SDavid du Colombier 	RGB16,			/* chan */
17993631029SDavid du Colombier 	nil,			/* cmap */
18093631029SDavid du Colombier 	&xgdata,		/* data */
18193631029SDavid du Colombier 	0,			/* zero */
18293631029SDavid du Colombier 	Wid*(Depth/BI2BY)/BY2WD, /* width in words of a single scan line */
18393631029SDavid du Colombier 	0,			/* layer */
18493631029SDavid du Colombier 	0,			/* flags */
18593631029SDavid du Colombier };
18693631029SDavid du Colombier 
18793631029SDavid du Colombier static Memimage *conscol;
18893631029SDavid du Colombier static Memimage *back;
18993631029SDavid du Colombier 
19093631029SDavid du Colombier static Memsubfont *memdefont;
19193631029SDavid du Colombier 
19293631029SDavid du Colombier static Lock screenlock;
19393631029SDavid du Colombier 
19493631029SDavid du Colombier static Point	curpos;
19593631029SDavid du Colombier static int	h, w;
19693631029SDavid du Colombier static int	landscape = 0;	/* screen orientation, default is 0: portrait */
19793631029SDavid du Colombier static ushort	*vscreen;	/* virtual screen */
19893631029SDavid du Colombier static Rectangle window;
19993631029SDavid du Colombier 
20093631029SDavid du Colombier static Dispc *dispc = (Dispc *)PHYSDISPC;
20193631029SDavid du Colombier static Dss *dss	= (Dss *)PHYSDSS;
20293631029SDavid du Colombier 
20393631029SDavid du Colombier static	void	omapscreenputs(char *s, int n);
20493631029SDavid du Colombier static	ulong	rep(ulong, int);
20593631029SDavid du Colombier static	void	screenputc(char *buf);
20693631029SDavid du Colombier static	void	screenwin(void);
20793631029SDavid du Colombier 
208*5efba406SDavid du Colombier /*
209*5efba406SDavid du Colombier  * Software cursor.
210*5efba406SDavid du Colombier  */
211*5efba406SDavid du Colombier int	swvisible;	/* is the cursor visible? */
212*5efba406SDavid du Colombier int	swenabled;	/* is the cursor supposed to be on the screen? */
213*5efba406SDavid du Colombier Memimage*	swback;	/* screen under cursor */
214*5efba406SDavid du Colombier Memimage*	swimg;	/* cursor image */
215*5efba406SDavid du Colombier Memimage*	swmask;	/* cursor mask */
216*5efba406SDavid du Colombier Memimage*	swimg1;
217*5efba406SDavid du Colombier Memimage*	swmask1;
218*5efba406SDavid du Colombier 
219*5efba406SDavid du Colombier Point	swoffset;
220*5efba406SDavid du Colombier Rectangle	swrect;	/* screen rectangle in swback */
221*5efba406SDavid du Colombier Point	swpt;	/* desired cursor location */
222*5efba406SDavid du Colombier Point	swvispt;	/* actual cursor location */
223*5efba406SDavid du Colombier int	swvers;	/* incremented each time cursor image changes */
224*5efba406SDavid du Colombier int	swvisvers;	/* the version on the screen */
225*5efba406SDavid du Colombier 
22693631029SDavid du Colombier static void
lcdoff(void)22793631029SDavid du Colombier lcdoff(void)
22893631029SDavid du Colombier {
22993631029SDavid du Colombier 	dispc->ctrl &= ~1;		/* disable the lcd */
23093631029SDavid du Colombier 	coherence();
23193631029SDavid du Colombier 
23293631029SDavid du Colombier 	dispc->irqstat1 |= 1;		/* set framedone */
23393631029SDavid du Colombier 	coherence();
23493631029SDavid du Colombier 
23593631029SDavid du Colombier 	/* the lcd never comes ready, so don't bother with this */
23693631029SDavid du Colombier #ifdef notdef
23793631029SDavid du Colombier 	/* spin until the frame is complete, but not forever */
23893631029SDavid du Colombier 	for(cnt = 50; !(dispc->irqstat1 & 1) && cnt-- > 0; )
23993631029SDavid du Colombier 		delay(10);
24093631029SDavid du Colombier #endif
24193631029SDavid du Colombier 	delay(20);			/* worst case for 1 frame, 50Hz */
24293631029SDavid du Colombier }
24393631029SDavid du Colombier 
24493631029SDavid du Colombier static void
dssstart(void)24593631029SDavid du Colombier dssstart(void)
24693631029SDavid du Colombier {
24793631029SDavid du Colombier 	/* should reset the dss system */
24893631029SDavid du Colombier 	dss->sysconf |= 1;
249634d7e5aSDavid du Colombier 	coherence();
25093631029SDavid du Colombier }
25193631029SDavid du Colombier 
252*5efba406SDavid du Colombier /* see spruf98i §15.6.7.4.2 */
25393631029SDavid du Colombier static void
configdispc(void)25493631029SDavid du Colombier configdispc(void)
25593631029SDavid du Colombier {
256*5efba406SDavid du Colombier 	Settings *sp;
257*5efba406SDavid du Colombier 
258*5efba406SDavid du Colombier 	sp = oscreen.settings;
25993631029SDavid du Colombier 	dss->ctrl &= 0x78;		/* choose dss clock */
26093631029SDavid du Colombier 	dispc->sysconf = Midlemode | Sidlemode | EnableWakeup | Autoidle;
26193631029SDavid du Colombier 	dispc->config = Loadmode;
26293631029SDavid du Colombier 	coherence();
26393631029SDavid du Colombier 
26493631029SDavid du Colombier 	/* pll */
26593631029SDavid du Colombier 	dispc->defaultcolor[0] = 0;	/* set background color to black? */
26693631029SDavid du Colombier 	dispc->defaultcolor[1] = 0;
26793631029SDavid du Colombier 	dispc->transcolor[0] = 0;	/* set transparency to full */
26893631029SDavid du Colombier 	dispc->transcolor[1] = 0;
26993631029SDavid du Colombier 
270*5efba406SDavid du Colombier 	dispc->timing_h = (sp->hbp-1) << 20 | (sp->hfp-1) << 8 |
271*5efba406SDavid du Colombier 			(sp->hsw-1);
272*5efba406SDavid du Colombier 	dispc->timing_v = sp->vbp << 20 | sp->vfp << 8 |
273*5efba406SDavid du Colombier 			(sp->vsw-1);
27493631029SDavid du Colombier 
27593631029SDavid du Colombier 	dispc->pol_req = Ipc | Ihs | Ivs | Acb;
276*5efba406SDavid du Colombier 	dispc->divisor = 1 << 16 | HOWMANY(432000, sp->pixelclock);
27793631029SDavid du Colombier 
278*5efba406SDavid du Colombier 	dispc->lcdsize = (sp->ht - 1) << 16 | (sp->wid - 1);
27993631029SDavid du Colombier 	coherence();
28093631029SDavid du Colombier 
28193631029SDavid du Colombier 	dispc->base[0] = PADDR(framebuf->pixel);
28293631029SDavid du Colombier 	dispc->base[1] = PADDR(framebuf->pixel);
28393631029SDavid du Colombier 
28493631029SDavid du Colombier 	dispc->pos = 0;			/* place screen in the left corner */
28593631029SDavid du Colombier 	/* use the whole screen */
286*5efba406SDavid du Colombier 	dispc->size = (sp->ht - 1) << 16 | (sp->wid - 1);
28793631029SDavid du Colombier 
28893631029SDavid du Colombier 	/* what mode does plan 9 use for fb? */
28993631029SDavid du Colombier 	dispc->attrib = Burstsize | Format | Gfxenable;
29093631029SDavid du Colombier 
29193631029SDavid du Colombier 	dispc->preload = Tft;
29293631029SDavid du Colombier 	dispc->fifosize = Fifosize;
29393631029SDavid du Colombier 	/* 1008 is max for our Burstsize */
29493631029SDavid du Colombier 	dispc->fifothr = (Fifosize - 1) << 16 | (1008 - 1);
29593631029SDavid du Colombier 
29693631029SDavid du Colombier 	/* 1 byte is one pixel (not true, we use 2 bytes per pixel) */
29793631029SDavid du Colombier 	dispc->rowinc = 1;
29893631029SDavid du Colombier 	dispc->pixelinc = 1;
29993631029SDavid du Colombier 	dispc->winskip = 0;		/* don't skip anything */
30093631029SDavid du Colombier 	coherence();
30193631029SDavid du Colombier 
30293631029SDavid du Colombier 	// dispc->palette = PADDR(framebuf->palette);
30393631029SDavid du Colombier }
30493631029SDavid du Colombier 
30593631029SDavid du Colombier static void
lcdon(int enable)30693631029SDavid du Colombier lcdon(int enable)
30793631029SDavid du Colombier {
30893631029SDavid du Colombier 	dispc->ctrl = Gpout1 | Gpout0 | Tftdata | Digital | Lcd | Stntft |
30993631029SDavid du Colombier 		Digitalen | enable;
31093631029SDavid du Colombier 	coherence();
31193631029SDavid du Colombier 	delay(10);
31293631029SDavid du Colombier }
31393631029SDavid du Colombier 
31493631029SDavid du Colombier static void
lcdstop(void)315634d7e5aSDavid du Colombier lcdstop(void)
31693631029SDavid du Colombier {
31793631029SDavid du Colombier 	configscreengpio();
31893631029SDavid du Colombier 	screenclockson();
31993631029SDavid du Colombier 
32093631029SDavid du Colombier 	lcdoff();
321634d7e5aSDavid du Colombier }
322634d7e5aSDavid du Colombier 
323634d7e5aSDavid du Colombier static void
lcdinit(void)324634d7e5aSDavid du Colombier lcdinit(void)
325634d7e5aSDavid du Colombier {
326634d7e5aSDavid du Colombier 	lcdstop();
327634d7e5aSDavid du Colombier 
32893631029SDavid du Colombier 	dssstart();
32993631029SDavid du Colombier 	configdispc();
33093631029SDavid du Colombier }
33193631029SDavid du Colombier 
33293631029SDavid du Colombier /* Paint the image data with blue pixels */
33393631029SDavid du Colombier void
screentest(void)33493631029SDavid du Colombier screentest(void)
33593631029SDavid du Colombier {
336bacfa46cSDavid du Colombier 	int i;
33793631029SDavid du Colombier 
338bacfa46cSDavid du Colombier 	for (i = nelem(framebuf->pixel) - 1; i >= 0; i--)
339bacfa46cSDavid du Colombier 		framebuf->pixel[i] = 0x1f;			/* blue */
34093631029SDavid du Colombier //	memset(framebuf->pixel, ~0, sizeof framebuf->pixel);	/* white */
34193631029SDavid du Colombier }
34293631029SDavid du Colombier 
34393631029SDavid du Colombier void
screenpower(int on)34493631029SDavid du Colombier screenpower(int on)
34593631029SDavid du Colombier {
34693631029SDavid du Colombier 	blankscreen(on == 0);
34793631029SDavid du Colombier }
34893631029SDavid du Colombier 
349*5efba406SDavid du Colombier /*
350*5efba406SDavid du Colombier  * called with drawlock locked for us, most of the time.
351*5efba406SDavid du Colombier  * kernel prints at inopportune times might mean we don't
352*5efba406SDavid du Colombier  * hold the lock, but memimagedraw is now reentrant so
353*5efba406SDavid du Colombier  * that should be okay: worst case we get cursor droppings.
354*5efba406SDavid du Colombier  */
355*5efba406SDavid du Colombier void
swcursorhide(void)356*5efba406SDavid du Colombier swcursorhide(void)
35793631029SDavid du Colombier {
358*5efba406SDavid du Colombier 	if(swvisible == 0)
359*5efba406SDavid du Colombier 		return;
360*5efba406SDavid du Colombier 	if(swback == nil)
361*5efba406SDavid du Colombier 		return;
362*5efba406SDavid du Colombier 	swvisible = 0;
363*5efba406SDavid du Colombier 	memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
364*5efba406SDavid du Colombier 	flushmemscreen(swrect);
365*5efba406SDavid du Colombier }
366*5efba406SDavid du Colombier 
367*5efba406SDavid du Colombier void
swcursoravoid(Rectangle r)368*5efba406SDavid du Colombier swcursoravoid(Rectangle r)
369*5efba406SDavid du Colombier {
370*5efba406SDavid du Colombier 	if(swvisible && rectXrect(r, swrect))
371*5efba406SDavid du Colombier 		swcursorhide();
372*5efba406SDavid du Colombier }
373*5efba406SDavid du Colombier 
374*5efba406SDavid du Colombier void
swcursordraw(void)375*5efba406SDavid du Colombier swcursordraw(void)
376*5efba406SDavid du Colombier {
377*5efba406SDavid du Colombier 	if(swvisible)
378*5efba406SDavid du Colombier 		return;
379*5efba406SDavid du Colombier 	if(swenabled == 0)
380*5efba406SDavid du Colombier 		return;
381*5efba406SDavid du Colombier 	if(swback == nil || swimg1 == nil || swmask1 == nil)
382*5efba406SDavid du Colombier 		return;
383*5efba406SDavid du Colombier //	assert(!canqlock(&drawlock));		// assertion fails on omap
384*5efba406SDavid du Colombier 	swvispt = swpt;
385*5efba406SDavid du Colombier 	swvisvers = swvers;
386*5efba406SDavid du Colombier 	swrect = rectaddpt(Rect(0,0,16,16), swvispt);
387*5efba406SDavid du Colombier 	memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
388*5efba406SDavid du Colombier 	memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
389*5efba406SDavid du Colombier 	flushmemscreen(swrect);
390*5efba406SDavid du Colombier 	swvisible = 1;
391*5efba406SDavid du Colombier }
392*5efba406SDavid du Colombier 
393*5efba406SDavid du Colombier int
cursoron(int dolock)394*5efba406SDavid du Colombier cursoron(int dolock)
395*5efba406SDavid du Colombier {
396*5efba406SDavid du Colombier 	if (dolock)
397*5efba406SDavid du Colombier 		lock(&oscreen);
398*5efba406SDavid du Colombier 	cursoroff(0);
399*5efba406SDavid du Colombier 	swcursordraw();
400*5efba406SDavid du Colombier 	if (dolock)
401*5efba406SDavid du Colombier 		unlock(&oscreen);
40293631029SDavid du Colombier 	return 0;
40393631029SDavid du Colombier }
40493631029SDavid du Colombier 
40593631029SDavid du Colombier void
cursoroff(int dolock)406*5efba406SDavid du Colombier cursoroff(int dolock)
40793631029SDavid du Colombier {
408*5efba406SDavid du Colombier 	if (dolock)
409*5efba406SDavid du Colombier 		lock(&oscreen);
410*5efba406SDavid du Colombier 	swcursorhide();
411*5efba406SDavid du Colombier 	if (dolock)
412*5efba406SDavid du Colombier 		unlock(&oscreen);
41393631029SDavid du Colombier }
41493631029SDavid du Colombier 
41593631029SDavid du Colombier void
swload(Cursor * curs)416*5efba406SDavid du Colombier swload(Cursor *curs)
41793631029SDavid du Colombier {
418*5efba406SDavid du Colombier 	uchar *ip, *mp;
419*5efba406SDavid du Colombier 	int i, j, set, clr;
42093631029SDavid du Colombier 
421*5efba406SDavid du Colombier 	if(!swimg || !swmask || !swimg1 || !swmask1)
422*5efba406SDavid du Colombier 		return;
423*5efba406SDavid du Colombier 	/*
424*5efba406SDavid du Colombier 	 * Build cursor image and mask.
425*5efba406SDavid du Colombier 	 * Image is just the usual cursor image
426*5efba406SDavid du Colombier 	 * but mask is a transparent alpha mask.
427*5efba406SDavid du Colombier 	 *
428*5efba406SDavid du Colombier 	 * The 16x16x8 memimages do not have
429*5efba406SDavid du Colombier 	 * padding at the end of their scan lines.
430*5efba406SDavid du Colombier 	 */
431*5efba406SDavid du Colombier 	ip = byteaddr(swimg, ZP);
432*5efba406SDavid du Colombier 	mp = byteaddr(swmask, ZP);
433*5efba406SDavid du Colombier 	for(i=0; i<32; i++){
434*5efba406SDavid du Colombier 		set = curs->set[i];
435*5efba406SDavid du Colombier 		clr = curs->clr[i];
436*5efba406SDavid du Colombier 		for(j=0x80; j; j>>=1){
437*5efba406SDavid du Colombier 			*ip++ = set&j ? 0x00 : 0xFF;
438*5efba406SDavid du Colombier 			*mp++ = (clr|set)&j ? 0xFF : 0x00;
439*5efba406SDavid du Colombier 		}
440*5efba406SDavid du Colombier 	}
441*5efba406SDavid du Colombier 	swoffset = curs->offset;
442*5efba406SDavid du Colombier 	swvers++;
443*5efba406SDavid du Colombier 	memimagedraw(swimg1,  swimg1->r,  swimg,  ZP, memopaque, ZP, S);
444*5efba406SDavid du Colombier 	memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
445*5efba406SDavid du Colombier }
446*5efba406SDavid du Colombier 
447*5efba406SDavid du Colombier /* called from devmouse */
448*5efba406SDavid du Colombier void
setcursor(Cursor * curs)449*5efba406SDavid du Colombier setcursor(Cursor* curs)
450*5efba406SDavid du Colombier {
451*5efba406SDavid du Colombier 	cursoroff(1);
452*5efba406SDavid du Colombier 	oscreen.Cursor = *curs;
453*5efba406SDavid du Colombier 	swload(curs);
454*5efba406SDavid du Colombier 	cursoron(1);
455*5efba406SDavid du Colombier }
456*5efba406SDavid du Colombier 
457*5efba406SDavid du Colombier int
swmove(Point p)458*5efba406SDavid du Colombier swmove(Point p)
459*5efba406SDavid du Colombier {
460*5efba406SDavid du Colombier 	swpt = addpt(p, swoffset);
461*5efba406SDavid du Colombier 	return 0;
462*5efba406SDavid du Colombier }
463*5efba406SDavid du Colombier 
464*5efba406SDavid du Colombier void
swcursorclock(void)465*5efba406SDavid du Colombier swcursorclock(void)
466*5efba406SDavid du Colombier {
467*5efba406SDavid du Colombier 	int x;
468*5efba406SDavid du Colombier 
469*5efba406SDavid du Colombier 	if(!swenabled)
470*5efba406SDavid du Colombier 		return;
471*5efba406SDavid du Colombier 	swmove(mousexy());
472*5efba406SDavid du Colombier 	if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
473*5efba406SDavid du Colombier 		return;
474*5efba406SDavid du Colombier 
475*5efba406SDavid du Colombier 	x = splhi();
476*5efba406SDavid du Colombier 	if(swenabled)
477*5efba406SDavid du Colombier 	if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
478*5efba406SDavid du Colombier 	if(canqlock(&drawlock)){
479*5efba406SDavid du Colombier 		swcursorhide();
480*5efba406SDavid du Colombier 		swcursordraw();
481*5efba406SDavid du Colombier 		qunlock(&drawlock);
482*5efba406SDavid du Colombier 	}
483*5efba406SDavid du Colombier 	splx(x);
484*5efba406SDavid du Colombier }
485*5efba406SDavid du Colombier 
486*5efba406SDavid du Colombier void
swcursorinit(void)487*5efba406SDavid du Colombier swcursorinit(void)
488*5efba406SDavid du Colombier {
489*5efba406SDavid du Colombier 	static int init;
490*5efba406SDavid du Colombier 
491*5efba406SDavid du Colombier 	if(!init){
492*5efba406SDavid du Colombier 		init = 1;
493*5efba406SDavid du Colombier 		addclock0link(swcursorclock, 10);
494*5efba406SDavid du Colombier 	}
495*5efba406SDavid du Colombier 	if(swback){
496*5efba406SDavid du Colombier 		freememimage(swback);
497*5efba406SDavid du Colombier 		freememimage(swmask);
498*5efba406SDavid du Colombier 		freememimage(swmask1);
499*5efba406SDavid du Colombier 		freememimage(swimg);
500*5efba406SDavid du Colombier 		freememimage(swimg1);
501*5efba406SDavid du Colombier 	}
502*5efba406SDavid du Colombier 
503*5efba406SDavid du Colombier 	swback  = allocmemimage(Rect(0,0,32,32), gscreen->chan);
504*5efba406SDavid du Colombier 	swmask  = allocmemimage(Rect(0,0,16,16), GREY8);
505*5efba406SDavid du Colombier 	swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
506*5efba406SDavid du Colombier 	swimg   = allocmemimage(Rect(0,0,16,16), GREY8);
507*5efba406SDavid du Colombier 	swimg1  = allocmemimage(Rect(0,0,16,16), GREY1);
508*5efba406SDavid du Colombier 	if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
509*5efba406SDavid du Colombier 		print("software cursor: allocmemimage fails\n");
510*5efba406SDavid du Colombier 		return;
511*5efba406SDavid du Colombier 	}
512*5efba406SDavid du Colombier 
513*5efba406SDavid du Colombier 	memfillcolor(swmask, DOpaque);
514*5efba406SDavid du Colombier 	memfillcolor(swmask1, DOpaque);
515*5efba406SDavid du Colombier 	memfillcolor(swimg, DBlack);
516*5efba406SDavid du Colombier 	memfillcolor(swimg1, DBlack);
51793631029SDavid du Colombier }
51893631029SDavid du Colombier 
519634d7e5aSDavid du Colombier /* called from main and possibly later from devdss to change resolution */
52093631029SDavid du Colombier void
screeninit(void)52193631029SDavid du Colombier screeninit(void)
52293631029SDavid du Colombier {
523634d7e5aSDavid du Colombier 	static int first = 1;
524634d7e5aSDavid du Colombier 
525634d7e5aSDavid du Colombier 	if (first) {
52693631029SDavid du Colombier 		iprint("screeninit...");
527*5efba406SDavid du Colombier 		oscreen.settings = &settings[Res1280x1024];
528634d7e5aSDavid du Colombier 
529634d7e5aSDavid du Colombier 		lcdstop();
530634d7e5aSDavid du Colombier 		if (framebuf)
531634d7e5aSDavid du Colombier 			free(framebuf);
53293631029SDavid du Colombier 		/* mode is 16*32 = 512 */
53393631029SDavid du Colombier 		framebuf = xspanalloc(sizeof *framebuf, 16*32, 0);
534634d7e5aSDavid du Colombier 	}
53593631029SDavid du Colombier 
53693631029SDavid du Colombier 	lcdinit();
53793631029SDavid du Colombier 	lcdon(1);
538634d7e5aSDavid du Colombier 	if (first) {
539634d7e5aSDavid du Colombier 		memimageinit();
540634d7e5aSDavid du Colombier 		memdefont = getmemdefont();
54193631029SDavid du Colombier 		screentest();
542634d7e5aSDavid du Colombier 	}
54393631029SDavid du Colombier 
54493631029SDavid du Colombier 	xgdata.ref = 1;
54593631029SDavid du Colombier 	xgdata.bdata = (uchar *)framebuf->pixel;
54693631029SDavid du Colombier 
54793631029SDavid du Colombier 	gscreen = &xgscreen;
54893631029SDavid du Colombier 	gscreen->r = Rect(0, 0, Wid, Ht);
54993631029SDavid du Colombier 	gscreen->clipr = gscreen->r;
55093631029SDavid du Colombier 	/* width, in words, of a single scan line */
55193631029SDavid du Colombier 	gscreen->width = Wid * (Depth / BI2BY) / BY2WD;
55293631029SDavid du Colombier 	flushmemscreen(gscreen->r);
55393631029SDavid du Colombier 
554*5efba406SDavid du Colombier 	blanktime = 3;				/* minutes */
555*5efba406SDavid du Colombier 
556634d7e5aSDavid du Colombier 	if (first) {
557634d7e5aSDavid du Colombier 		iprint("on: blue for 3 seconds...");
558634d7e5aSDavid du Colombier 		delay(3*1000);
55993631029SDavid du Colombier 		iprint("\n");
56093631029SDavid du Colombier 
561bacfa46cSDavid du Colombier 		screenwin();		/* draw border & top orange bar */
56293631029SDavid du Colombier 		screenputs = omapscreenputs;
563634d7e5aSDavid du Colombier 		iprint("screen: frame buffer at %#p for %dx%d\n",
564*5efba406SDavid du Colombier 			framebuf, oscreen.settings->wid, oscreen.settings->ht);
565*5efba406SDavid du Colombier 
566*5efba406SDavid du Colombier 		swenabled = 1;
567*5efba406SDavid du Colombier 		swcursorinit();		/* needs gscreen set */
568*5efba406SDavid du Colombier 		setcursor(&arrow);
569*5efba406SDavid du Colombier 
570634d7e5aSDavid du Colombier 		first = 0;
571634d7e5aSDavid du Colombier 	}
57293631029SDavid du Colombier }
57393631029SDavid du Colombier 
57493631029SDavid du Colombier /* flushmemscreen should change buffer? */
57593631029SDavid du Colombier void
flushmemscreen(Rectangle r)57693631029SDavid du Colombier flushmemscreen(Rectangle r)
57793631029SDavid du Colombier {
57893631029SDavid du Colombier 	ulong start, end;
57993631029SDavid du Colombier 
58093631029SDavid du Colombier 	if (r.min.x < 0)
58193631029SDavid du Colombier 		r.min.x = 0;
58293631029SDavid du Colombier 	if (r.max.x > Wid)
58393631029SDavid du Colombier 		r.max.x = Wid;
58493631029SDavid du Colombier 	if (r.min.y < 0)
58593631029SDavid du Colombier 		r.min.y = 0;
58693631029SDavid du Colombier 	if (r.max.y > Ht)
58793631029SDavid du Colombier 		r.max.y = Ht;
58893631029SDavid du Colombier 	if (rectclip(&r, gscreen->r) == 0)
58993631029SDavid du Colombier 		return;
59093631029SDavid du Colombier 	start = (ulong)&framebuf->pixel[r.min.y*Wid + r.min.x];
59193631029SDavid du Colombier 	end   = (ulong)&framebuf->pixel[(r.max.y - 1)*Wid + r.max.x -1];
59293631029SDavid du Colombier 	cachedwbse((ulong *)start, end - start);
59393631029SDavid du Colombier }
59493631029SDavid du Colombier 
59593631029SDavid du Colombier /*
59693631029SDavid du Colombier  * export screen to devdraw
59793631029SDavid du Colombier  */
59893631029SDavid du Colombier uchar*
attachscreen(Rectangle * r,ulong * chan,int * d,int * width,int * softscreen)59993631029SDavid du Colombier attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen)
60093631029SDavid du Colombier {
60193631029SDavid du Colombier 	*r = gscreen->r;
60293631029SDavid du Colombier 	*d = gscreen->depth;
60393631029SDavid du Colombier 	*chan = gscreen->chan;
60493631029SDavid du Colombier 	*width = gscreen->width;
60593631029SDavid du Colombier 	*softscreen = (landscape == 0);
60693631029SDavid du Colombier 	return (uchar *)gscreen->data->bdata;
60793631029SDavid du Colombier }
60893631029SDavid du Colombier 
60993631029SDavid du Colombier void
getcolor(ulong p,ulong * pr,ulong * pg,ulong * pb)61093631029SDavid du Colombier getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
61193631029SDavid du Colombier {
61293631029SDavid du Colombier 	USED(p, pr, pg, pb);
61393631029SDavid du Colombier }
61493631029SDavid du Colombier 
61593631029SDavid du Colombier int
setcolor(ulong p,ulong r,ulong g,ulong b)61693631029SDavid du Colombier setcolor(ulong p, ulong r, ulong g, ulong b)
61793631029SDavid du Colombier {
61893631029SDavid du Colombier 	USED(p, r, g, b);
61993631029SDavid du Colombier 	return 0;
62093631029SDavid du Colombier }
62193631029SDavid du Colombier 
62293631029SDavid du Colombier void
blankscreen(int blank)62393631029SDavid du Colombier blankscreen(int blank)
62493631029SDavid du Colombier {
62593631029SDavid du Colombier 	if (blank)
62693631029SDavid du Colombier 		lcdon(0);
62793631029SDavid du Colombier 	else {
62893631029SDavid du Colombier 		lcdinit();
62993631029SDavid du Colombier 		lcdon(1);
63093631029SDavid du Colombier 	}
63193631029SDavid du Colombier }
63293631029SDavid du Colombier 
63393631029SDavid du Colombier static void
omapscreenputs(char * s,int n)63493631029SDavid du Colombier omapscreenputs(char *s, int n)
63593631029SDavid du Colombier {
63693631029SDavid du Colombier 	int i;
63793631029SDavid du Colombier 	Rune r;
63893631029SDavid du Colombier 	char buf[4];
63993631029SDavid du Colombier 
64093631029SDavid du Colombier 	if (!islo()) {
64193631029SDavid du Colombier 		/* don't deadlock trying to print in interrupt */
64293631029SDavid du Colombier 		if (!canlock(&screenlock))
64393631029SDavid du Colombier 			return;			/* discard s */
64493631029SDavid du Colombier 	} else
64593631029SDavid du Colombier 		lock(&screenlock);
64693631029SDavid du Colombier 
64793631029SDavid du Colombier 	while (n > 0) {
64893631029SDavid du Colombier 		i = chartorune(&r, s);
64993631029SDavid du Colombier 		if (i == 0) {
65093631029SDavid du Colombier 			s++;
65193631029SDavid du Colombier 			--n;
65293631029SDavid du Colombier 			continue;
65393631029SDavid du Colombier 		}
65493631029SDavid du Colombier 		memmove(buf, s, i);
65593631029SDavid du Colombier 		buf[i] = 0;
65693631029SDavid du Colombier 		n -= i;
65793631029SDavid du Colombier 		s += i;
65893631029SDavid du Colombier 		screenputc(buf);
65993631029SDavid du Colombier 	}
66093631029SDavid du Colombier 	unlock(&screenlock);
66193631029SDavid du Colombier }
66293631029SDavid du Colombier 
66393631029SDavid du Colombier static void
screenwin(void)66493631029SDavid du Colombier screenwin(void)
66593631029SDavid du Colombier {
66693631029SDavid du Colombier 	char *greet;
66793631029SDavid du Colombier 	Memimage *orange;
66893631029SDavid du Colombier 	Point p, q;
66993631029SDavid du Colombier 	Rectangle r;
67093631029SDavid du Colombier 
67193631029SDavid du Colombier 	memsetchan(gscreen, RGB16);
67293631029SDavid du Colombier 
67393631029SDavid du Colombier 	back = memwhite;
67493631029SDavid du Colombier 	conscol = memblack;
67593631029SDavid du Colombier 
67693631029SDavid du Colombier 	orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
67793631029SDavid du Colombier 	orange->flags |= Frepl;
67893631029SDavid du Colombier 	orange->clipr = gscreen->r;
67993631029SDavid du Colombier 	orange->data->bdata[0] = 0x40;		/* magic: colour? */
68093631029SDavid du Colombier 	orange->data->bdata[1] = 0xfd;		/* magic: colour? */
68193631029SDavid du Colombier 
68293631029SDavid du Colombier 	w = memdefont->info[' '].width;
68393631029SDavid du Colombier 	h = memdefont->height;
68493631029SDavid du Colombier 
68593631029SDavid du Colombier 	r = insetrect(gscreen->r, 4);
68693631029SDavid du Colombier 
68793631029SDavid du Colombier 	memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
68893631029SDavid du Colombier 	window = insetrect(r, 4);
68993631029SDavid du Colombier 	memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
69093631029SDavid du Colombier 
69193631029SDavid du Colombier 	memimagedraw(gscreen, Rect(window.min.x, window.min.y,
69293631029SDavid du Colombier 		window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
69393631029SDavid du Colombier 	freememimage(orange);
69493631029SDavid du Colombier 	window = insetrect(window, 5);
69593631029SDavid du Colombier 
69693631029SDavid du Colombier 	greet = " Plan 9 Console ";
69793631029SDavid du Colombier 	p = addpt(window.min, Pt(10, 0));
69893631029SDavid du Colombier 	q = memsubfontwidth(memdefont, greet);
69993631029SDavid du Colombier 	memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
70093631029SDavid du Colombier 	flushmemscreen(r);
70193631029SDavid du Colombier 	window.min.y += h + 6;
70293631029SDavid du Colombier 	curpos = window.min;
70393631029SDavid du Colombier 	window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
70493631029SDavid du Colombier }
70593631029SDavid du Colombier 
70693631029SDavid du Colombier static void
scroll(void)70793631029SDavid du Colombier scroll(void)
70893631029SDavid du Colombier {
70993631029SDavid du Colombier 	int o;
71093631029SDavid du Colombier 	Point p;
71193631029SDavid du Colombier 	Rectangle r;
71293631029SDavid du Colombier 
713634d7e5aSDavid du Colombier 	/* move window contents up Scroll text lines */
714634d7e5aSDavid du Colombier 	o = Scroll * h;
71593631029SDavid du Colombier 	r = Rpt(window.min, Pt(window.max.x, window.max.y - o));
71693631029SDavid du Colombier 	p = Pt(window.min.x, window.min.y + o);
71793631029SDavid du Colombier 	memimagedraw(gscreen, r, gscreen, p, nil, p, S);
71893631029SDavid du Colombier 	flushmemscreen(r);
71993631029SDavid du Colombier 
720634d7e5aSDavid du Colombier 	/* clear the bottom Scroll text lines */
72193631029SDavid du Colombier 	r = Rpt(Pt(window.min.x, window.max.y - o), window.max);
72293631029SDavid du Colombier 	memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
72393631029SDavid du Colombier 	flushmemscreen(r);
72493631029SDavid du Colombier 
72593631029SDavid du Colombier 	curpos.y -= o;
72693631029SDavid du Colombier }
72793631029SDavid du Colombier 
72893631029SDavid du Colombier static void
screenputc(char * buf)72993631029SDavid du Colombier screenputc(char *buf)
73093631029SDavid du Colombier {
73193631029SDavid du Colombier 	int w;
73293631029SDavid du Colombier 	uint pos;
73393631029SDavid du Colombier 	Point p;
73493631029SDavid du Colombier 	Rectangle r;
73593631029SDavid du Colombier 	static int *xp;
73693631029SDavid du Colombier 	static int xbuf[256];
73793631029SDavid du Colombier 
73893631029SDavid du Colombier 	if (xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
73993631029SDavid du Colombier 		xp = xbuf;
74093631029SDavid du Colombier 
74193631029SDavid du Colombier 	switch (buf[0]) {
74293631029SDavid du Colombier 	case '\n':
74393631029SDavid du Colombier 		if (curpos.y + h >= window.max.y)
74493631029SDavid du Colombier 			scroll();
74593631029SDavid du Colombier 		curpos.y += h;
74693631029SDavid du Colombier 		screenputc("\r");
74793631029SDavid du Colombier 		break;
74893631029SDavid du Colombier 	case '\r':
74993631029SDavid du Colombier 		xp = xbuf;
75093631029SDavid du Colombier 		curpos.x = window.min.x;
75193631029SDavid du Colombier 		break;
75293631029SDavid du Colombier 	case '\t':
75393631029SDavid du Colombier 		p = memsubfontwidth(memdefont, " ");
75493631029SDavid du Colombier 		w = p.x;
75593631029SDavid du Colombier 		if (curpos.x >= window.max.x - Tabstop * w)
75693631029SDavid du Colombier 			screenputc("\n");
75793631029SDavid du Colombier 
75893631029SDavid du Colombier 		pos = (curpos.x - window.min.x) / w;
75993631029SDavid du Colombier 		pos = Tabstop - pos % Tabstop;
76093631029SDavid du Colombier 		*xp++ = curpos.x;
76193631029SDavid du Colombier 		r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
76293631029SDavid du Colombier 		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
76393631029SDavid du Colombier 		flushmemscreen(r);
76493631029SDavid du Colombier 		curpos.x += pos * w;
76593631029SDavid du Colombier 		break;
76693631029SDavid du Colombier 	case '\b':
76793631029SDavid du Colombier 		if (xp <= xbuf)
76893631029SDavid du Colombier 			break;
76993631029SDavid du Colombier 		xp--;
77093631029SDavid du Colombier 		r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
77193631029SDavid du Colombier 		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
77293631029SDavid du Colombier 		flushmemscreen(r);
77393631029SDavid du Colombier 		curpos.x = *xp;
77493631029SDavid du Colombier 		break;
77593631029SDavid du Colombier 	case '\0':
77693631029SDavid du Colombier 		break;
77793631029SDavid du Colombier 	default:
77893631029SDavid du Colombier 		p = memsubfontwidth(memdefont, buf);
77993631029SDavid du Colombier 		w = p.x;
78093631029SDavid du Colombier 
78193631029SDavid du Colombier 		if (curpos.x >= window.max.x - w)
78293631029SDavid du Colombier 			screenputc("\n");
78393631029SDavid du Colombier 
78493631029SDavid du Colombier 		*xp++ = curpos.x;
78593631029SDavid du Colombier 		r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
78693631029SDavid du Colombier 		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
78793631029SDavid du Colombier 		memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
78893631029SDavid du Colombier 		flushmemscreen(r);
78993631029SDavid du Colombier 		curpos.x += w;
79093631029SDavid du Colombier 	}
79193631029SDavid du Colombier }
792