File hw/xalga/ddx.c added (mode: 100644) (index 0000000..d992b77) |
|
1 |
|
/* |
|
2 |
|
* XALGA implementation |
|
3 |
|
* Copyright (C) 2014 Sylvain BERTRAND All Rights Reserved |
|
4 |
|
* Opens source legal protection provided by a GNU Lesser GPLv3 license |
|
5 |
|
*/ |
|
6 |
|
#define _POSIX_C_SOURCE 200809L /* scandir */ |
|
7 |
|
#include <linux/input.h> |
|
8 |
|
#include <errno.h> |
|
9 |
|
#include <unistd.h> |
|
10 |
|
#include <dirent.h> |
|
11 |
|
|
|
12 |
|
#include "dix-config.h" |
|
13 |
|
#include "extension.h" |
|
14 |
|
#include "screenint.h" |
|
15 |
|
#include "scrnintstr.h" |
|
16 |
|
#include "servermd.h" |
|
17 |
|
#include "mi.h" |
|
18 |
|
#include "input.h" |
|
19 |
|
#include "list.h" |
|
20 |
|
|
|
21 |
|
#include "xalga_glx_extinit.h" |
|
22 |
|
|
|
23 |
|
#include "xalga/namespace.h" |
|
24 |
|
#include "xalga/output.h" |
|
25 |
|
#include "xalga/evdev/axis/rel.h" |
|
26 |
|
#include "xalga/evdev/evdev.h" |
|
27 |
|
|
|
28 |
|
|
|
29 |
|
/*----------------------------------------------------------------------------*/ |
|
30 |
|
/* we do the link with our GLX implementation here */ |
|
31 |
|
static Bool no_xalga_glx_extension = FALSE; |
|
32 |
|
static const ExtensionModule xalga_extensions[] = { |
|
33 |
|
{xalga_glx_extension_init, "GLX", &no_xalga_glx_extension} |
|
34 |
|
}; |
|
35 |
|
/*----------------------------------------------------------------------------*/ |
|
36 |
|
|
|
37 |
|
|
|
38 |
|
/*----------------------------------------------------------------------------*/ |
|
39 |
|
/* hardcoded evdev devices for pointers and keyboards */ |
|
40 |
|
static struct xorg_list evdevs_head; |
|
41 |
|
/*----------------------------------------------------------------------------*/ |
|
42 |
|
|
|
43 |
|
|
|
44 |
|
/*----------------------------------------------------------------------------*/ |
|
45 |
|
static int event_filter(const struct dirent *dirent); |
|
46 |
|
static void event_add(struct dirent *dirent, long fs_name_sz_max); |
|
47 |
|
/*----------------------------------------------------------------------------*/ |
|
48 |
|
|
|
49 |
|
|
|
50 |
|
/******************************************************************************/ |
|
51 |
|
/* in this section, you will have the mandatory entry points for a ddx */ |
|
52 |
|
void |
|
53 |
|
DDXRingBell(int volume, int pitch, int duration) |
|
54 |
|
{ |
|
55 |
|
} |
|
56 |
|
|
|
57 |
|
void |
|
58 |
|
ProcessInputEvents(void) |
|
59 |
|
{ |
|
60 |
|
mieqProcessInputEvents(); |
|
61 |
|
} |
|
62 |
|
|
|
63 |
|
Bool |
|
64 |
|
LegalModifier(unsigned int key, DeviceIntPtr pDev) |
|
65 |
|
{ |
|
66 |
|
return TRUE; |
|
67 |
|
} |
|
68 |
|
|
|
69 |
|
int |
|
70 |
|
ddxProcessArgument(int argc, char *argv[], int i) |
|
71 |
|
{ |
|
72 |
|
return 0; |
|
73 |
|
} |
|
74 |
|
|
|
75 |
|
void |
|
76 |
|
ddxUseMsg(void) |
|
77 |
|
{ |
|
78 |
|
} |
|
79 |
|
|
|
80 |
|
void |
|
81 |
|
ddxGiveUp(enum ExitCode error) |
|
82 |
|
{ |
|
83 |
|
ErrorF("ddxGiveUp\n"); |
|
84 |
|
} |
|
85 |
|
|
|
86 |
|
void |
|
87 |
|
AbortDDX(enum ExitCode error) |
|
88 |
|
{ |
|
89 |
|
ErrorF("AbortDDX\n"); |
|
90 |
|
ddxGiveUp(error); |
|
91 |
|
} |
|
92 |
|
|
|
93 |
|
void |
|
94 |
|
OsVendorFatalError(const char *f, va_list args) |
|
95 |
|
{ |
|
96 |
|
} |
|
97 |
|
|
|
98 |
|
void |
|
99 |
|
OsVendorInit(void) |
|
100 |
|
{ |
|
101 |
|
} |
|
102 |
|
|
|
103 |
|
static int |
|
104 |
|
event_filter(const struct dirent *dirent) |
|
105 |
|
{ |
|
106 |
|
/* yes, this is really basic */ |
|
107 |
|
if (strstr(dirent->d_name, "event")) |
|
108 |
|
return 1; |
|
109 |
|
return 0; |
|
110 |
|
} |
|
111 |
|
|
|
112 |
|
#define DEV_INPUT "/dev/input" |
|
113 |
|
static |
|
114 |
|
void event_add(struct dirent *dirent, long fs_name_sz_max) |
|
115 |
|
{ |
|
116 |
|
char *dev_path; |
|
117 |
|
Bool r; |
|
118 |
|
struct evdev *evdev; |
|
119 |
|
|
|
120 |
|
dev_path = xnfcalloc(1, strlen(DEV_INPUT) + strlen("/") + fs_name_sz_max |
|
121 |
|
+ strlen("\0")); |
|
122 |
|
strcpy(dev_path, DEV_INPUT); |
|
123 |
|
strcat(dev_path, "/"); |
|
124 |
|
strcat(dev_path, dirent->d_name); |
|
125 |
|
|
|
126 |
|
evdev = xnfcalloc(1, sizeof(*evdev)); |
|
127 |
|
evdev->dev_path = dev_path; |
|
128 |
|
evdev->xkb.rules = xnfstrdup("evdev"); |
|
129 |
|
evdev->xkb.model = xnfstrdup("tm2030USB"); |
|
130 |
|
evdev->xkb.layout = xnfstrdup("dvorak"); |
|
131 |
|
evdev->xkb.variant = NULL; |
|
132 |
|
evdev->xkb.options = xnfstrdup("compose:ralt"); |
|
133 |
|
|
|
134 |
|
ErrorF("adding %s\n", evdev->dev_path); |
|
135 |
|
r = evdev_init(evdev); |
|
136 |
|
if (!r) { |
|
137 |
|
ErrorF("unable to init %s\n", evdev->dev_path); |
|
138 |
|
if (evdev->xkb.options) |
|
139 |
|
free(evdev->xkb.options); |
|
140 |
|
if (evdev->xkb.variant) |
|
141 |
|
free(evdev->xkb.variant); |
|
142 |
|
if (evdev->xkb.layout) |
|
143 |
|
free(evdev->xkb.layout); |
|
144 |
|
if (evdev->xkb.model) |
|
145 |
|
free(evdev->xkb.model); |
|
146 |
|
free(evdev->xkb.rules); |
|
147 |
|
free(dev_path); |
|
148 |
|
free(evdev); |
|
149 |
|
} else |
|
150 |
|
xorg_list_add(&evdev->entry, &evdevs_head); |
|
151 |
|
free(dirent); |
|
152 |
|
} |
|
153 |
|
|
|
154 |
|
#define FS_NAME_SZ_MAX_DEFAULT 256 |
|
155 |
|
void |
|
156 |
|
InitInput(int argc, char *argv[]) |
|
157 |
|
{ |
|
158 |
|
struct dirent **dirents; |
|
159 |
|
int dirents_cnt; |
|
160 |
|
int dirents_idx; |
|
161 |
|
long fs_name_sz_max; |
|
162 |
|
|
|
163 |
|
/* |
|
164 |
|
* this is Machine Independent event queue for input device **internal** |
|
165 |
|
* event processing |
|
166 |
|
*/ |
|
167 |
|
mieqInit(); |
|
168 |
|
|
|
169 |
|
/* we open all evdev devices */ |
|
170 |
|
xorg_list_init(&evdevs_head); |
|
171 |
|
|
|
172 |
|
/*------------------------------------------------------------------------*/ |
|
173 |
|
errno = 0; |
|
174 |
|
fs_name_sz_max = pathconf(DEV_INPUT, _PC_NAME_MAX); |
|
175 |
|
if (fs_name_sz_max == -1) |
|
176 |
|
fs_name_sz_max = FS_NAME_SZ_MAX_DEFAULT; |
|
177 |
|
/*------------------------------------------------------------------------*/ |
|
178 |
|
|
|
179 |
|
/*------------------------------------------------------------------------*/ |
|
180 |
|
dirents_cnt = scandir(DEV_INPUT, &dirents, event_filter, NULL); |
|
181 |
|
|
|
182 |
|
if (dirents_cnt == -1) { |
|
183 |
|
ErrorF("unable to scan the dir " DEV_INPUT "\n"); |
|
184 |
|
return; |
|
185 |
|
} |
|
186 |
|
/*------------------------------------------------------------------------*/ |
|
187 |
|
|
|
188 |
|
dirents_idx = dirents_cnt; |
|
189 |
|
|
|
190 |
|
while (dirents_idx--) |
|
191 |
|
event_add(dirents[dirents_idx], fs_name_sz_max); |
|
192 |
|
|
|
193 |
|
free(dirents); |
|
194 |
|
return; |
|
195 |
|
} |
|
196 |
|
|
|
197 |
|
void |
|
198 |
|
CloseInput(void) |
|
199 |
|
{ |
|
200 |
|
/* evdev file descriptors cleanup everything properly at process shutdown */ |
|
201 |
|
|
|
202 |
|
/* TODO: cleanup input device OS resources */ |
|
203 |
|
mieqFini(); |
|
204 |
|
} |
|
205 |
|
|
|
206 |
|
void |
|
207 |
|
InitOutput(ScreenInfo *screen_info, int argc, char **argv) |
|
208 |
|
{ |
|
209 |
|
int depths[] = {1, 4, 8, 15, 16, 24, 32}; |
|
210 |
|
int bpp[] = {1, 8, 8, 16, 16, 32, 32}; |
|
211 |
|
u8 i; |
|
212 |
|
int r; |
|
213 |
|
|
|
214 |
|
(void)argc; |
|
215 |
|
(void)argv; |
|
216 |
|
|
|
217 |
|
for (i = 0; i < ARRAY_SIZE(depths); ++i) { |
|
218 |
|
screen_info->formats[i].depth = depths[i]; |
|
219 |
|
screen_info->formats[i].bitsPerPixel = bpp[i]; |
|
220 |
|
screen_info->formats[i].scanlinePad = BITMAP_SCANLINE_PAD; |
|
221 |
|
} |
|
222 |
|
|
|
223 |
|
screen_info->imageByteOrder = IMAGE_BYTE_ORDER; |
|
224 |
|
screen_info->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; |
|
225 |
|
screen_info->bitmapScanlinePad = BITMAP_SCANLINE_PAD; |
|
226 |
|
screen_info->bitmapBitOrder = BITMAP_BIT_ORDER; |
|
227 |
|
screen_info->numPixmapFormats = ARRAY_SIZE(depths); |
|
228 |
|
|
|
229 |
|
LoadExtensionList(xalga_extensions, ARRAY_SIZE(xalga_extensions), FALSE); |
|
230 |
|
|
|
231 |
|
/* XXX:strange, we add a screen whatever */ |
|
232 |
|
r = AddScreen(screen_init, argc, argv); |
|
233 |
|
if (r == -1) |
|
234 |
|
FatalError("couldn't add screen\n"); |
|
235 |
|
ErrorF("ddx InitOutput successful\n"); |
|
236 |
|
} |
|
237 |
|
/******************************************************************************/ |
File hw/xalga/evdev/axis/rel.c added (mode: 100644) (index 0000000..ab9adf2) |
|
1 |
|
/* |
|
2 |
|
* XALGA implementation |
|
3 |
|
* Copyright (C) 2014 Sylvain BERTRAND All Rights Reserved |
|
4 |
|
* Opens source legal protection provided by a GNU Lesser GPLv3 license |
|
5 |
|
*/ |
|
6 |
|
#include <stdint.h> |
|
7 |
|
#include <sys/ioctl.h> |
|
8 |
|
#include <linux/input.h> |
|
9 |
|
|
|
10 |
|
#include "dix-config.h" |
|
11 |
|
#include "inpututils.h" |
|
12 |
|
#include "input.h" |
|
13 |
|
#include "xserver-properties.h" |
|
14 |
|
#include "exevents.h" |
|
15 |
|
|
|
16 |
|
#include "xalga/namespace.h" |
|
17 |
|
#define XALGA_EVDEV_AXIS_REL_C |
|
18 |
|
#include "xalga/evdev/axis/rel.h" |
|
19 |
|
#include "xalga/evdev/evdev.h" |
|
20 |
|
|
|
21 |
|
#include "xalga/evdev/private.h" |
|
22 |
|
|
|
23 |
|
struct rel_axis_desc { |
|
24 |
|
long bit_idx; |
|
25 |
|
const char *dix_name; |
|
26 |
|
|
|
27 |
|
/* if we want a dix scrolling valuator for this axis */ |
|
28 |
|
u8 scroll_type; |
|
29 |
|
u8 scroll_flags; /* to select a prefered scroll valuator */ |
|
30 |
|
}; |
|
31 |
|
|
|
32 |
|
static struct rel_axis_desc rel_axes_desc[REL_CNT] = { |
|
33 |
|
{REL_X, AXIS_LABEL_PROP_REL_X,SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
34 |
|
{REL_Y, AXIS_LABEL_PROP_REL_Y, SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
35 |
|
{REL_Z, AXIS_LABEL_PROP_REL_Z, SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
36 |
|
{REL_RX, AXIS_LABEL_PROP_REL_RX, SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
37 |
|
{REL_RY, AXIS_LABEL_PROP_REL_RY, SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
38 |
|
{REL_RZ, AXIS_LABEL_PROP_REL_RZ, SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
39 |
|
{REL_HWHEEL, AXIS_LABEL_PROP_REL_HWHEEL, SCROLL_TYPE_HORIZONTAL, |
|
40 |
|
SCROLL_FLAG_NONE}, |
|
41 |
|
{REL_DIAL, AXIS_LABEL_PROP_REL_DIAL, SCROLL_TYPE_HORIZONTAL, |
|
42 |
|
SCROLL_FLAG_NONE}, |
|
43 |
|
{REL_WHEEL, AXIS_LABEL_PROP_REL_WHEEL, SCROLL_TYPE_VERTICAL, |
|
44 |
|
SCROLL_FLAG_PREFERRED}, |
|
45 |
|
{REL_MISC, AXIS_LABEL_PROP_REL_MISC, SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
46 |
|
{REL_MAX, "unknown axis label", SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
47 |
|
{REL_MAX, "unknown axis label", SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
48 |
|
{REL_MAX, "unknown axis label", SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
49 |
|
{REL_MAX, "unknown axis label", SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
50 |
|
{REL_MAX, "unknown axis label", SCROLL_TYPE_NONE, SCROLL_FLAG_NONE}, |
|
51 |
|
{REL_MAX, "unknown axis label", SCROLL_TYPE_NONE, SCROLL_FLAG_NONE} |
|
52 |
|
}; |
|
53 |
|
|
|
54 |
|
Bool |
|
55 |
|
rel_axes_codes_get(struct evdev *evdev) |
|
56 |
|
{ |
|
57 |
|
int r; |
|
58 |
|
|
|
59 |
|
r = ioctl(evdev->fd, EVIOCGBIT(EV_REL, sizeof(evdev->rel_codes)), |
|
60 |
|
evdev->rel_codes); |
|
61 |
|
if (r == -1) { |
|
62 |
|
ErrorF("unable to query the supported evdev rel codes\n"); |
|
63 |
|
return FALSE; |
|
64 |
|
} |
|
65 |
|
return TRUE; |
|
66 |
|
} |
|
67 |
|
|
|
68 |
|
/* here we stack all the relative axes supported by this evdev device */ |
|
69 |
|
void |
|
70 |
|
rel_axes_get(struct dix_init_data *init_data) |
|
71 |
|
{ |
|
72 |
|
struct evdev *evdev; |
|
73 |
|
Atom *labels; |
|
74 |
|
u8 *scroll_type; |
|
75 |
|
u8 *scroll_flags; |
|
76 |
|
u8 dix_rel_axis; |
|
77 |
|
u8 rel_axis; |
|
78 |
|
u8 supported_rel_axis; |
|
79 |
|
|
|
80 |
|
ErrorF("getting supported evdev rel axes...\n"); |
|
81 |
|
|
|
82 |
|
evdev = init_data->dix->public.devicePrivate; |
|
83 |
|
|
|
84 |
|
dix_rel_axis = init_data->dix_axes_cnt; /* first available dix axis index */ |
|
85 |
|
|
|
86 |
|
supported_rel_axis = 0; |
|
87 |
|
labels = &init_data->rel_axes.labels[0]; |
|
88 |
|
scroll_type = &init_data->rel_axes.scroll_type[0]; |
|
89 |
|
scroll_flags = &init_data->rel_axes.scroll_flags[0]; |
|
90 |
|
|
|
91 |
|
/* init the evdev -> dix mapping */ |
|
92 |
|
for (rel_axis = 0; rel_axis < REL_CNT; ++rel_axis) |
|
93 |
|
evdev->rel_axes_dix_map[rel_axis] = -1; |
|
94 |
|
|
|
95 |
|
for (rel_axis = 0; rel_axis < REL_CNT; ++rel_axis) |
|
96 |
|
if (IS_BIT_SET(evdev->rel_codes, rel_axes_desc[rel_axis].bit_idx)) { |
|
97 |
|
ErrorF("%s axis supported\n", rel_axes_desc[rel_axis].dix_name); |
|
98 |
|
|
|
99 |
|
labels[supported_rel_axis] = XIGetKnownProperty( |
|
100 |
|
rel_axes_desc[rel_axis].dix_name); |
|
101 |
|
scroll_type[supported_rel_axis] = |
|
102 |
|
rel_axes_desc[rel_axis].scroll_type; |
|
103 |
|
scroll_flags[supported_rel_axis] = |
|
104 |
|
rel_axes_desc[rel_axis].scroll_flags; |
|
105 |
|
|
|
106 |
|
evdev->rel_axes_dix_map[rel_axis] = dix_rel_axis; |
|
107 |
|
++supported_rel_axis; |
|
108 |
|
++dix_rel_axis; |
|
109 |
|
} |
|
110 |
|
|
|
111 |
|
init_data->rel_axes.cnt = supported_rel_axis; |
|
112 |
|
} |
|
113 |
|
|
|
114 |
|
void |
|
115 |
|
rel_axis_code_dispatch(DeviceIntPtr dix, struct input_event *e) |
|
116 |
|
{ |
|
117 |
|
struct evdev *evdev; |
|
118 |
|
int dix_axis; |
|
119 |
|
ValuatorMask mask; |
|
120 |
|
|
|
121 |
|
valuator_mask_zero(&mask); |
|
122 |
|
|
|
123 |
|
evdev = dix->public.devicePrivate; |
|
124 |
|
dix_axis = evdev->rel_axes_dix_map[e->code]; |
|
125 |
|
|
|
126 |
|
if (dix_axis != -1) {/* only if that evdev axis is mapped */ |
|
127 |
|
valuator_mask_set(&mask, dix_axis, (int)e->value); |
|
128 |
|
QueuePointerEvents(dix, MotionNotify, 0, 0, &mask); |
|
129 |
|
} |
|
130 |
|
} |
|
131 |
|
|
|
132 |
|
static void |
|
133 |
|
feedback_ctl(DeviceIntPtr device, PtrCtrl *ctrl) |
|
134 |
|
{ |
|
135 |
|
/* Nothing to do, dix handles all settings */ |
|
136 |
|
} |
|
137 |
|
|
|
138 |
|
Bool |
|
139 |
|
dix_rel_axes_register(struct dix_init_data *init_data) |
|
140 |
|
{ |
|
141 |
|
Bool r; |
|
142 |
|
u8 axis; |
|
143 |
|
|
|
144 |
|
if (!init_data->rel_axes.cnt) { |
|
145 |
|
ErrorF("no evdev rel axes to register in dix\n"); |
|
146 |
|
return TRUE; |
|
147 |
|
} |
|
148 |
|
|
|
149 |
|
ErrorF("registering %u relative axes in dix...\n", init_data->rel_axes.cnt); |
|
150 |
|
|
|
151 |
|
/* |
|
152 |
|
* XXX: this is really ugly. For an dix input device valuators of all axes |
|
153 |
|
* should be allocated with this function, absolute or relative |
|
154 |
|
* with/without a proximity class (which get allocated *only* here with |
|
155 |
|
* the OutOfProximity mode flag. Since, it's exclusive, a dix input device |
|
156 |
|
* should be created for each type of valuator an evdev device has. |
|
157 |
|
* You can "overwrite" the relative/absolute mode by re-configuring each |
|
158 |
|
* axis with the following InitValuatorAxisStruct. |
|
159 |
|
*/ |
|
160 |
|
r = InitValuatorClassDeviceStruct(init_data->dix, init_data->rel_axes.cnt, |
|
161 |
|
&init_data->rel_axes.labels[0], GetMotionHistorySize(), Relative); |
|
162 |
|
if (!r) { |
|
163 |
|
ErrorF("unable to alloc the valuator class device struct for relative axes\n"); |
|
164 |
|
return FALSE; |
|
165 |
|
} |
|
166 |
|
|
|
167 |
|
r = InitPtrFeedbackClassDeviceStruct(init_data->dix, feedback_ctl); |
|
168 |
|
if (!r) { |
|
169 |
|
ErrorF("unable to init the pointer feedback class device struct for relative axes\n"); |
|
170 |
|
return FALSE; |
|
171 |
|
} |
|
172 |
|
|
|
173 |
|
for (axis = 0; axis < init_data->rel_axes.cnt; ++axis) { |
|
174 |
|
double delta; |
|
175 |
|
const char *type; |
|
176 |
|
const char *flags; |
|
177 |
|
|
|
178 |
|
r = InitValuatorAxisStruct(init_data->dix, axis, |
|
179 |
|
init_data->rel_axes.labels[axis], NO_AXIS_LIMITS, |
|
180 |
|
NO_AXIS_LIMITS, 1, 0, 1, Relative); |
|
181 |
|
if (!r) { |
|
182 |
|
ErrorF("unable to configure resolution/min/max for axis %u\n", axis); |
|
183 |
|
return FALSE; |
|
184 |
|
} |
|
185 |
|
|
|
186 |
|
if (init_data->rel_axes.scroll_type[axis] == SCROLL_TYPE_NONE) |
|
187 |
|
continue; |
|
188 |
|
|
|
189 |
|
if (init_data->rel_axes.scroll_type[axis] == SCROLL_TYPE_VERTICAL) |
|
190 |
|
delta = -1.0; |
|
191 |
|
else |
|
192 |
|
delta = 1.0; |
|
193 |
|
|
|
194 |
|
/*--------------------------------------------------------------------*/ |
|
195 |
|
if (init_data->rel_axes.scroll_type[axis] == SCROLL_TYPE_VERTICAL) |
|
196 |
|
type = "vertical"; |
|
197 |
|
else |
|
198 |
|
type = "horizontal"; |
|
199 |
|
|
|
200 |
|
if (init_data->rel_axes.scroll_flags[axis] == SCROLL_FLAG_PREFERRED) |
|
201 |
|
flags = " prefered"; |
|
202 |
|
else |
|
203 |
|
flags = ""; |
|
204 |
|
|
|
205 |
|
ErrorF("registering%s %s scroll valuator on axis %u with a delta of %f\n", |
|
206 |
|
flags, type, axis, delta); |
|
207 |
|
/*--------------------------------------------------------------------*/ |
|
208 |
|
|
|
209 |
|
/* |
|
210 |
|
* XXX: carefull, there is only one valuator created per axis. The |
|
211 |
|
* "scroll valuator" is actually an extra/extension input class to the |
|
212 |
|
* the valuator axis class. Yes, this is actually really awkward. |
|
213 |
|
* Hopefully the original writters did not use syntax rich/object |
|
214 |
|
* oriented language which would have given us a massive object |
|
215 |
|
* orientish kludge. |
|
216 |
|
*/ |
|
217 |
|
r = SetScrollValuator(init_data->dix, axis, |
|
218 |
|
init_data->rel_axes.scroll_type[axis], delta, |
|
219 |
|
init_data->rel_axes.scroll_flags[axis]); |
|
220 |
|
if (!r) { |
|
221 |
|
ErrorF("unable to register scroll valuator for axis %u\n", axis); |
|
222 |
|
return FALSE; |
|
223 |
|
} |
|
224 |
|
} |
|
225 |
|
return TRUE; |
|
226 |
|
} |
File hw/xalga/evdev/evdev.c added (mode: 100644) (index 0000000..7e773e8) |
|
1 |
|
/* |
|
2 |
|
* XALGA implementation |
|
3 |
|
* Copyright (C) 2014 Sylvain BERTRAND All Rights Reserved |
|
4 |
|
* Opens source legal protection provided by a GNU Lesser GPLv3 license |
|
5 |
|
*/ |
|
6 |
|
#include <unistd.h> |
|
7 |
|
#include <sys/ioctl.h> |
|
8 |
|
#include <fcntl.h> |
|
9 |
|
#include <libgen.h> |
|
10 |
|
#include <linux/input.h> |
|
11 |
|
|
|
12 |
|
|
|
13 |
|
#include "dix-config.h" |
|
14 |
|
#include "input.h" |
|
15 |
|
#include "exevents.h" |
|
16 |
|
#include "xserver-properties.h" |
|
17 |
|
#include "extinit.h" |
|
18 |
|
|
|
19 |
|
#include "xalga/namespace.h" |
|
20 |
|
#include "xalga/evdev/axis/rel.h" |
|
21 |
|
#define XALGA_EVDEV_EVDEV_C |
|
22 |
|
#include "xalga/evdev/evdev.h" |
|
23 |
|
#include "xalga/evdev/private.h" |
|
24 |
|
#include "xalga/evdev/input-event.h" |
|
25 |
|
#include "xalga/evdev/key/key.h" |
|
26 |
|
#include "xalga/evdev/key/key-key.h" |
|
27 |
|
#include "xalga/evdev/key/key-btn.h" |
|
28 |
|
|
|
29 |
|
|
|
30 |
|
/*----------------------------------------------------------------------------*/ |
|
31 |
|
static Bool event_types_get(struct evdev *evdev); |
|
32 |
|
static Bool init_data_collect(struct dix_init_data *init_data); |
|
33 |
|
/*----------------------------------------------------------------------------*/ |
|
34 |
|
|
|
35 |
|
|
|
36 |
|
/*----------------------------------------------------------------------------*/ |
|
37 |
|
static Bool dix_register(struct dix_init_data *init_data); |
|
38 |
|
|
|
39 |
|
static int dix_proc(DeviceIntPtr dix, int what); |
|
40 |
|
static int dix_init(DeviceIntPtr dix); |
|
41 |
|
static int dix_on(DeviceIntPtr dix); |
|
42 |
|
static void dix_off(DeviceIntPtr dix); |
|
43 |
|
/*----------------------------------------------------------------------------*/ |
|
44 |
|
|
|
45 |
|
|
|
46 |
|
static int |
|
47 |
|
dix_proc(DeviceIntPtr dix, int what) |
|
48 |
|
{ |
|
49 |
|
int r; |
|
50 |
|
struct evdev *evdev; |
|
51 |
|
|
|
52 |
|
r = BadMatch; |
|
53 |
|
|
|
54 |
|
switch (what) { |
|
55 |
|
case DEVICE_INIT: |
|
56 |
|
r = dix_init(dix); |
|
57 |
|
break; |
|
58 |
|
case DEVICE_ON: |
|
59 |
|
r = dix_on(dix); |
|
60 |
|
break; |
|
61 |
|
case DEVICE_OFF: |
|
62 |
|
dix_off(dix); |
|
63 |
|
r = Success; |
|
64 |
|
break; |
|
65 |
|
case DEVICE_CLOSE: |
|
66 |
|
ErrorF("closing input device...\n"); |
|
67 |
|
if (dix->public.on) { |
|
68 |
|
ErrorF("the input device is closed before being turned off, turning off now\n"); |
|
69 |
|
dix_off(dix); |
|
70 |
|
} |
|
71 |
|
/* |
|
72 |
|
* XXX: for the moment, only happening at server shutdown then, just |
|
73 |
|
* do basic cleanup (even if it's useless) |
|
74 |
|
*/ |
|
75 |
|
evdev = dix->public.devicePrivate; |
|
76 |
|
if (evdev->xkb.options) |
|
77 |
|
free(evdev->xkb.options); |
|
78 |
|
if (evdev->xkb.variant) |
|
79 |
|
free(evdev->xkb.variant); |
|
80 |
|
if (evdev->xkb.layout) |
|
81 |
|
free(evdev->xkb.layout); |
|
82 |
|
if (evdev->xkb.model) |
|
83 |
|
free(evdev->xkb.model); |
|
84 |
|
free(evdev->xkb.rules); |
|
85 |
|
free(evdev->dev_path); |
|
86 |
|
close(evdev->fd); |
|
87 |
|
xorg_list_del(&evdev->entry); |
|
88 |
|
free(evdev); |
|
89 |
|
break; |
|
90 |
|
} |
|
91 |
|
return r; |
|
92 |
|
} |
|
93 |
|
|
|
94 |
|
static Bool |
|
95 |
|
event_types_get(struct evdev *evdev) |
|
96 |
|
{ |
|
97 |
|
int r; |
|
98 |
|
|
|
99 |
|
r = ioctl(evdev->fd, EVIOCGBIT(0, sizeof(evdev->event_types)), |
|
100 |
|
evdev->event_types); |
|
101 |
|
if (r == -1) { |
|
102 |
|
ErrorF("unable to query the supported evdev event types\n"); |
|
103 |
|
return FALSE; |
|
104 |
|
} |
|
105 |
|
return TRUE; |
|
106 |
|
} |
|
107 |
|
|
|
108 |
|
static Bool |
|
109 |
|
init_data_collect(struct dix_init_data *init_data) |
|
110 |
|
{ |
|
111 |
|
struct evdev *evdev; |
|
112 |
|
Bool r; |
|
113 |
|
|
|
114 |
|
evdev = init_data->dix->public.devicePrivate; |
|
115 |
|
|
|
116 |
|
if (IS_BIT_SET(evdev->event_types, EV_REL)) { |
|
117 |
|
ErrorF("evdev rel events supported\n"); |
|
118 |
|
|
|
119 |
|
r = rel_axes_codes_get(evdev); |
|
120 |
|
if (!r) |
|
121 |
|
return FALSE; |
|
122 |
|
|
|
123 |
|
rel_axes_get(init_data); |
|
124 |
|
} |
|
125 |
|
|
|
126 |
|
/* XXX: I don't support ABS axes yet */ |
|
127 |
|
|
|
128 |
|
if (IS_BIT_SET(evdev->event_types, EV_KEY)) { |
|
129 |
|
ErrorF("evdev key events supported\n"); |
|
130 |
|
|
|
131 |
|
r = key_codes_get(evdev); |
|
132 |
|
if (!r) |
|
133 |
|
return FALSE; |
|
134 |
|
|
|
135 |
|
key_btns_get(init_data); |
|
136 |
|
key_keys_get(init_data); |
|
137 |
|
} |
|
138 |
|
return TRUE; |
|
139 |
|
} |
|
140 |
|
|
|
141 |
|
static Bool |
|
142 |
|
dix_register(struct dix_init_data *init_data) |
|
143 |
|
{ |
|
144 |
|
Bool r; |
|
145 |
|
|
|
146 |
|
r = dix_keys_register(init_data); |
|
147 |
|
if (!r) |
|
148 |
|
return FALSE; |
|
149 |
|
|
|
150 |
|
r = dix_btns_register(init_data); |
|
151 |
|
if (!r) |
|
152 |
|
return FALSE; |
|
153 |
|
|
|
154 |
|
r = dix_rel_axes_register(init_data); |
|
155 |
|
if (!r) |
|
156 |
|
return FALSE; |
|
157 |
|
return TRUE; |
|
158 |
|
} |
|
159 |
|
|
|
160 |
|
static int |
|
161 |
|
dix_init(DeviceIntPtr dix) |
|
162 |
|
{ |
|
163 |
|
struct evdev *evdev; |
|
164 |
|
Bool r; |
|
165 |
|
struct dix_init_data dix_init_data; |
|
166 |
|
|
|
167 |
|
evdev = dix->public.devicePrivate; |
|
168 |
|
|
|
169 |
|
ErrorF("initing dix device for evdev %s...\n", evdev->dev_path); |
|
170 |
|
|
|
171 |
|
evdev->fd = open(evdev->dev_path, O_RDWR | O_NONBLOCK); |
|
172 |
|
if (evdev->fd == -1) { |
|
173 |
|
ErrorF("unable to open the evdev file descriptor\n"); |
|
174 |
|
return BadValue; |
|
175 |
|
} |
|
176 |
|
|
|
177 |
|
r = event_types_get(evdev); |
|
178 |
|
if (!r) |
|
179 |
|
goto err_close_evdev_fd; |
|
180 |
|
|
|
181 |
|
memset(&dix_init_data, 0, sizeof(dix_init_data)); |
|
182 |
|
dix_init_data.dix = dix; |
|
183 |
|
|
|
184 |
|
r = init_data_collect(&dix_init_data); |
|
185 |
|
if (!r) |
|
186 |
|
goto err_close_evdev_fd; |
|
187 |
|
|
|
188 |
|
r = dix_register(&dix_init_data); |
|
189 |
|
if (!r) |
|
190 |
|
goto err_close_evdev_fd; |
|
191 |
|
|
|
192 |
|
return Success; |
|
193 |
|
|
|
194 |
|
err_close_evdev_fd: |
|
195 |
|
close(evdev->fd); |
|
196 |
|
return BadValue; |
|
197 |
|
} |
|
198 |
|
|
|
199 |
|
/* |
|
200 |
|
* This is called after the dix waitforsomething select. The err parameter |
|
201 |
|
* contain the return value from the select (error or not), or a dix |
|
202 |
|
* specific error. The read_mask is the FD_SET of file descriptors available |
|
203 |
|
* for reading. |
|
204 |
|
*/ |
|
205 |
|
static void |
|
206 |
|
wakeup_handler(void *data, int err, void *read_mask) |
|
207 |
|
{ |
|
208 |
|
DeviceIntPtr dix; |
|
209 |
|
struct evdev *evdev; |
|
210 |
|
|
|
211 |
|
/* the dix waitforsomething select is in error or the dix */ |
|
212 |
|
if (err < 0) |
|
213 |
|
return; |
|
214 |
|
|
|
215 |
|
dix = data; |
|
216 |
|
evdev = dix->public.devicePrivate; |
|
217 |
|
|
|
218 |
|
if (FD_ISSET(evdev->fd, (fd_set*)read_mask)) |
|
219 |
|
read_buf_processing(dix); |
|
220 |
|
} |
|
221 |
|
|
|
222 |
|
static int |
|
223 |
|
dix_on(DeviceIntPtr dix) |
|
224 |
|
{ |
|
225 |
|
struct evdev *evdev; |
|
226 |
|
Bool r; |
|
227 |
|
|
|
228 |
|
evdev = dix->public.devicePrivate; |
|
229 |
|
|
|
230 |
|
ErrorF("switching on evdev device %s...\n", evdev->dev_path); |
|
231 |
|
|
|
232 |
|
evdev->read_buf = read_buf_alloc(); |
|
233 |
|
if (!evdev->read_buf) |
|
234 |
|
return BadValue; |
|
235 |
|
|
|
236 |
|
/* |
|
237 |
|
* The block handler is called before the dix waitforsomething select. |
|
238 |
|
* The wakeup handler is called after the dix waitforsomething select |
|
239 |
|
* with the result of the select in err parameter. |
|
240 |
|
* We don't have a block handler here. |
|
241 |
|
*/ |
|
242 |
|
r = RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, |
|
243 |
|
wakeup_handler, dix); |
|
244 |
|
if (!r) { |
|
245 |
|
ErrorF("unable to add pointer wakeup handler\n"); |
|
246 |
|
goto err_free_read_buf; |
|
247 |
|
} |
|
248 |
|
|
|
249 |
|
/* |
|
250 |
|
* this will add the file descriptor to the dix |
|
251 |
|
* dispatch/waitforsomething core loop. Do not mixup that API with the |
|
252 |
|
* API from AddInputDevice which is at other level. |
|
253 |
|
* Reading from this file destriptor will be done in the "wakeup handler". |
|
254 |
|
*/ |
|
255 |
|
AddEnabledDevice(evdev->fd); |
|
256 |
|
|
|
257 |
|
evdev->overrun = FALSE; |
|
258 |
|
dix->public.on = TRUE; |
|
259 |
|
return Success; |
|
260 |
|
|
|
261 |
|
err_free_read_buf: |
|
262 |
|
free(evdev->read_buf); |
|
263 |
|
return BadValue; |
|
264 |
|
} |
|
265 |
|
|
|
266 |
|
static void |
|
267 |
|
dix_off(DeviceIntPtr dix) |
|
268 |
|
{ |
|
269 |
|
struct evdev *evdev; |
|
270 |
|
|
|
271 |
|
evdev = dix->public.devicePrivate; |
|
272 |
|
|
|
273 |
|
ErrorF("switching off evdev device %s...\n", evdev->dev_path); |
|
274 |
|
|
|
275 |
|
RemoveEnabledDevice(evdev->fd); |
|
276 |
|
|
|
277 |
|
RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, wakeup_handler, |
|
278 |
|
dix); |
|
279 |
|
|
|
280 |
|
free(evdev->read_buf); |
|
281 |
|
dix->public.on = FALSE; |
|
282 |
|
} |
|
283 |
|
|
|
284 |
|
/*----------------------------------------------------------------------------*/ |
|
285 |
|
#define EVDEV_ATOM_TYPE_NAME "evdev" |
|
286 |
|
#define FS_NAME_SZ_MAX_DEFAULT 256 |
|
287 |
|
Bool |
|
288 |
|
evdev_init(struct evdev *evdev) |
|
289 |
|
{ |
|
290 |
|
static Atom type_atom = None; |
|
291 |
|
int r; |
|
292 |
|
long fs_name_sz_max; /* fs stands for filesystem */ |
|
293 |
|
char *atom_name; |
|
294 |
|
ul atom_name_sz; |
|
295 |
|
char *dev_path_dup; |
|
296 |
|
char *dev_path_basename; |
|
297 |
|
|
|
298 |
|
/* evdev->dev_path is usually something like /dev/input/event16 */ |
|
299 |
|
fs_name_sz_max = pathconf(evdev->dev_path, _PC_NAME_MAX); |
|
300 |
|
if (fs_name_sz_max == -1) |
|
301 |
|
fs_name_sz_max = FS_NAME_SZ_MAX_DEFAULT; |
|
302 |
|
|
|
303 |
|
dev_path_dup = xnfstrdup(evdev->dev_path); |
|
304 |
|
dev_path_basename = basename(dev_path_dup); /* POSIX and not GNU behavior */ |
|
305 |
|
|
|
306 |
|
atom_name_sz = sizeof(EVDEV_ATOM_TYPE_NAME "-") + strlen(dev_path_basename); |
|
307 |
|
atom_name = xnfalloc(atom_name_sz); |
|
308 |
|
snprintf(atom_name, atom_name_sz, "%s-%s", EVDEV_ATOM_TYPE_NAME, |
|
309 |
|
dev_path_basename); |
|
310 |
|
free(dev_path_dup); |
|
311 |
|
|
|
312 |
|
/* |
|
313 |
|
* XXX: due to the weird and ugly dix api method |
|
314 |
|
* "InitValuatorClassDeviceStruct", an evdev device should be split in |
|
315 |
|
* several dix input devices for relative, absolute with/without proximity. |
|
316 |
|
* axis support. |
|
317 |
|
*/ |
|
318 |
|
evdev->dix = AddInputDevice(serverClient, dix_proc, TRUE); |
|
319 |
|
if (!evdev->dix) { |
|
320 |
|
ErrorF("unable to add the evdev device to dix input subsystem\n"); |
|
321 |
|
return FALSE; |
|
322 |
|
} |
|
323 |
|
evdev->dix->public.devicePrivate = evdev; |
|
324 |
|
|
|
325 |
|
/* the type atom is made only once, then static */ |
|
326 |
|
if (type_atom == None) { |
|
327 |
|
type_atom = MakeAtom(EVDEV_ATOM_TYPE_NAME, |
|
328 |
|
sizeof(EVDEV_ATOM_TYPE_NAME) - 1, TRUE); |
|
329 |
|
if(type_atom == BAD_RESOURCE) { |
|
330 |
|
ErrorF("unable to make a type atom for evdev\n"); |
|
331 |
|
goto err_remove_device; |
|
332 |
|
} |
|
333 |
|
} |
|
334 |
|
AssignTypeAndName(evdev->dix, type_atom, atom_name); |
|
335 |
|
evdev->dix->type = SLAVE; |
|
336 |
|
evdev->dix->spriteInfo->spriteOwner = FALSE; |
|
337 |
|
return TRUE; |
|
338 |
|
|
|
339 |
|
err_remove_device: |
|
340 |
|
r = RemoveDevice(evdev->dix, TRUE); |
|
341 |
|
if (r != Success) |
|
342 |
|
ErrorF("something went wrong while removing the dix device\n"); |
|
343 |
|
return FALSE; |
|
344 |
|
} |
|
345 |
|
/*----------------------------------------------------------------------------*/ |
File hw/xalga/evdev/key/key-btn.c added (mode: 100644) (index 0000000..0d5ae46) |
|
1 |
|
/* |
|
2 |
|
* XALGA implementation |
|
3 |
|
* Copyright (C) 2014 Sylvain BERTRAND All Rights Reserved |
|
4 |
|
* Opens source legal protection provided by a GNU Lesser GPLv3 license |
|
5 |
|
*/ |
|
6 |
|
#include <linux/input.h> |
|
7 |
|
|
|
8 |
|
#include "dix-config.h" |
|
9 |
|
#include "input.h" |
|
10 |
|
#include "xserver-properties.h" |
|
11 |
|
#include "exevents.h" |
|
12 |
|
|
|
13 |
|
#include "xalga/namespace.h" |
|
14 |
|
#include "xalga/evdev/axis/rel.h" |
|
15 |
|
#include "xalga/evdev/evdev.h" |
|
16 |
|
#include "xalga/evdev/private.h" |
|
17 |
|
|
|
18 |
|
struct btn { |
|
19 |
|
long evdev_bit; |
|
20 |
|
int dix; |
|
21 |
|
const char *name; |
|
22 |
|
}; |
|
23 |
|
|
|
24 |
|
/*----------------------------------------------------------------------------*/ |
|
25 |
|
static void btns_section_map(struct dix_init_data *init_data, |
|
26 |
|
struct btn *evdev_section, long evdev_section_btns_n, |
|
27 |
|
int *dix_map, u16 evdev_mask); |
|
28 |
|
|
|
29 |
|
/* public */ |
|
30 |
|
void key_btns_get(struct dix_init_data *init_data); |
|
31 |
|
Bool dix_btns_register(struct dix_init_data *init_data); |
|
32 |
|
|
|
33 |
|
/* private to evdev/key */ |
|
34 |
|
void btn_process(DeviceIntPtr dix, struct input_event *e, u16 btn_section_mask); |
|
35 |
|
u16 btn_section_mask_get(u16 code); |
|
36 |
|
/*----------------------------------------------------------------------------*/ |
|
37 |
|
|
|
38 |
|
|
|
39 |
|
/*----------------------------------------------------------------------------*/ |
|
40 |
|
/* follow the dix button mapping found in xorg ddx evdev driver */ |
|
41 |
|
static struct btn btns_section_misc[] = { |
|
42 |
|
{BTN_0, 1, BTN_LABEL_PROP_BTN_0}, |
|
43 |
|
{BTN_1, 2, BTN_LABEL_PROP_BTN_1}, |
|
44 |
|
{BTN_2, 3, BTN_LABEL_PROP_BTN_2}, |
|
45 |
|
{BTN_3, 8, BTN_LABEL_PROP_BTN_3}, |
|
46 |
|
{BTN_4, 9, BTN_LABEL_PROP_BTN_4}, |
|
47 |
|
{BTN_5, 10, BTN_LABEL_PROP_BTN_5}, |
|
48 |
|
{BTN_6, 11, BTN_LABEL_PROP_BTN_6}, |
|
49 |
|
{BTN_7, 12, BTN_LABEL_PROP_BTN_7}, |
|
50 |
|
{BTN_8, 13, BTN_LABEL_PROP_BTN_8}, |
|
51 |
|
{BTN_9, 14, BTN_LABEL_PROP_BTN_9} |
|
52 |
|
}; |
|
53 |
|
|
|
54 |
|
static struct btn btns_section_mouse[] = { |
|
55 |
|
{BTN_LEFT, 1, BTN_LABEL_PROP_BTN_LEFT}, |
|
56 |
|
{BTN_RIGHT, 3, BTN_LABEL_PROP_BTN_RIGHT}, |
|
57 |
|
{BTN_MIDDLE, 2, BTN_LABEL_PROP_BTN_MIDDLE}, |
|
58 |
|
{BTN_SIDE, 8, BTN_LABEL_PROP_BTN_SIDE}, |
|
59 |
|
{BTN_EXTRA, 9, BTN_LABEL_PROP_BTN_EXTRA}, |
|
60 |
|
{BTN_FORWARD, 10, BTN_LABEL_PROP_BTN_FORWARD}, |
|
61 |
|
{BTN_BACK, 11, BTN_LABEL_PROP_BTN_BACK}, |
|
62 |
|
{BTN_TASK, 12, BTN_LABEL_PROP_BTN_TASK} |
|
63 |
|
}; |
|
64 |
|
|
|
65 |
|
static struct btn btns_section_joystick[] = { |
|
66 |
|
{BTN_TRIGGER, 0, BTN_LABEL_PROP_BTN_TRIGGER}, |
|
67 |
|
{BTN_THUMB, 0, BTN_LABEL_PROP_BTN_THUMB}, |
|
68 |
|
{BTN_THUMB2, 0, BTN_LABEL_PROP_BTN_THUMB2}, |
|
69 |
|
{BTN_TOP, 0, BTN_LABEL_PROP_BTN_TOP}, |
|
70 |
|
{BTN_TOP2, 0, BTN_LABEL_PROP_BTN_TOP2}, |
|
71 |
|
{BTN_PINKIE, 0, BTN_LABEL_PROP_BTN_PINKIE}, |
|
72 |
|
{BTN_BASE, 0, BTN_LABEL_PROP_BTN_BASE}, |
|
73 |
|
{BTN_BASE2, 0, BTN_LABEL_PROP_BTN_BASE2}, |
|
74 |
|
{BTN_BASE3, 0, BTN_LABEL_PROP_BTN_BASE3}, |
|
75 |
|
{BTN_BASE4, 0, BTN_LABEL_PROP_BTN_BASE4}, |
|
76 |
|
{BTN_BASE5, 0, BTN_LABEL_PROP_BTN_BASE5}, |
|
77 |
|
{BTN_BASE6, 0, BTN_LABEL_PROP_BTN_BASE6}, |
|
78 |
|
{BTN_DEAD, 0, BTN_LABEL_PROP_BTN_DEAD} |
|
79 |
|
}; |
|
80 |
|
|
|
81 |
|
static struct btn btns_section_gamepad[] = { |
|
82 |
|
{BTN_A, 0, BTN_LABEL_PROP_BTN_A}, |
|
83 |
|
{BTN_B, 0, BTN_LABEL_PROP_BTN_B}, |
|
84 |
|
{BTN_C, 0, BTN_LABEL_PROP_BTN_C}, |
|
85 |
|
{BTN_X, 0, BTN_LABEL_PROP_BTN_X}, |
|
86 |
|
{BTN_Y, 0, BTN_LABEL_PROP_BTN_Y}, |
|
87 |
|
{BTN_Z, 0, BTN_LABEL_PROP_BTN_Z}, |
|
88 |
|
{BTN_TL, 0, BTN_LABEL_PROP_BTN_TL}, |
|
89 |
|
{BTN_TR, 0, BTN_LABEL_PROP_BTN_TR}, |
|
90 |
|
{BTN_TL2, 0, BTN_LABEL_PROP_BTN_TL2}, |
|
91 |
|
{BTN_TR2, 0, BTN_LABEL_PROP_BTN_TR2}, |
|
92 |
|
{BTN_SELECT, 0, BTN_LABEL_PROP_BTN_SELECT}, |
|
93 |
|
{BTN_START, 0, BTN_LABEL_PROP_BTN_START}, |
|
94 |
|
{BTN_MODE, 0, BTN_LABEL_PROP_BTN_MODE}, |
|
95 |
|
{BTN_THUMBL, 0, BTN_LABEL_PROP_BTN_THUMBL}, |
|
96 |
|
{BTN_THUMBR, 0, BTN_LABEL_PROP_BTN_THUMBR} |
|
97 |
|
}; |
|
98 |
|
|
|
99 |
|
static struct btn btns_section_digi[] = { |
|
100 |
|
{BTN_TOOL_PEN, 0, BTN_LABEL_PROP_BTN_TOOL_PEN}, |
|
101 |
|
{BTN_TOOL_RUBBER, 0, BTN_LABEL_PROP_BTN_TOOL_RUBBER}, |
|
102 |
|
{BTN_TOOL_BRUSH, 0, BTN_LABEL_PROP_BTN_TOOL_BRUSH}, |
|
103 |
|
{BTN_TOOL_PENCIL, 0, BTN_LABEL_PROP_BTN_TOOL_PENCIL}, |
|
104 |
|
{BTN_TOOL_AIRBRUSH, 0, BTN_LABEL_PROP_BTN_TOOL_AIRBRUSH}, |
|
105 |
|
{BTN_TOOL_FINGER, 0, BTN_LABEL_PROP_BTN_TOOL_FINGER}, |
|
106 |
|
{BTN_TOOL_MOUSE, 0, BTN_LABEL_PROP_BTN_TOOL_MOUSE}, |
|
107 |
|
{BTN_TOOL_LENS, 0, BTN_LABEL_PROP_BTN_TOOL_LENS}, |
|
108 |
|
{BTN_TOOL_QUINTTAP, 0, "Button Tool Quinttap"}, |
|
109 |
|
{BTN_TOUCH, 1, BTN_LABEL_PROP_BTN_TOUCH}, |
|
110 |
|
{BTN_STYLUS, 2, BTN_LABEL_PROP_BTN_STYLUS}, |
|
111 |
|
{BTN_STYLUS2, 3, BTN_LABEL_PROP_BTN_STYLUS2}, |
|
112 |
|
{BTN_TOOL_DOUBLETAP, 0, BTN_LABEL_PROP_BTN_TOOL_DOUBLETAP}, |
|
113 |
|
{BTN_TOOL_TRIPLETAP, 0, BTN_LABEL_PROP_BTN_TOOL_TRIPLETAP}, |
|
114 |
|
{BTN_TOOL_QUADTAP, 0, "Button Tool Quadtap"} |
|
115 |
|
}; |
|
116 |
|
|
|
117 |
|
static struct btn btns_section_wheel[] = { |
|
118 |
|
{BTN_GEAR_DOWN, 0, BTN_LABEL_PROP_BTN_GEAR_DOWN}, |
|
119 |
|
{BTN_GEAR_UP, 0, BTN_LABEL_PROP_BTN_GEAR_UP} |
|
120 |
|
}; |
|
121 |
|
|
|
122 |
|
static struct btn btns_section_dpad[] = { |
|
123 |
|
{BTN_DPAD_UP, 0, "Button Dpad Up"}, |
|
124 |
|
{BTN_DPAD_DOWN, 0, "Button Dpad Down"}, |
|
125 |
|
{BTN_DPAD_LEFT, 0, "Button Dpad Left"}, |
|
126 |
|
{BTN_DPAD_RIGHT, 0, "Button Dpad Right"} |
|
127 |
|
}; |
|
128 |
|
|
|
129 |
|
static struct btn btns_section_trigger_happy[] = { |
|
130 |
|
{BTN_TRIGGER_HAPPY1, 0, "Button Trigger Happy 1"}, |
|
131 |
|
{BTN_TRIGGER_HAPPY2, 0, "Button Trigger Happy 2"}, |
|
132 |
|
{BTN_TRIGGER_HAPPY3, 0, "Button Trigger Happy 3"}, |
|
133 |
|
{BTN_TRIGGER_HAPPY4, 0, "Button Trigger Happy 4"}, |
|
134 |
|
{BTN_TRIGGER_HAPPY5, 0, "Button Trigger Happy 5"}, |
|
135 |
|
{BTN_TRIGGER_HAPPY6, 0, "Button Trigger Happy 6"}, |
|
136 |
|
{BTN_TRIGGER_HAPPY7, 0, "Button Trigger Happy 7"}, |
|
137 |
|
{BTN_TRIGGER_HAPPY8, 0, "Button Trigger Happy 8"}, |
|
138 |
|
{BTN_TRIGGER_HAPPY9, 0, "Button Trigger Happy 9"}, |
|
139 |
|
{BTN_TRIGGER_HAPPY10, 0, "Button Trigger Happy 10"}, |
|
140 |
|
{BTN_TRIGGER_HAPPY11, 0, "Button Trigger Happy 11"}, |
|
141 |
|
{BTN_TRIGGER_HAPPY12, 0, "Button Trigger Happy 12"}, |
|
142 |
|
{BTN_TRIGGER_HAPPY13, 0, "Button Trigger Happy 13"}, |
|
143 |
|
{BTN_TRIGGER_HAPPY14, 0, "Button Trigger Happy 14"}, |
|
144 |
|
{BTN_TRIGGER_HAPPY15, 0, "Button Trigger Happy 15"}, |
|
145 |
|
{BTN_TRIGGER_HAPPY16, 0, "Button Trigger Happy 16"}, |
|
146 |
|
{BTN_TRIGGER_HAPPY17, 0, "Button Trigger Happy 17"}, |
|
147 |
|
{BTN_TRIGGER_HAPPY18, 0, "Button Trigger Happy 18"}, |
|
148 |
|
{BTN_TRIGGER_HAPPY19, 0, "Button Trigger Happy 19"}, |
|
149 |
|
{BTN_TRIGGER_HAPPY20, 0, "Button Trigger Happy 20"}, |
|
150 |
|
{BTN_TRIGGER_HAPPY21, 0, "Button Trigger Happy 21"}, |
|
151 |
|
{BTN_TRIGGER_HAPPY22, 0, "Button Trigger Happy 22"}, |
|
152 |
|
{BTN_TRIGGER_HAPPY23, 0, "Button Trigger Happy 23"}, |
|
153 |
|
{BTN_TRIGGER_HAPPY24, 0, "Button Trigger Happy 24"}, |
|
154 |
|
{BTN_TRIGGER_HAPPY25, 0, "Button Trigger Happy 25"}, |
|
155 |
|
{BTN_TRIGGER_HAPPY26, 0, "Button Trigger Happy 26"}, |
|
156 |
|
{BTN_TRIGGER_HAPPY27, 0, "Button Trigger Happy 27"}, |
|
157 |
|
{BTN_TRIGGER_HAPPY28, 0, "Button Trigger Happy 28"}, |
|
158 |
|
{BTN_TRIGGER_HAPPY29, 0, "Button Trigger Happy 29"}, |
|
159 |
|
{BTN_TRIGGER_HAPPY30, 0, "Button Trigger Happy 30"}, |
|
160 |
|
{BTN_TRIGGER_HAPPY31, 0, "Button Trigger Happy 31"}, |
|
161 |
|
{BTN_TRIGGER_HAPPY32, 0, "Button Trigger Happy 32"}, |
|
162 |
|
{BTN_TRIGGER_HAPPY33, 0, "Button Trigger Happy 33"}, |
|
163 |
|
{BTN_TRIGGER_HAPPY34, 0, "Button Trigger Happy 34"}, |
|
164 |
|
{BTN_TRIGGER_HAPPY35, 0, "Button Trigger Happy 35"}, |
|
165 |
|
{BTN_TRIGGER_HAPPY36, 0, "Button Trigger Happy 36"}, |
|
166 |
|
{BTN_TRIGGER_HAPPY37, 0, "Button Trigger Happy 37"}, |
|
167 |
|
{BTN_TRIGGER_HAPPY38, 0, "Button Trigger Happy 38"}, |
|
168 |
|
{BTN_TRIGGER_HAPPY39, 0, "Button Trigger Happy 39"}, |
|
169 |
|
{BTN_TRIGGER_HAPPY40, 0, "Button Trigger Happy 40"} |
|
170 |
|
}; |
|
171 |
|
/* end of evdev button to dix mapping definitions */ |
|
172 |
|
/*----------------------------------------------------------------------------*/ |
|
173 |
|
|
|
174 |
|
static void |
|
175 |
|
btns_section_map(struct dix_init_data *init_data, struct btn *evdev_section, |
|
176 |
|
long evdev_section_btns_n, int *dix_map, u16 evdev_mask) |
|
177 |
|
{ |
|
178 |
|
struct evdev *evdev; |
|
179 |
|
long section_btn_idx; |
|
180 |
|
|
|
181 |
|
evdev = init_data->dix->public.devicePrivate; |
|
182 |
|
|
|
183 |
|
for (section_btn_idx = 0; section_btn_idx < evdev_section_btns_n; |
|
184 |
|
++section_btn_idx) { |
|
185 |
|
struct btn *section_btn; |
|
186 |
|
|
|
187 |
|
section_btn = evdev_section + section_btn_idx; |
|
188 |
|
|
|
189 |
|
if (IS_BIT_SET(evdev->key_codes, section_btn->evdev_bit)) { |
|
190 |
|
u16 evdev_map_idx; |
|
191 |
|
|
|
192 |
|
/* we use the xserver strings for evdev, they are the same */ |
|
193 |
|
if (section_btn->dix) { |
|
194 |
|
ErrorF("evdev %s mapped to dix %u\n", section_btn->name, |
|
195 |
|
section_btn->dix); |
|
196 |
|
|
|
197 |
|
} else { |
|
198 |
|
ErrorF("evdev %s ignored\n", section_btn->name); |
|
199 |
|
} |
|
200 |
|
|
|
201 |
|
if (section_btn->dix > init_data->dix_btn_n_max) |
|
202 |
|
init_data->dix_btn_n_max = (u16)section_btn->dix; |
|
203 |
|
|
|
204 |
|
evdev_map_idx = section_btn->evdev_bit & ~evdev_mask; |
|
205 |
|
dix_map[evdev_map_idx] = section_btn->dix; |
|
206 |
|
} |
|
207 |
|
} |
|
208 |
|
} |
|
209 |
|
|
|
210 |
|
void |
|
211 |
|
key_btns_get(struct dix_init_data *init_data) |
|
212 |
|
{ |
|
213 |
|
struct evdev *evdev; |
|
214 |
|
|
|
215 |
|
evdev = init_data->dix->public.devicePrivate; |
|
216 |
|
|
|
217 |
|
ErrorF("getting supported evdev misc section buttons...\n"); |
|
218 |
|
btns_section_map(init_data, &btns_section_misc[0], |
|
219 |
|
ARRAY_SIZE(btns_section_misc), |
|
220 |
|
&evdev->btns_misc_dix_map[0], BTN_MISC); |
|
221 |
|
|
|
222 |
|
ErrorF("getting supported evdev mouse section buttons...\n"); |
|
223 |
|
btns_section_map(init_data, &btns_section_mouse[0], |
|
224 |
|
ARRAY_SIZE(btns_section_mouse), |
|
225 |
|
&evdev->btns_mouse_dix_map[0], BTN_MOUSE); |
|
226 |
|
|
|
227 |
|
ErrorF("getting supported evdev joystick section buttons...\n"); |
|
228 |
|
btns_section_map(init_data, &btns_section_joystick[0], |
|
229 |
|
ARRAY_SIZE(btns_section_joystick), |
|
230 |
|
&evdev->btns_joystick_dix_map[0], BTN_JOYSTICK); |
|
231 |
|
|
|
232 |
|
ErrorF("getting supported evdev gamepad section buttons...\n"); |
|
233 |
|
btns_section_map(init_data, &btns_section_gamepad[0], |
|
234 |
|
ARRAY_SIZE(btns_section_gamepad), |
|
235 |
|
&evdev->btns_gamepad_dix_map[0], BTN_GAMEPAD); |
|
236 |
|
|
|
237 |
|
ErrorF("getting supported evdev digi section buttons...\n"); |
|
238 |
|
btns_section_map(init_data, &btns_section_digi[0], |
|
239 |
|
ARRAY_SIZE(btns_section_digi), |
|
240 |
|
&evdev->btns_digi_dix_map[0], BTN_DIGI); |
|
241 |
|
|
|
242 |
|
ErrorF("getting supported evdev wheel section buttons...\n"); |
|
243 |
|
btns_section_map(init_data, &btns_section_wheel[0], |
|
244 |
|
ARRAY_SIZE(btns_section_wheel), |
|
245 |
|
&evdev->btns_wheel_dix_map[0], BTN_WHEEL); |
|
246 |
|
|
|
247 |
|
ErrorF("getting supported evdev dpad section buttons...\n"); |
|
248 |
|
btns_section_map(init_data, &btns_section_dpad[0], |
|
249 |
|
ARRAY_SIZE(btns_section_dpad), |
|
250 |
|
&evdev->btns_dpad_dix_map[0], BTN_DPAD_UP); |
|
251 |
|
|
|
252 |
|
ErrorF("getting supported evdev trigger happy section buttons...\n"); |
|
253 |
|
btns_section_map(init_data, &btns_section_trigger_happy[0], |
|
254 |
|
ARRAY_SIZE(btns_section_trigger_happy), |
|
255 |
|
&evdev->btns_trigger_happy_dix_map[0], BTN_TRIGGER_HAPPY); |
|
256 |
|
} |
|
257 |
|
|
|
258 |
|
/* we could use Bool arithmetics... */ |
|
259 |
|
u16 |
|
260 |
|
btn_section_mask_get(u16 code) |
|
261 |
|
{ |
|
262 |
|
if (BTN_MISC <= code && code <= BTN_9) |
|
263 |
|
return BTN_MISC; |
|
264 |
|
|
|
265 |
|
if (BTN_MOUSE <= code && code <= BTN_TASK) |
|
266 |
|
return BTN_MOUSE; |
|
267 |
|
|
|
268 |
|
if (BTN_JOYSTICK <= code && code <= BTN_DEAD) |
|
269 |
|
return BTN_JOYSTICK; |
|
270 |
|
|
|
271 |
|
if (BTN_GAMEPAD <= code && code <= BTN_THUMBR) |
|
272 |
|
return BTN_GAMEPAD; |
|
273 |
|
|
|
274 |
|
if (BTN_DIGI <= code && code <= BTN_TOOL_QUADTAP) |
|
275 |
|
return BTN_DIGI; |
|
276 |
|
|
|
277 |
|
if (BTN_WHEEL <= code && code <= BTN_GEAR_UP) |
|
278 |
|
return BTN_WHEEL; |
|
279 |
|
|
|
280 |
|
if (BTN_DPAD_UP <= code && code <= BTN_DPAD_RIGHT) |
|
281 |
|
return BTN_DPAD_UP; |
|
282 |
|
|
|
283 |
|
if (BTN_TRIGGER_HAPPY <= code && code <= BTN_TRIGGER_HAPPY40) |
|
284 |
|
return BTN_TRIGGER_HAPPY; |
|
285 |
|
return 0; /* it's a KEY KEY not KEY BTN... */ |
|
286 |
|
} |
|
287 |
|
|
|
288 |
|
void |
|
289 |
|
btn_process(DeviceIntPtr dix, struct input_event *e, u16 btn_section_mask) |
|
290 |
|
{ |
|
291 |
|
int dix_btn_n; |
|
292 |
|
struct evdev *evdev; |
|
293 |
|
int dix_type; |
|
294 |
|
|
|
295 |
|
evdev = dix->public.devicePrivate; |
|
296 |
|
dix_btn_n = 0; |
|
297 |
|
|
|
298 |
|
switch (btn_section_mask) { |
|
299 |
|
case BTN_MISC: |
|
300 |
|
dix_btn_n = evdev->btns_misc_dix_map[e->code & ~BTN_MISC]; |
|
301 |
|
break; |
|
302 |
|
case BTN_MOUSE: |
|
303 |
|
dix_btn_n = evdev->btns_mouse_dix_map[e->code & ~BTN_MOUSE]; |
|
304 |
|
break; |
|
305 |
|
case BTN_JOYSTICK: |
|
306 |
|
dix_btn_n = evdev->btns_joystick_dix_map[e->code & ~BTN_JOYSTICK]; |
|
307 |
|
break; |
|
308 |
|
case BTN_GAMEPAD: |
|
309 |
|
dix_btn_n = evdev->btns_gamepad_dix_map[e->code & ~BTN_GAMEPAD]; |
|
310 |
|
break; |
|
311 |
|
case BTN_DIGI: |
|
312 |
|
dix_btn_n = evdev->btns_digi_dix_map[e->code & ~BTN_DIGI]; |
|
313 |
|
break; |
|
314 |
|
case BTN_WHEEL: |
|
315 |
|
dix_btn_n = evdev->btns_wheel_dix_map[e->code & ~BTN_WHEEL]; |
|
316 |
|
break; |
|
317 |
|
case BTN_DPAD_UP: |
|
318 |
|
dix_btn_n = evdev->btns_wheel_dix_map[e->code & ~BTN_DPAD_UP]; |
|
319 |
|
break; |
|
320 |
|
case BTN_TRIGGER_HAPPY: |
|
321 |
|
dix_btn_n = evdev->btns_trigger_happy_dix_map[e->code |
|
322 |
|
& ~BTN_TRIGGER_HAPPY]; |
|
323 |
|
break; |
|
324 |
|
}; |
|
325 |
|
|
|
326 |
|
if (!dix_btn_n) /* no dix btn mapped */ |
|
327 |
|
return; |
|
328 |
|
|
|
329 |
|
/* |
|
330 |
|
* XXX: a evdev KEY can have an "autorepeat" value = 2, ignore the button |
|
331 |
|
* event |
|
332 |
|
*/ |
|
333 |
|
if (e->value == 2) |
|
334 |
|
return; |
|
335 |
|
|
|
336 |
|
if (e->value) |
|
337 |
|
dix_type = ButtonPress; |
|
338 |
|
else |
|
339 |
|
dix_type = ButtonRelease; |
|
340 |
|
|
|
341 |
|
QueuePointerEvents(dix, dix_type, dix_btn_n, 0, NULL); |
|
342 |
|
} |
|
343 |
|
|
|
344 |
|
#define BTN_ATOM_FMT "Button %02u" |
|
345 |
|
#define BTN_ATOM_TMPL "Button XX" |
|
346 |
|
#define BTN_ATOM_TMPL_SZ sizeof(BTN_ATOM_TMPL) |
|
347 |
|
static Atom* |
|
348 |
|
dix_btns_atom_make(u16 btns_cnt) |
|
349 |
|
{ |
|
350 |
|
u16 btn; |
|
351 |
|
Atom *labels; |
|
352 |
|
|
|
353 |
|
ErrorF("creating %u atoms for button labels\n", btns_cnt); |
|
354 |
|
|
|
355 |
|
labels = xnfcalloc(1, btns_cnt * sizeof(*labels)); |
|
356 |
|
|
|
357 |
|
/* x11 button number for 1, but labels from 0 */ |
|
358 |
|
for(btn = 1; btn <= btns_cnt; ++btn) { |
|
359 |
|
char label[BTN_ATOM_TMPL_SZ]; |
|
360 |
|
|
|
361 |
|
snprintf(label, BTN_ATOM_TMPL_SZ, BTN_ATOM_FMT, btn); |
|
362 |
|
|
|
363 |
|
labels[btn - 1] = MakeAtom(label, strlen(label), TRUE); |
|
364 |
|
if (labels[btn - 1] == BAD_RESOURCE) { |
|
365 |
|
ErrorF("unable to make atom for button label %02u\n", btn); |
|
366 |
|
free(labels); |
|
367 |
|
return NULL; |
|
368 |
|
} |
|
369 |
|
} |
|
370 |
|
return labels; |
|
371 |
|
} |
|
372 |
|
|
|
373 |
|
Bool |
|
374 |
|
dix_btns_register(struct dix_init_data *init_data) |
|
375 |
|
{ |
|
376 |
|
Bool r; |
|
377 |
|
Atom *labels; |
|
378 |
|
BYTE *map; |
|
379 |
|
u16 btn; |
|
380 |
|
|
|
381 |
|
if (!init_data->dix_btn_n_max) { |
|
382 |
|
ErrorF("no evdev buttons to register in dix\n"); |
|
383 |
|
return TRUE; |
|
384 |
|
} |
|
385 |
|
|
|
386 |
|
labels = dix_btns_atom_make(init_data->dix_btn_n_max); |
|
387 |
|
if (!labels) |
|
388 |
|
return FALSE; |
|
389 |
|
|
|
390 |
|
/* identity mapping */ |
|
391 |
|
map = xnfcalloc(1, (init_data->dix_btn_n_max + 1) * sizeof(*map)); |
|
392 |
|
for (btn = 1; btn <= init_data->dix_btn_n_max; ++btn) |
|
393 |
|
map[btn] = (BYTE)btn; |
|
394 |
|
|
|
395 |
|
r = InitButtonClassDeviceStruct(init_data->dix, |
|
396 |
|
init_data->dix_btn_n_max, labels, map); |
|
397 |
|
if (!r) |
|
398 |
|
ErrorF("unable to register evdev buttons in dix\n"); |
|
399 |
|
|
|
400 |
|
free(map); |
|
401 |
|
free(labels); |
|
402 |
|
return r; |
|
403 |
|
} |
File hw/xalga/output.c added (mode: 100644) (index 0000000..2273ead) |
|
1 |
|
/* |
|
2 |
|
* XALGA implementation |
|
3 |
|
* Copyright (C) 2014 Sylvain BERTRAND All Rights Reserved |
|
4 |
|
* Opens source legal protection provided by a GNU Lesser GPLv3 license |
|
5 |
|
*/ |
|
6 |
|
#include <stdint.h> |
|
7 |
|
/*============================================================================*/ |
|
8 |
|
#include <time.h> |
|
9 |
|
#include <sys/epoll.h> |
|
10 |
|
#include <sys/ioctl.h> |
|
11 |
|
#include <sys/mman.h> |
|
12 |
|
#include <stdlib.h> |
|
13 |
|
#include <unistd.h> |
|
14 |
|
#include <fcntl.h> |
|
15 |
|
#include <errno.h> |
|
16 |
|
#include <alga/pixel_fmts.h> |
|
17 |
|
#include <alga/amd/dce6/dce6.h> |
|
18 |
|
#include <alga/amd/si/ioctl.h> |
|
19 |
|
/*============================================================================*/ |
|
20 |
|
|
|
21 |
|
#include "dix-config.h" |
|
22 |
|
#include "randrstr.h" |
|
23 |
|
#include "micmap.h" |
|
24 |
|
#include "fb.h" |
|
25 |
|
#include "mipointer.h" |
|
26 |
|
|
|
27 |
|
#include "xalga/namespace.h" |
|
28 |
|
|
|
29 |
|
#define DISPLAYPORT_DEFAULT_WIDTH 640 |
|
30 |
|
#define DISPLAYPORT_DEFAULT_HEIGHT 480 |
|
31 |
|
#define DISPLAYPORT_DEFAULT_REFRESH 60 |
|
32 |
|
#define X_DPI_DEFAULT 96 |
|
33 |
|
#define Y_DPI_DEFAULT 96 |
|
34 |
|
#define DCE6_WIDTH_MAX 16384 |
|
35 |
|
#define DCE6_HEIGHT_MAX 16384 |
|
36 |
|
|
|
37 |
|
#define CREATE_PIXMAP_USAGE_DMA 5 |
|
38 |
|
|
|
39 |
|
/*----------------------------------------------------------------------------*/ |
|
40 |
|
struct alga_pixmap { |
|
41 |
|
void *data; |
|
42 |
|
u64 data_sz; |
|
43 |
|
}; |
|
44 |
|
static DevPrivateKeyRec alga_pixmap_private_key; |
|
45 |
|
|
|
46 |
|
static void alga_pixmap_set_private(PixmapPtr pixmap, |
|
47 |
|
struct alga_pixmap *alga_pixmap); |
|
48 |
|
static PixmapPtr pixmap_create(ScreenPtr screen, int w, int h, int d, |
|
49 |
|
unsigned int hint); |
|
50 |
|
static Bool pixmap_destroy(PixmapPtr pixmap); |
|
51 |
|
/*----------------------------------------------------------------------------*/ |
|
52 |
|
|
|
53 |
|
|
|
54 |
|
/*----------------------------------------------------------------------------*/ |
|
55 |
|
#define MODE_NAME_MAX_TMPL "wwwwxhhhhh@rrr" |
|
56 |
|
struct alga_screen { |
|
57 |
|
/* this is used to chain our work with the work of other subsystems */ |
|
58 |
|
CreateScreenResourcesProcPtr CreateScreenResources; |
|
59 |
|
CloseScreenProcPtr CloseScreen; |
|
60 |
|
|
|
61 |
|
RealizeWindowProcPtr RealizeWindow; |
|
62 |
|
|
|
63 |
|
/*============================================================================*/ |
|
64 |
|
int f; |
|
65 |
|
u16 w; |
|
66 |
|
u16 h; |
|
67 |
|
u8 r; |
|
68 |
|
u8 pixel_fmt; |
|
69 |
|
u64 stride; |
|
70 |
|
/* because af randr mode info, it must have a terminal 0 */ |
|
71 |
|
char mode_name[sizeof(MODE_NAME_MAX_TMPL)]; |
|
72 |
|
|
|
73 |
|
u8 idx; /* the index of the display block */ |
|
74 |
|
u64 fb_gpu_addr_front; |
|
75 |
|
u64 fb_gpu_addr_back; |
|
76 |
|
u64 fb_gpu_addr_visible; |
|
77 |
|
u64 fb_gpu_addr_hidden; |
|
78 |
|
u64 fb_sz; |
|
79 |
|
RROutputPtr randr_output; |
|
80 |
|
RRCrtcPtr randr_crtc; |
|
81 |
|
|
|
82 |
|
/*----------------*/ |
|
83 |
|
/* state */ |
|
84 |
|
Bool dpm_on; |
|
85 |
|
Bool flip_evts_expected; |
|
86 |
|
Bool fb_dma_do; |
|
87 |
|
/*----------------*/ |
|
88 |
|
ScreenBlockHandlerProcPtr BlockHandler; |
|
89 |
|
ScreenWakeupHandlerProcPtr WakeupHandler; |
|
90 |
|
/*============================================================================*/ |
|
91 |
|
}; |
|
92 |
|
static DevPrivateKeyRec alga_screen_private_key; |
|
93 |
|
|
|
94 |
|
static void alga_screen_set_private(ScreenPtr screen, |
|
95 |
|
struct alga_screen *alga_screen); |
|
96 |
|
static struct alga_screen * alga_screen_get(ScreenPtr screen); |
|
97 |
|
static Bool screen_save(ScreenPtr pScreen, int on); |
|
98 |
|
static Bool alga_CreateScreenResources(ScreenPtr screen); |
|
99 |
|
static Bool alga_CloseScreen(ScreenPtr screen); |
|
100 |
|
static Bool alga_rrGetInfo(ScreenPtr pScreen, Rotation * rotations); |
|
101 |
|
static Bool alga_rrSetConfig(ScreenPtr pScreen, Rotation rotation, int rate, |
|
102 |
|
RRScreenSizePtr pSize); |
|
103 |
|
/*============================================================================*/ |
|
104 |
|
static void alga_fb_alloc(struct alga_screen *alga_screen); |
|
105 |
|
static void alga_fb_free(struct alga_screen *alga_screen); |
|
106 |
|
static void alga_mode_set(struct alga_screen *alga_screen); |
|
107 |
|
/*============================================================================*/ |
|
108 |
|
/*----------------------------------------------------------------------------*/ |
|
109 |
|
|
|
110 |
|
|
|
111 |
|
/*----------------------------------------------------------------------------*/ |
|
112 |
|
struct alga_window { |
|
113 |
|
WindowPtr window; |
|
114 |
|
DamagePtr damage; |
|
115 |
|
}; |
|
116 |
|
|
|
117 |
|
static Bool alga_RealizeWindow(WindowPtr window); |
|
118 |
|
/*----------------------------------------------------------------------------*/ |
|
119 |
|
|
|
120 |
|
|
|
121 |
|
/*----------------------------------------------------------------------------*/ |
|
122 |
|
static Bool alga_CursorOffScreen(ScreenPtr *screen, int *x, int *y); |
|
123 |
|
static void alga_CrossScreen(ScreenPtr screen, int entering); |
|
124 |
|
static void alga_WarpCursor(DeviceIntPtr dev, ScreenPtr screen, int x, int y); |
|
125 |
|
|
|
126 |
|
miPointerScreenFuncRec alga_pointer_screen_funcs = { |
|
127 |
|
alga_CursorOffScreen, |
|
128 |
|
alga_CrossScreen, |
|
129 |
|
alga_WarpCursor |
|
130 |
|
}; |
|
131 |
|
/*----------------------------------------------------------------------------*/ |
|
132 |
|
|
|
133 |
|
|
|
134 |
|
/*----------------------------------------------------------------------------*/ |
|
135 |
|
static void alga_BlockHandler(ScreenPtr pScreen, void *pTimeout, |
|
136 |
|
void *pReadmask); |
|
137 |
|
static void alga_WakeupHandler(ScreenPtr pScreen, unsigned long result, |
|
138 |
|
void *pReadMask); |
|
139 |
|
/*----------------------------------------------------------------------------*/ |
|
140 |
|
|
|
141 |
|
|
|
142 |
|
/*----------------------------------------------------------------------------*/ |
|
143 |
|
Bool screen_init(ScreenPtr screen, int argc, char **argv); |
|
144 |
|
/*----------------------------------------------------------------------------*/ |
|
145 |
|
|
|
146 |
|
|
|
147 |
|
/*----------------------------------------------------------------------------*/ |
|
148 |
|
static void dpm_on(ScreenPtr pScreen); |
|
149 |
|
static void fb_flip_schedule(ScreenPtr screen, Bool retry_on_pending); |
|
150 |
|
static void si_evts_process(ScreenPtr screen, Bool flip_fbs); |
|
151 |
|
static void fb_dma_to_device(ScreenPtr screen, Bool visible); |
|
152 |
|
/*----------------------------------------------------------------------------*/ |
|
153 |
|
|
|
154 |
|
|
|
155 |
|
static Bool |
|
156 |
|
alga_CursorOffScreen(ScreenPtr *screen, int *x, int *y) |
|
157 |
|
{ |
|
158 |
|
/* |
|
159 |
|
* XXX: if there are more than 1 screen, and if the cursor leaving its |
|
160 |
|
* current screen reaches another screen, then update the screen pointer |
|
161 |
|
* and return TRUE. Else return FALSE; |
|
162 |
|
*/ |
|
163 |
|
return FALSE; |
|
164 |
|
} |
|
165 |
|
|
|
166 |
|
static void |
|
167 |
|
alga_CrossScreen(ScreenPtr screen, int entering) |
|
168 |
|
{ |
|
169 |
|
/* |
|
170 |
|
* XXX: probably called when entering a new screen decided by |
|
171 |
|
* alga_CursorOffScreen above. |
|
172 |
|
*/ |
|
173 |
|
} |
|
174 |
|
|
|
175 |
|
static void |
|
176 |
|
alga_WarpCursor(DeviceIntPtr dev, ScreenPtr screen, int x, int y) |
|
177 |
|
{ |
|
178 |
|
OsBlockSIGIO(); |
|
179 |
|
miPointerWarpCursor(dev, screen, x, y); |
|
180 |
|
OsReleaseSIGIO(); |
|
181 |
|
} |
|
182 |
|
|
|
183 |
|
static void |
|
184 |
|
alga_pixmap_set_private(PixmapPtr pixmap, struct alga_pixmap *alga_pixmap) |
|
185 |
|
{ |
|
186 |
|
dixSetPrivate(&pixmap->devPrivates, &alga_pixmap_private_key, alga_pixmap); |
|
187 |
|
} |
|
188 |
|
|
|
189 |
|
static struct alga_pixmap * |
|
190 |
|
alga_pixmap_get(PixmapPtr pixmap) |
|
191 |
|
{ |
|
192 |
|
return dixLookupPrivate(&pixmap->devPrivates, &alga_screen_private_key); |
|
193 |
|
} |
|
194 |
|
|
|
195 |
|
static void |
|
196 |
|
alga_screen_set_private(ScreenPtr screen, struct alga_screen *alga_screen) |
|
197 |
|
{ |
|
198 |
|
dixSetPrivate(&screen->devPrivates, &alga_screen_private_key, alga_screen); |
|
199 |
|
} |
|
200 |
|
|
|
201 |
|
static struct alga_screen * |
|
202 |
|
alga_screen_get(ScreenPtr screen) |
|
203 |
|
{ |
|
204 |
|
return dixLookupPrivate(&screen->devPrivates, &alga_screen_private_key); |
|
205 |
|
} |
|
206 |
|
|
|
207 |
|
static Bool |
|
208 |
|
pixmap_destroy(PixmapPtr pixmap) |
|
209 |
|
{ |
|
210 |
|
struct alga_pixmap *alga_pixmap; |
|
211 |
|
|
|
212 |
|
alga_pixmap = alga_pixmap_get(pixmap); |
|
213 |
|
|
|
214 |
|
if (alga_pixmap && pixmap->refcnt == 1) { |
|
215 |
|
if (alga_pixmap->data) |
|
216 |
|
munmap(alga_pixmap->data, alga_pixmap->data_sz); |
|
217 |
|
free(alga_pixmap); |
|
218 |
|
} |
|
219 |
|
return fbDestroyPixmap(pixmap); |
|
220 |
|
} |
|
221 |
|
|
|
222 |
|
static PixmapPtr |
|
223 |
|
pixmap_create(ScreenPtr screen, int w, int h, int d, unsigned int hint) |
|
224 |
|
{ |
|
225 |
|
PixmapPtr pixmap; |
|
226 |
|
struct alga_pixmap *alga_pixmap; |
|
227 |
|
u64 stride; |
|
228 |
|
Bool r; |
|
229 |
|
struct alga_screen *alga_screen; |
|
230 |
|
|
|
231 |
|
/* we have our own hint */ |
|
232 |
|
if (hint != CREATE_PIXMAP_USAGE_DMA) |
|
233 |
|
return fbCreatePixmap(screen, w, h, d, hint); |
|
234 |
|
|
|
235 |
|
/* |
|
236 |
|
* XXX: here we let the fb helper create a pixmap of WxH 0x0 which we will |
|
237 |
|
* update below with the right sizes. This is a nasty hack in order |
|
238 |
|
* to forbid the fb helper to allocate memory. |
|
239 |
|
*/ |
|
240 |
|
pixmap = fbCreatePixmap(screen, 0, 0, d, hint); |
|
241 |
|
if (!pixmap) { |
|
242 |
|
ErrorF("%s:unable to allocate frame buffer helper pixmap\n", __func__); |
|
243 |
|
return NULL; |
|
244 |
|
} |
|
245 |
|
|
|
246 |
|
alga_pixmap = malloc(sizeof(*alga_pixmap)); |
|
247 |
|
if (alga_pixmap == NULL) { |
|
248 |
|
ErrorF("%s:unable to allocate alga pixmap\n", __func__); |
|
249 |
|
goto err_destroy_pixmap; |
|
250 |
|
} |
|
251 |
|
|
|
252 |
|
/* the actual number of byte for a line */ |
|
253 |
|
stride = (u64)PixmapBytePad(w, d); |
|
254 |
|
alga_pixmap->data_sz = stride * h; |
|
255 |
|
|
|
256 |
|
alga_screen = alga_screen_get(screen); |
|
257 |
|
alga_pixmap->data = mmap(NULL, alga_pixmap->data_sz, PROT_READ |
|
258 |
|
| PROT_WRITE, MAP_SHARED, alga_screen->f, 0); |
|
259 |
|
if (alga_pixmap->data == MAP_FAILED) { |
|
260 |
|
ErrorF("%s:unable to mmap alga pixmap buffer\n", __func__); |
|
261 |
|
alga_pixmap->data = NULL; |
|
262 |
|
goto err_free_alga_pixmap; |
|
263 |
|
} |
|
264 |
|
|
|
265 |
|
r = (*screen->ModifyPixmapHeader)(pixmap, w, h, d, BitsPerPixel(d), stride, |
|
266 |
|
alga_pixmap->data); |
|
267 |
|
if (!r) { |
|
268 |
|
ErrorF("%s:unable to modify pixmap header\n", __func__); |
|
269 |
|
goto err_munmap_alga_pixmap_data; |
|
270 |
|
} |
|
271 |
|
|
|
272 |
|
alga_pixmap_set_private(pixmap, alga_pixmap); |
|
273 |
|
return pixmap; |
|
274 |
|
|
|
275 |
|
err_munmap_alga_pixmap_data: |
|
276 |
|
munmap(alga_pixmap->data, alga_pixmap->data_sz); |
|
277 |
|
|
|
278 |
|
err_free_alga_pixmap: |
|
279 |
|
free(alga_pixmap); |
|
280 |
|
|
|
281 |
|
err_destroy_pixmap: |
|
282 |
|
fbDestroyPixmap(pixmap); |
|
283 |
|
return NULL; |
|
284 |
|
} |
|
285 |
|
|
|
286 |
|
static Bool |
|
287 |
|
alga_RealizeWindow(WindowPtr window) |
|
288 |
|
{ |
|
289 |
|
ScreenPtr screen; |
|
290 |
|
struct alga_screen *alga_screen; |
|
291 |
|
Bool r; |
|
292 |
|
|
|
293 |
|
screen = window->drawable.pScreen; |
|
294 |
|
alga_screen = alga_screen_get(screen); |
|
295 |
|
|
|
296 |
|
screen->RealizeWindow = alga_screen->RealizeWindow; |
|
297 |
|
r = screen->RealizeWindow(window); |
|
298 |
|
|
|
299 |
|
/* |
|
300 |
|
* XXX: in xalga we want the cursor on the root window to be displayed right |
|
301 |
|
* away and not wait for the first application to call XDefineCursor |
|
302 |
|
*/ |
|
303 |
|
if (window == screen->root) |
|
304 |
|
CursorVisible = EnableCursor; |
|
305 |
|
|
|
306 |
|
if (!r) |
|
307 |
|
goto err; |
|
308 |
|
|
|
309 |
|
|
|
310 |
|
alga_screen->RealizeWindow = screen->RealizeWindow; |
|
311 |
|
screen->RealizeWindow = alga_RealizeWindow; |
|
312 |
|
return TRUE; |
|
313 |
|
|
|
314 |
|
err: |
|
315 |
|
alga_screen->RealizeWindow = screen->RealizeWindow; |
|
316 |
|
screen->RealizeWindow = alga_RealizeWindow; |
|
317 |
|
return FALSE; |
|
318 |
|
} |
|
319 |
|
|
|
320 |
|
static void |
|
321 |
|
fb_flip_evt_wait(ScreenPtr pScreen) |
|
322 |
|
{ |
|
323 |
|
struct alga_screen *alga_screen; |
|
324 |
|
fd_set flip_set; |
|
325 |
|
int r; |
|
326 |
|
|
|
327 |
|
alga_screen = alga_screen_get(pScreen); |
|
328 |
|
|
|
329 |
|
FD_ZERO(&flip_set); |
|
330 |
|
FD_SET(alga_screen->f, &flip_set); |
|
331 |
|
while (1) { |
|
332 |
|
errno = 0; |
|
333 |
|
r = select(alga_screen->f + 1, &flip_set, NULL, NULL, NULL); |
|
334 |
|
if (r == -1 && errno != EINTR) |
|
335 |
|
FatalError("%s:unable to synchronously wait for the flip event\n", |
|
336 |
|
__func__); |
|
337 |
|
if (r == 1) |
|
338 |
|
break; |
|
339 |
|
} |
|
340 |
|
} |
|
341 |
|
|
|
342 |
|
static void |
|
343 |
|
dpm_on(ScreenPtr pScreen) |
|
344 |
|
{ |
|
345 |
|
struct alga_screen *alga_screen; |
|
346 |
|
int r; |
|
347 |
|
ul req; |
|
348 |
|
|
|
349 |
|
alga_screen = alga_screen_get(pScreen); |
|
350 |
|
|
|
351 |
|
req = _IOW('d', SI_DCE_DP_DPM, alga_screen->idx); |
|
352 |
|
r = ioctl(alga_screen->f, req, &alga_screen->idx); |
|
353 |
|
if (r == -1) |
|
354 |
|
FatalError("%s:an error occured while switching dpm on\n", __func__); |
|
355 |
|
} |
|
356 |
|
|
|
357 |
|
static Bool |
|
358 |
|
screen_save(ScreenPtr pScreen, int on) |
|
359 |
|
{ |
|
360 |
|
struct alga_screen *alga_screen; |
|
361 |
|
alga_screen = alga_screen_get(pScreen); |
|
362 |
|
|
|
363 |
|
switch (on) { |
|
364 |
|
case SCREEN_SAVER_ON: |
|
365 |
|
/* |
|
366 |
|
* we allow to stall and wait for the outstanding page flip event |
|
367 |
|
* since we are not in a hurry. In the opposite case, we would have |
|
368 |
|
* needed a cancel flip driver command |
|
369 |
|
*/ |
|
370 |
|
if (alga_screen->flip_evts_expected) { |
|
371 |
|
fb_flip_evt_wait(pScreen); |
|
372 |
|
si_evts_process(pScreen, FALSE); |
|
373 |
|
alga_screen->flip_evts_expected = FALSE; |
|
374 |
|
} |
|
375 |
|
dpm_on(pScreen); |
|
376 |
|
alga_screen->dpm_on = TRUE; |
|
377 |
|
break; |
|
378 |
|
case SCREEN_SAVER_OFF: |
|
379 |
|
alga_mode_set(alga_screen); |
|
380 |
|
alga_screen->fb_dma_do = TRUE; |
|
381 |
|
alga_screen->dpm_on = FALSE; |
|
382 |
|
break; |
|
383 |
|
case SCREEN_SAVER_FORCER: |
|
384 |
|
case SCREEN_SAVER_CYCLE: |
|
385 |
|
default: |
|
386 |
|
break; |
|
387 |
|
}; |
|
388 |
|
return TRUE; |
|
389 |
|
} |
|
390 |
|
|
|
391 |
|
static Bool |
|
392 |
|
alga_CloseScreen(ScreenPtr screen) |
|
393 |
|
{ |
|
394 |
|
struct alga_screen *alga_screen; |
|
395 |
|
|
|
396 |
|
alga_screen = alga_screen_get(screen); |
|
397 |
|
|
|
398 |
|
/*========================================================================*/ |
|
399 |
|
dpm_on(screen); |
|
400 |
|
RROutputDestroy(alga_screen->randr_output); |
|
401 |
|
RRCrtcDestroy(alga_screen->randr_crtc); |
|
402 |
|
alga_fb_free(alga_screen); |
|
403 |
|
pixmap_destroy((PixmapPtr)screen->devPrivate); |
|
404 |
|
/* |
|
405 |
|
* XXX: the fb helper screen close expect a pixmap here if not null and |
|
406 |
|
* will free the pixmap without destroying it... |
|
407 |
|
*/ |
|
408 |
|
screen->devPrivate = NULL; |
|
409 |
|
RemoveGeneralSocket(alga_screen->f); |
|
410 |
|
close(alga_screen->f); |
|
411 |
|
/*========================================================================*/ |
|
412 |
|
|
|
413 |
|
/* unwrap/restore screen methods */ |
|
414 |
|
screen->CreateScreenResources = alga_screen->CreateScreenResources; |
|
415 |
|
screen->CloseScreen = alga_screen->CloseScreen; |
|
416 |
|
screen->RealizeWindow= alga_screen->RealizeWindow; |
|
417 |
|
screen->BlockHandler = alga_screen->BlockHandler; |
|
418 |
|
screen->WakeupHandler = alga_screen->WakeupHandler; |
|
419 |
|
|
|
420 |
|
free(alga_screen); |
|
421 |
|
return screen->CloseScreen(screen); |
|
422 |
|
} |
|
423 |
|
|
|
424 |
|
static Bool |
|
425 |
|
alga_CreateScreenResources(ScreenPtr screen) |
|
426 |
|
{ |
|
427 |
|
struct alga_screen *alga_screen; |
|
428 |
|
Bool r; |
|
429 |
|
|
|
430 |
|
alga_screen = alga_screen_get(screen); |
|
431 |
|
|
|
432 |
|
screen->CreateScreenResources = alga_screen->CreateScreenResources; |
|
433 |
|
r = (*screen->CreateScreenResources)(screen); |
|
434 |
|
alga_screen->CreateScreenResources = screen->CreateScreenResources; |
|
435 |
|
screen->CreateScreenResources = alga_CreateScreenResources; |
|
436 |
|
|
|
437 |
|
if (!r) |
|
438 |
|
return FALSE; |
|
439 |
|
|
|
440 |
|
/* |
|
441 |
|
* XXX: we use the fb helper for the screen, it wants the framebuffer |
|
442 |
|
* pixmap here. Carefull, it's not "destroyed" between server generations, |
|
443 |
|
* just freed by the fb helper close screen. |
|
444 |
|
*/ |
|
445 |
|
screen->devPrivate = pixmap_create(screen, screen->width, screen->height, |
|
446 |
|
screen->rootDepth, CREATE_PIXMAP_USAGE_DMA); |
|
447 |
|
if (!screen->devPrivate) |
|
448 |
|
return FALSE; |
|
449 |
|
return TRUE; |
|
450 |
|
} |
|
451 |
|
|
|
452 |
|
static Bool |
|
453 |
|
alga_rrGetInfo(ScreenPtr pScreen, Rotation * rotations) |
|
454 |
|
{ |
|
455 |
|
*rotations = 0; |
|
456 |
|
|
|
457 |
|
return TRUE; |
|
458 |
|
} |
|
459 |
|
|
|
460 |
|
static Bool |
|
461 |
|
alga_rrSetConfig(ScreenPtr pScreen, Rotation rotation, int rate, |
|
462 |
|
RRScreenSizePtr pSize) |
|
463 |
|
{ |
|
464 |
|
return FALSE; |
|
465 |
|
} |
|
466 |
|
|
|
467 |
|
/*============================================================================*/ |
|
468 |
|
static void |
|
469 |
|
alga_fb_alloc(struct alga_screen *alga_screen) |
|
470 |
|
{ |
|
471 |
|
struct si_mem mem; |
|
472 |
|
u64 sz; |
|
473 |
|
ul req; |
|
474 |
|
int r; |
|
475 |
|
|
|
476 |
|
memset(&mem,0,sizeof(mem)); |
|
477 |
|
|
|
478 |
|
mem.align = 4096; /* FIXME: 256 should be enough */ |
|
479 |
|
alga_screen->fb_sz = alga_screen->stride * alga_screen->h; |
|
480 |
|
sz = 2 * alga_screen->fb_sz; |
|
481 |
|
mem.sz = sz; |
|
482 |
|
ErrorF("db_fb alloc sz=%016llx\n",(ull)mem.sz); |
|
483 |
|
req = _IOWR('d',SI_MEM_ALLOC,mem); |
|
484 |
|
r = ioctl(alga_screen->f, req, &mem); |
|
485 |
|
if (r == -1) |
|
486 |
|
FatalError("%s:alloc db_fb failed\n", __func__); |
|
487 |
|
|
|
488 |
|
ErrorF("front_fb=0x%016llx back_fb=0x%016llx\n",(ull)mem.gpu_addr, |
|
489 |
|
(ull)mem.gpu_addr + alga_screen->fb_sz); |
|
490 |
|
alga_screen->fb_gpu_addr_front = mem.gpu_addr; |
|
491 |
|
alga_screen->fb_gpu_addr_back = mem.gpu_addr + alga_screen->fb_sz; |
|
492 |
|
alga_screen->fb_gpu_addr_visible = alga_screen->fb_gpu_addr_front; |
|
493 |
|
alga_screen->fb_gpu_addr_hidden = alga_screen->fb_gpu_addr_back; |
|
494 |
|
} |
|
495 |
|
|
|
496 |
|
static void |
|
497 |
|
alga_fb_free(struct alga_screen *alga_screen) |
|
498 |
|
{ |
|
499 |
|
ul req; |
|
500 |
|
int r; |
|
501 |
|
|
|
502 |
|
ErrorF("freeing fb_gpu_addr_front=%016llx\n", |
|
503 |
|
(ull)alga_screen->fb_gpu_addr_front); |
|
504 |
|
req = _IOW('d', SI_MEM_FREE, alga_screen->fb_gpu_addr_front); |
|
505 |
|
r = ioctl(alga_screen->f, req, &alga_screen->fb_gpu_addr_front); |
|
506 |
|
if (r == -1) |
|
507 |
|
ErrorF("%s:free vram fb failed (LEAK till garbage collection is implemented!)\n", |
|
508 |
|
__func__); |
|
509 |
|
} |
|
510 |
|
|
|
511 |
|
static void |
|
512 |
|
alga_mode_set(struct alga_screen *alga_screen) |
|
513 |
|
{ |
|
514 |
|
struct si_dce_dp_set dp_set; |
|
515 |
|
ul req; |
|
516 |
|
int r; |
|
517 |
|
|
|
518 |
|
memset(&dp_set,0,sizeof(dp_set)); |
|
519 |
|
|
|
520 |
|
dp_set.idx = alga_screen->idx; |
|
521 |
|
dp_set.primary = alga_screen->fb_gpu_addr_front; |
|
522 |
|
dp_set.secondary = alga_screen->fb_gpu_addr_back; |
|
523 |
|
strncpy(&dp_set.mode[0], &alga_screen->mode_name[0], sizeof(dp_set.mode)); |
|
524 |
|
strncpy(&dp_set.pixel_fmt[0], alga_pixel_fmts_str[alga_screen->pixel_fmt], |
|
525 |
|
sizeof(dp_set.pixel_fmt)); |
|
526 |
|
req = _IOR('d', SI_DCE_DP_SET, dp_set); |
|
527 |
|
r = ioctl(alga_screen->f, req, &dp_set); |
|
528 |
|
if (r == -1) |
|
529 |
|
FatalError("%s:dp set failed", __func__); |
|
530 |
|
|
|
531 |
|
alga_screen->fb_gpu_addr_visible = alga_screen->fb_gpu_addr_front; |
|
532 |
|
alga_screen->fb_gpu_addr_hidden = alga_screen->fb_gpu_addr_back; |
|
533 |
|
} |
|
534 |
|
/*============================================================================*/ |
|
535 |
|
|
|
536 |
|
Bool |
|
537 |
|
screen_init(ScreenPtr screen, int argc, char **argv) |
|
538 |
|
{ |
|
539 |
|
Bool r; |
|
540 |
|
struct alga_screen *alga_screen; |
|
541 |
|
/*========================================================================*/ |
|
542 |
|
rrScrPrivPtr rr; |
|
543 |
|
xRRModeInfo mode_info; |
|
544 |
|
RRModePtr randr_mode; |
|
545 |
|
/*========================================================================*/ |
|
546 |
|
|
|
547 |
|
ErrorF("initing screen...\n"); |
|
548 |
|
|
|
549 |
|
/* a private key is the way to allocate private data into a public struct */ |
|
550 |
|
r = dixRegisterPrivateKey(&alga_pixmap_private_key, PRIVATE_PIXMAP, 0); |
|
551 |
|
if (!r) { |
|
552 |
|
ErrorF("unable to register a dix private key for pixmap structure\n"); |
|
553 |
|
goto err; |
|
554 |
|
} |
|
555 |
|
|
|
556 |
|
r = dixRegisterPrivateKey(&alga_screen_private_key, PRIVATE_SCREEN, 0); |
|
557 |
|
if (!r) { |
|
558 |
|
ErrorF("unable to register a dix private key for screen structure\n"); |
|
559 |
|
goto err; |
|
560 |
|
} |
|
561 |
|
|
|
562 |
|
alga_screen = calloc(1, sizeof(*alga_screen)); |
|
563 |
|
if (!alga_screen) { |
|
564 |
|
ErrorF("unable to allocate an alga private screen structure\n"); |
|
565 |
|
goto err; |
|
566 |
|
} |
|
567 |
|
|
|
568 |
|
/*========================================================================*/ |
|
569 |
|
alga_screen->f = open("/dev/si0", O_RDWR | O_NONBLOCK); |
|
570 |
|
if (alga_screen->f == -1) { |
|
571 |
|
ErrorF("unable to open /dev/si0\n"); |
|
572 |
|
goto err_free_alga_screen; |
|
573 |
|
} |
|
574 |
|
AddGeneralSocket(alga_screen->f); |
|
575 |
|
|
|
576 |
|
r = RRScreenInit(screen); |
|
577 |
|
if (!r) { |
|
578 |
|
ErrorF("unable to perform randr screen init\n"); |
|
579 |
|
goto err_remove_general_socket; |
|
580 |
|
} |
|
581 |
|
|
|
582 |
|
RRScreenSetSizeRange(screen, DISPLAYPORT_DEFAULT_WIDTH, |
|
583 |
|
DISPLAYPORT_DEFAULT_HEIGHT, DCE6_WIDTH_MAX, DCE6_HEIGHT_MAX); |
|
584 |
|
|
|
585 |
|
rr = rrGetScrPriv(screen); |
|
586 |
|
rr->rrGetInfo = alga_rrGetInfo; |
|
587 |
|
rr->rrSetConfig = alga_rrSetConfig; |
|
588 |
|
|
|
589 |
|
alga_screen->idx = 5; |
|
590 |
|
alga_screen->w = 1920; |
|
591 |
|
alga_screen->h = 1080; |
|
592 |
|
alga_screen->r = 60; |
|
593 |
|
alga_screen->pixel_fmt = ALGA_ARGB8888; |
|
594 |
|
alga_screen->stride = alga_screen->w |
|
595 |
|
* alga_pixel_fmts_sz[alga_screen->pixel_fmt]; |
|
596 |
|
snprintf(&alga_screen->mode_name[0], CSTRLEN(MODE_NAME_MAX_TMPL), |
|
597 |
|
"%ux%u@%u", alga_screen->w, alga_screen->h, alga_screen->r); |
|
598 |
|
|
|
599 |
|
alga_fb_alloc(alga_screen); |
|
600 |
|
alga_mode_set(alga_screen); |
|
601 |
|
|
|
602 |
|
alga_screen->randr_crtc = RRCrtcCreate(screen, alga_screen); |
|
603 |
|
if (!alga_screen->randr_crtc) { |
|
604 |
|
ErrorF("unable to create randr crtc\n"); |
|
605 |
|
goto err_free_fb; |
|
606 |
|
} |
|
607 |
|
|
|
608 |
|
#define OUTPUT_NAME "hardcoded_output0" |
|
609 |
|
alga_screen->randr_output = RROutputCreate(screen, OUTPUT_NAME, |
|
610 |
|
sizeof(OUTPUT_NAME), alga_screen); |
|
611 |
|
if (!alga_screen->randr_output) { |
|
612 |
|
ErrorF("unable to create randr output\n"); |
|
613 |
|
goto err_destroy_randr_crtc; |
|
614 |
|
} |
|
615 |
|
|
|
616 |
|
r = RRCrtcGammaSetSize(alga_screen->randr_crtc, 256); |
|
617 |
|
if (!r) { |
|
618 |
|
ErrorF("unable to setup randr crtc gamma size\n"); |
|
619 |
|
goto err_destroy_randr_output; |
|
620 |
|
} |
|
621 |
|
|
|
622 |
|
r = RROutputSetCrtcs(alga_screen->randr_output, &alga_screen->randr_crtc, |
|
623 |
|
1); |
|
624 |
|
if (!r) { |
|
625 |
|
ErrorF("unable to setup randr crtc for the output\n"); |
|
626 |
|
goto err_destroy_randr_output; |
|
627 |
|
} |
|
628 |
|
|
|
629 |
|
r = RROutputSetConnection(alga_screen->randr_output, RR_Connected); |
|
630 |
|
if (!r) { |
|
631 |
|
ErrorF("unable to set randr connected state of the output\n"); |
|
632 |
|
goto err_destroy_randr_output; |
|
633 |
|
} |
|
634 |
|
|
|
635 |
|
memset(&mode_info, 0, sizeof(mode_info)); |
|
636 |
|
mode_info.width = alga_screen->w; |
|
637 |
|
mode_info.height = alga_screen->h; |
|
638 |
|
/* we presume Hz here */ |
|
639 |
|
mode_info.dotClock = alga_screen->w * alga_screen->h * alga_screen->r; |
|
640 |
|
mode_info.hSyncStart = alga_screen->w; |
|
641 |
|
mode_info.hSyncEnd = alga_screen->w; |
|
642 |
|
mode_info.hTotal = alga_screen->w; |
|
643 |
|
mode_info.hSkew = 0; |
|
644 |
|
mode_info.vSyncStart = alga_screen->h; |
|
645 |
|
mode_info.vSyncEnd = alga_screen->h; |
|
646 |
|
mode_info.vTotal = alga_screen->h; |
|
647 |
|
|
|
648 |
|
mode_info.nameLength = strlen(&alga_screen->mode_name[0]) + 1; |
|
649 |
|
randr_mode = RRModeGet(&mode_info, &alga_screen->mode_name[0]); |
|
650 |
|
|
|
651 |
|
r = RROutputSetModes(alga_screen->randr_output, &randr_mode, 1, 1); |
|
652 |
|
if (!r) { |
|
653 |
|
ErrorF("unable to setup the randr modes of the output\n"); |
|
654 |
|
goto err_destroy_randr_output; |
|
655 |
|
} |
|
656 |
|
|
|
657 |
|
r = RRCrtcNotify(alga_screen->randr_crtc, randr_mode, 0, 0, RR_Rotate_0, |
|
658 |
|
NULL, 1, &alga_screen->randr_output); |
|
659 |
|
if (!r) { |
|
660 |
|
ErrorF("unable to setup the randr crtc for the output mode\n"); |
|
661 |
|
goto err_destroy_randr_output; |
|
662 |
|
} |
|
663 |
|
|
|
664 |
|
screen->width = alga_screen->w; |
|
665 |
|
screen->height = alga_screen->h; |
|
666 |
|
/* FIXME: no root window yet for RRScreenSizeNotify(screen) */ |
|
667 |
|
/*========================================================================*/ |
|
668 |
|
|
|
669 |
|
/* target ARGB8888 as default */ |
|
670 |
|
if (alga_screen->pixel_fmt != ALGA_ARGB8888) { |
|
671 |
|
ErrorF("don't handle pixel format other than ALGA_ARGB8888\n"); |
|
672 |
|
goto err_destroy_randr_output; |
|
673 |
|
} |
|
674 |
|
|
|
675 |
|
r = miSetVisualTypesAndMasks(24, 1 << TrueColor, 8, TrueColor, 0x00ff0000, |
|
676 |
|
0x0000ff00, 0x000000ff); |
|
677 |
|
if (!r) { |
|
678 |
|
ErrorF("unable to perform mi visual init\n"); |
|
679 |
|
goto err_destroy_randr_output; |
|
680 |
|
} |
|
681 |
|
|
|
682 |
|
r = miSetPixmapDepths(); |
|
683 |
|
if (!r) { |
|
684 |
|
ErrorF("unable to perform mi pixmap depth init\n"); |
|
685 |
|
goto err_destroy_randr_output; |
|
686 |
|
} |
|
687 |
|
|
|
688 |
|
/* |
|
689 |
|
* XXX: we force the fbScreenInit code path *not* to put a pixmap |
|
690 |
|
* in screen->devPrivate, since we will use it for our framebuffer |
|
691 |
|
*/ |
|
692 |
|
r = fbScreenInit(screen, NULL, screen->width, screen->height, X_DPI_DEFAULT, |
|
693 |
|
Y_DPI_DEFAULT, |
|
694 |
|
0, /* no pixmap provided */ |
|
695 |
|
32); |
|
696 |
|
if (!r) { |
|
697 |
|
ErrorF("unable to perform frame buffer helper init\n"); |
|
698 |
|
goto err_destroy_randr_output; |
|
699 |
|
} |
|
700 |
|
|
|
701 |
|
r = fbPictureInit(screen, 0, 0); |
|
702 |
|
if (!r) { |
|
703 |
|
ErrorF("unable to perform frame buffer helper picture init\n"); |
|
704 |
|
goto err_destroy_randr_output; |
|
705 |
|
} |
|
706 |
|
|
|
707 |
|
screen->CreatePixmap = pixmap_create; |
|
708 |
|
screen->DestroyPixmap = pixmap_destroy; |
|
709 |
|
|
|
710 |
|
screen->SaveScreen = screen_save; |
|
711 |
|
|
|
712 |
|
screen->blackPixel = 0; |
|
713 |
|
screen->whitePixel = 1; |
|
714 |
|
|
|
715 |
|
/* XXX: must be setup *before* the color map */ |
|
716 |
|
r = miDCInitialize(screen, &alga_pointer_screen_funcs); |
|
717 |
|
if (!r) { |
|
718 |
|
ErrorF("unable to init pointer support\n"); |
|
719 |
|
goto err_destroy_randr_output; |
|
720 |
|
} |
|
721 |
|
|
|
722 |
|
r = fbCreateDefColormap(screen); |
|
723 |
|
if (!r) { |
|
724 |
|
ErrorF("unable to perform the frame buffer helper color map init\n"); |
|
725 |
|
goto err_destroy_randr_output; |
|
726 |
|
} |
|
727 |
|
|
|
728 |
|
/*------------------------------------------------------------------------*/ |
|
729 |
|
/* chain our funcs with the other subsystems */ |
|
730 |
|
alga_screen->CreateScreenResources = screen->CreateScreenResources; |
|
731 |
|
screen->CreateScreenResources = alga_CreateScreenResources; |
|
732 |
|
|
|
733 |
|
alga_screen->CloseScreen = screen->CloseScreen; |
|
734 |
|
screen->CloseScreen = alga_CloseScreen; |
|
735 |
|
|
|
736 |
|
alga_screen->BlockHandler = screen->BlockHandler; |
|
737 |
|
screen->BlockHandler = alga_BlockHandler; |
|
738 |
|
|
|
739 |
|
alga_screen->WakeupHandler = screen->WakeupHandler; |
|
740 |
|
screen->WakeupHandler = alga_WakeupHandler; |
|
741 |
|
|
|
742 |
|
alga_screen->RealizeWindow = screen->RealizeWindow; |
|
743 |
|
screen->RealizeWindow = alga_RealizeWindow; |
|
744 |
|
/*------------------------------------------------------------------------*/ |
|
745 |
|
|
|
746 |
|
alga_screen_set_private(screen, alga_screen); |
|
747 |
|
fb_flip_schedule(screen, FALSE); |
|
748 |
|
return TRUE; |
|
749 |
|
|
|
750 |
|
/*========================================================================*/ |
|
751 |
|
err_destroy_randr_output: |
|
752 |
|
RROutputDestroy(alga_screen->randr_output); |
|
753 |
|
|
|
754 |
|
err_destroy_randr_crtc: |
|
755 |
|
RRCrtcDestroy(alga_screen->randr_crtc); |
|
756 |
|
|
|
757 |
|
err_free_fb: |
|
758 |
|
alga_fb_free(alga_screen); |
|
759 |
|
|
|
760 |
|
err_remove_general_socket: |
|
761 |
|
RemoveGeneralSocket(alga_screen->f); |
|
762 |
|
close(alga_screen->f); |
|
763 |
|
/*========================================================================*/ |
|
764 |
|
|
|
765 |
|
err_free_alga_screen: |
|
766 |
|
free(alga_screen); |
|
767 |
|
|
|
768 |
|
err: |
|
769 |
|
ErrorF("failed to init default screen\n"); |
|
770 |
|
return FALSE; |
|
771 |
|
} |
|
772 |
|
|
|
773 |
|
static void |
|
774 |
|
fb_dma_to_device(ScreenPtr screen, Bool visible) |
|
775 |
|
{ |
|
776 |
|
struct alga_screen *alga_screen; |
|
777 |
|
PixmapPtr screen_pixmap; |
|
778 |
|
struct alga_pixmap *alga_screen_pixmap; |
|
779 |
|
/*----*/ |
|
780 |
|
struct si_dma dma; |
|
781 |
|
struct si_dma_l2l *l2l; |
|
782 |
|
struct si_timeouts_info *t_info; |
|
783 |
|
ul req; |
|
784 |
|
si r; |
|
785 |
|
|
|
786 |
|
alga_screen = alga_screen_get(screen); |
|
787 |
|
screen_pixmap = (PixmapPtr)screen->devPrivate; |
|
788 |
|
alga_screen_pixmap = alga_pixmap_get(screen_pixmap); |
|
789 |
|
|
|
790 |
|
l2l = &dma.params.l2l; |
|
791 |
|
t_info = &dma.t_info; |
|
792 |
|
|
|
793 |
|
dma.type = SI_DMA_TYPE_L2L; |
|
794 |
|
dma.dir=SI_DMA_TO_DEVICE; |
|
795 |
|
|
|
796 |
|
/* we don't really care here lets put one seconde! */ |
|
797 |
|
t_info->ring.n_max = 1; |
|
798 |
|
t_info->ring.us = 1000000; |
|
799 |
|
t_info->fence.n_max = 1; |
|
800 |
|
t_info->fence.us = 1000000; |
|
801 |
|
|
|
802 |
|
l2l->src_addr = (u64)alga_screen_pixmap->data; |
|
803 |
|
if (visible) |
|
804 |
|
l2l->dst_addr = alga_screen->fb_gpu_addr_visible; |
|
805 |
|
else |
|
806 |
|
l2l->dst_addr = alga_screen->fb_gpu_addr_hidden; |
|
807 |
|
l2l->sz = alga_screen_pixmap->data_sz; |
|
808 |
|
|
|
809 |
|
req = _IOW('d', SI_DMA, dma); |
|
810 |
|
|
|
811 |
|
errno = 0; |
|
812 |
|
r = ioctl(alga_screen->f, req, &dma); |
|
813 |
|
switch (r) { |
|
814 |
|
case -1: |
|
815 |
|
FatalError("%s:dma l2l failed:%s\n", __func__, strerror(errno)); |
|
816 |
|
case SI_RING_TIMEOUT: |
|
817 |
|
FatalError("%s:dma l2l failed:ring timeout\n", __func__); |
|
818 |
|
case SI_FENCE_TIMEOUT: |
|
819 |
|
FatalError("%s:dma l2l failed:fence timeout\n", __func__); |
|
820 |
|
} |
|
821 |
|
} |
|
822 |
|
|
|
823 |
|
static void |
|
824 |
|
si_evts_process(ScreenPtr screen, Bool flip_fbs) |
|
825 |
|
{ |
|
826 |
|
struct alga_screen *alga_screen; |
|
827 |
|
struct si_evt si_evt; |
|
828 |
|
ssize_t rd; |
|
829 |
|
|
|
830 |
|
alga_screen = alga_screen_get(screen); |
|
831 |
|
|
|
832 |
|
while (1) { |
|
833 |
|
errno = 0; |
|
834 |
|
/* the driver sends whole events in order */ |
|
835 |
|
rd = read(alga_screen->f, &si_evt, sizeof(si_evt)); |
|
836 |
|
|
|
837 |
|
if (rd == -1) { |
|
838 |
|
if (errno == EINTR) |
|
839 |
|
continue; |
|
840 |
|
|
|
841 |
|
if (errno == EAGAIN || errno == EWOULDBLOCK) { |
|
842 |
|
return; /* no more events with a non blocking fd */ |
|
843 |
|
} |
|
844 |
|
|
|
845 |
|
FatalError("an error occured while reading the page flip event\n"); |
|
846 |
|
} |
|
847 |
|
|
|
848 |
|
if (!flip_fbs) |
|
849 |
|
continue; |
|
850 |
|
|
|
851 |
|
if (alga_screen->fb_gpu_addr_visible == alga_screen->fb_gpu_addr_front) { |
|
852 |
|
alga_screen->fb_gpu_addr_visible = alga_screen->fb_gpu_addr_back; |
|
853 |
|
alga_screen->fb_gpu_addr_hidden = alga_screen->fb_gpu_addr_front; |
|
854 |
|
} else { |
|
855 |
|
alga_screen->fb_gpu_addr_visible = alga_screen->fb_gpu_addr_front; |
|
856 |
|
alga_screen->fb_gpu_addr_hidden = alga_screen->fb_gpu_addr_back; |
|
857 |
|
} |
|
858 |
|
} |
|
859 |
|
} |
|
860 |
|
|
|
861 |
|
static void |
|
862 |
|
fb_flip_schedule(ScreenPtr screen, Bool retry_on_pending) |
|
863 |
|
{ |
|
864 |
|
struct alga_screen *alga_screen; |
|
865 |
|
u8 idx; |
|
866 |
|
|
|
867 |
|
alga_screen = alga_screen_get(screen); |
|
868 |
|
idx = alga_screen->idx; |
|
869 |
|
|
|
870 |
|
while (1) { |
|
871 |
|
ul req; |
|
872 |
|
int r; |
|
873 |
|
|
|
874 |
|
req = _IOW('d', SI_DCE_PF, idx); |
|
875 |
|
errno = 0; |
|
876 |
|
r = ioctl(alga_screen->f, req, &idx); |
|
877 |
|
|
|
878 |
|
switch (r) { |
|
879 |
|
case SI_DCE_PF_PENDING: |
|
880 |
|
if (retry_on_pending) |
|
881 |
|
continue; |
|
882 |
|
else |
|
883 |
|
FatalError("%s:a page flip is already pending\n", __func__); |
|
884 |
|
case 0: |
|
885 |
|
return; |
|
886 |
|
case -1: |
|
887 |
|
default: |
|
888 |
|
FatalError("%s:error while scheduling a flip\n", __func__); |
|
889 |
|
} |
|
890 |
|
} |
|
891 |
|
} |
|
892 |
|
|
|
893 |
|
/* |
|
894 |
|
* XXX: properly handling errors to make the code path robust is a **huge** |
|
895 |
|
* task. Several displays per screen with a "not abort all on error" policy is |
|
896 |
|
* really a daunting task. It is very likely that the code paths would become |
|
897 |
|
* quite complex. |
|
898 |
|
*/ |
|
899 |
|
static void |
|
900 |
|
alga_BlockHandler(ScreenPtr pScreen, void *pTimeout, void *pReadmask) |
|
901 |
|
{ |
|
902 |
|
struct alga_screen *alga_screen; |
|
903 |
|
alga_screen = alga_screen_get(pScreen); |
|
904 |
|
|
|
905 |
|
if (alga_screen->fb_dma_do) { |
|
906 |
|
alga_screen->fb_dma_do = FALSE; |
|
907 |
|
|
|
908 |
|
if (!alga_screen->dpm_on) { |
|
909 |
|
fb_dma_to_device(pScreen, FALSE); |
|
910 |
|
|
|
911 |
|
fb_flip_schedule(pScreen, TRUE); |
|
912 |
|
alga_screen->flip_evts_expected = TRUE; |
|
913 |
|
} |
|
914 |
|
} |
|
915 |
|
} |
|
916 |
|
|
|
917 |
|
static void |
|
918 |
|
alga_WakeupHandler(ScreenPtr pScreen, unsigned long result, void *pReadMask) |
|
919 |
|
{ |
|
920 |
|
struct alga_screen *alga_screen; |
|
921 |
|
fd_set *general_sockets_rd; |
|
922 |
|
|
|
923 |
|
alga_screen = alga_screen_get(pScreen); |
|
924 |
|
general_sockets_rd = (fd_set *)pReadMask; |
|
925 |
|
|
|
926 |
|
if (FD_ISSET(alga_screen->f, general_sockets_rd)) { |
|
927 |
|
si_evts_process(pScreen, TRUE); |
|
928 |
|
alga_screen->flip_evts_expected = FALSE; |
|
929 |
|
alga_screen->fb_dma_do = TRUE; |
|
930 |
|
} |
|
931 |
|
} |