1 /*
2  *  Copyright (C) 2006-2018  Anders Gavare.  All rights reserved.
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions are met:
6  *
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. The name of the author may not be used to endorse or promote products
13  *     derived from this software without specific prior written permission.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  *  SUCH DAMAGE.
26  *
27  *
28  *  COMMENT: Framebuffer controller device (control's dev_fb in test machines)
29  *
30  *  A "framebuffer control" device. It can be used to manipulate the
31  *  framebuffer device in testmachines.
32  */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "cpu.h"
39 #include "device.h"
40 #include "devices.h"
41 #include "machine.h"
42 #include "memory.h"
43 #include "misc.h"
44 
45 #include "testmachine/dev_fb.h"
46 
47 
48 struct fbctrl_data {
49 	struct vfb_data *vfb_data;
50 	int		current_port;
51 	int		port[DEV_FBCTRL_NPORTS];
52 };
53 
54 
55 /*
56  *  fbctrl_command():
57  *
58  *  Execute a framebuffer control command.
59  */
fbctrl_command(struct cpu * cpu,struct fbctrl_data * d)60 static void fbctrl_command(struct cpu *cpu, struct fbctrl_data *d)
61 {
62 	int cmd = d->port[DEV_FBCTRL_PORT_COMMAND];
63 	int x1, y1, i;
64 
65 	switch (cmd) {
66 
67 	case DEV_FBCTRL_COMMAND_NOP:
68 		break;
69 
70 	case DEV_FBCTRL_COMMAND_SET_RESOLUTION:
71 		/*
72 		 *  Change the framebuffer resolution to X1 x Y1 pixels.
73 		 */
74 		x1 = d->port[DEV_FBCTRL_PORT_X1];
75 		y1 = d->port[DEV_FBCTRL_PORT_Y1];
76 		debug("[ dev_fbctrl: changing resolution to %i,%i ]\n", x1, y1);
77 
78 		dev_fb_resize(d->vfb_data, x1, y1);
79 
80 		/*  Remember to invalidate all translations for anyone
81 		    who might have used the old framebuffer:  */
82 		for (i = 0; i < cpu->machine->ncpus; i++)
83 			cpu->machine->cpus[i]->invalidate_translation_caches(
84 			    cpu->machine->cpus[i], 0, INVALIDATE_ALL);
85 		break;
86 
87 	case DEV_FBCTRL_COMMAND_GET_RESOLUTION:
88 		if (cpu->machine->x11_md.in_use) {
89 			d->port[DEV_FBCTRL_PORT_X1] = d->vfb_data->xsize;
90 			d->port[DEV_FBCTRL_PORT_Y1] = d->vfb_data->ysize;
91 		} else {
92 			// When not using X11 output, return 0x0 size.
93 			d->port[DEV_FBCTRL_PORT_X1] = 0;
94 			d->port[DEV_FBCTRL_PORT_Y1] = 0;
95 		}
96 		break;
97 
98 	/*  TODO: Block copy and fill.  */
99 
100 	default:fatal("fbctrl_command: Unimplemented command %i.\n", cmd);
101 		exit(1);
102 	}
103 }
104 
105 
DEVICE_ACCESS(fbctrl)106 DEVICE_ACCESS(fbctrl)
107 {
108 	struct fbctrl_data *d = (struct fbctrl_data *) extra;
109 	uint64_t idata = 0, odata = 0;
110 
111 	if (writeflag == MEM_WRITE)
112 	        idata = memory_readmax64(cpu, data, len);
113 
114 	switch (relative_addr) {
115 
116 	case DEV_FBCTRL_PORT:
117 		if (writeflag == MEM_READ)
118 			odata = d->current_port;
119 		else {
120 			d->current_port = idata;
121 			if (idata >= DEV_FBCTRL_NPORTS)
122 				fatal("[ WARNING: fbctrl port number is out"
123 				    " of range! ]\n");
124 		}
125 		break;
126 
127 	case DEV_FBCTRL_DATA:
128 		if (d->current_port < 0 || d->current_port
129 		    >= DEV_FBCTRL_NPORTS) {
130 			fatal("[ fbctrl port number is out of range! ]\n");
131 			exit(1);
132 		}
133 
134 		if (writeflag == MEM_READ)
135 			odata = d->port[d->current_port];
136 		else {
137 			d->port[d->current_port] = idata;
138 			if (d->current_port == DEV_FBCTRL_PORT_COMMAND)
139 				fbctrl_command(cpu, d);
140 		}
141 
142 		break;
143 
144 	default:
145 		fatal("[ dev_fbctrl: unimplemented relative addr 0x%x ]\n",
146 		    (int)relative_addr);
147 		exit(1);
148 	}
149 
150 	if (writeflag == MEM_READ)
151 		memory_writemax64(cpu, data, len, odata);
152 
153 	return 1;
154 }
155 
156 
DEVINIT(fbctrl)157 DEVINIT(fbctrl)
158 {
159 	struct fbctrl_data *d;
160 
161 	CHECK_ALLOCATION(d = (struct fbctrl_data *) malloc(sizeof(struct fbctrl_data)));
162 	memset(d, 0, sizeof(struct fbctrl_data));
163 
164 	d->vfb_data = dev_fb_init(devinit->machine, devinit->machine->memory,
165 	    DEV_FB_ADDRESS, VFB_GENERIC, 640, 480, 640, DEV_FBCTRL_MAXY(640),
166 	    24, "generic");
167 
168 	memory_device_register(devinit->machine->memory, devinit->name,
169 	    devinit->addr, DEV_FBCTRL_LENGTH, dev_fbctrl_access, d,
170 	    DM_DEFAULT, NULL);
171 
172 	return 1;
173 }
174 
175