1 /*
2 * Copyright 2006-2018, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 */
8
9
10 #include "driver.h"
11 #include "device.h"
12 #include "intel_extreme.h"
13 #include "utility.h"
14
15 #include <OS.h>
16 #include <KernelExport.h>
17 #include <Drivers.h>
18 #include <PCI.h>
19 #include <SupportDefs.h>
20 #include <graphic_driver.h>
21 #include <image.h>
22
23 #include <stdlib.h>
24 #include <string.h>
25
26
27 #define DEBUG_COMMANDS
28
29 #define TRACE_DEVICE
30 #ifdef TRACE_DEVICE
31 # define TRACE(x...) dprintf("intel_extreme: " x)
32 #else
33 # define TRACE(x) ;
34 #endif
35
36 #define ERROR(x...) dprintf("intel_extreme: " x)
37 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
38
39
40 /* device hooks prototypes */
41
42 static status_t device_open(const char* name, uint32 flags, void** _cookie);
43 static status_t device_close(void* data);
44 static status_t device_free(void* data);
45 static status_t device_ioctl(void* data, uint32 opcode, void* buffer,
46 size_t length);
47 static status_t device_read(void* data, off_t offset, void* buffer,
48 size_t* length);
49 static status_t device_write(void* data, off_t offset, const void* buffer,
50 size_t* length);
51
52
53 device_hooks gDeviceHooks = {
54 device_open,
55 device_close,
56 device_free,
57 device_ioctl,
58 device_read,
59 device_write,
60 NULL,
61 NULL,
62 NULL,
63 NULL
64 };
65
66
67 #ifdef DEBUG_COMMANDS
68 static int
getset_register(int argc,char ** argv)69 getset_register(int argc, char** argv)
70 {
71 if (argc < 2 || argc > 3) {
72 kprintf("usage: %s <register> [set-to-value]\n", argv[0]);
73 return 0;
74 }
75
76 uint32 reg = parse_expression(argv[1]);
77 uint32 value = 0;
78 bool set = argc == 3;
79 if (set)
80 value = parse_expression(argv[2]);
81
82 kprintf("intel_extreme register %#" B_PRIx32 "\n", reg);
83
84 intel_info &info = *gDeviceInfo[0];
85 uint32 oldValue = read32(info, reg);
86
87 kprintf(" %svalue: %#" B_PRIx32 " (%" B_PRIu32 ")\n", set ? "old " : "",
88 oldValue, oldValue);
89
90 if (set) {
91 write32(info, reg, value);
92
93 value = read32(info, reg);
94 kprintf(" new value: %#" B_PRIx32 " (%" B_PRIu32 ")\n", value, value);
95 }
96
97 return 0;
98 }
99
100
101 static int
dump_pipe_info(int argc,char ** argv)102 dump_pipe_info(int argc, char** argv)
103 {
104 int pipeOffset = 0;
105
106 if (argc > 2) {
107 kprintf("usage: %s [pipe index]\n", argv[0]);
108 return 0;
109 }
110
111 if (argc > 1) {
112 uint32 pipe = parse_expression(argv[1]);
113 if (pipe != 0)
114 pipeOffset = INTEL_DISPLAY_OFFSET; // Use pipe B if requested
115 }
116
117 intel_info &info = *gDeviceInfo[0];
118 uint32 value;
119
120 kprintf("intel_extreme pipe configuration:\n");
121
122 value = read32(info, INTEL_DISPLAY_A_HTOTAL + pipeOffset);
123 kprintf(" HTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
124 (value & 0xFFFF) + 1, (value >> 16) + 1);
125 value = read32(info, INTEL_DISPLAY_A_HBLANK + pipeOffset);
126 kprintf(" HBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
127 (value & 0xFFFF) + 1, (value >> 16) + 1);
128 value = read32(info, INTEL_DISPLAY_A_HSYNC + pipeOffset);
129 kprintf(" HSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
130 (value & 0xFFFF) + 1, (value >> 16) + 1);
131 value = read32(info, INTEL_DISPLAY_A_VTOTAL + pipeOffset);
132 kprintf(" VTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
133 (value & 0xFFFF) + 1, (value >> 16) + 1);
134 value = read32(info, INTEL_DISPLAY_A_VBLANK + pipeOffset);
135 kprintf(" VBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
136 (value & 0xFFFF) + 1, (value >> 16) + 1);
137 value = read32(info, INTEL_DISPLAY_A_VSYNC + pipeOffset);
138 kprintf(" VSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
139 (value & 0xFFFF) + 1, (value >> 16) + 1);
140 value = read32(info, INTEL_DISPLAY_A_PIPE_SIZE + pipeOffset);
141 kprintf(" SIZE %" B_PRIu32 "x%" B_PRIu32 "\n",
142 (value & 0xFFFF) + 1, (value >> 16) + 1);
143
144 if (info.pch_info != INTEL_PCH_NONE) {
145 kprintf("intel_extreme transcoder configuration:\n");
146
147 value = read32(info, INTEL_TRANSCODER_A_HTOTAL + pipeOffset);
148 kprintf(" HTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
149 (value & 0xFFFF) + 1, (value >> 16) + 1);
150 value = read32(info, INTEL_TRANSCODER_A_HBLANK + pipeOffset);
151 kprintf(" HBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
152 (value & 0xFFFF) + 1, (value >> 16) + 1);
153 value = read32(info, INTEL_TRANSCODER_A_HSYNC + pipeOffset);
154 kprintf(" HSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
155 (value & 0xFFFF) + 1, (value >> 16) + 1);
156 value = read32(info, INTEL_TRANSCODER_A_VTOTAL + pipeOffset);
157 kprintf(" VTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
158 (value & 0xFFFF) + 1, (value >> 16) + 1);
159 value = read32(info, INTEL_TRANSCODER_A_VBLANK + pipeOffset);
160 kprintf(" VBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
161 (value & 0xFFFF) + 1, (value >> 16) + 1);
162 value = read32(info, INTEL_TRANSCODER_A_VSYNC + pipeOffset);
163 kprintf(" VSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
164 (value & 0xFFFF) + 1, (value >> 16) + 1);
165 value = read32(info, INTEL_TRANSCODER_A_IMAGE_SIZE + pipeOffset);
166 kprintf(" SIZE %" B_PRIu32 "x%" B_PRIu32 "\n",
167 (value & 0xFFFF) + 1, (value >> 16) + 1);
168 }
169
170 kprintf("intel_extreme display plane configuration:\n");
171
172 value = read32(info, INTEL_DISPLAY_A_CONTROL + pipeOffset);
173 kprintf(" CONTROL: %" B_PRIx32 "\n", value);
174 value = read32(info, INTEL_DISPLAY_A_BASE + pipeOffset);
175 kprintf(" BASE: %" B_PRIx32 "\n", value);
176 value = read32(info, INTEL_DISPLAY_A_BYTES_PER_ROW + pipeOffset);
177 kprintf(" BYTES_PER_ROW: %" B_PRIx32 "\n", value);
178 value = read32(info, INTEL_DISPLAY_A_SURFACE + pipeOffset);
179 kprintf(" SURFACE: %" B_PRIx32 "\n", value);
180
181 return 0;
182 }
183
184 #endif // DEBUG_COMMANDS
185
186
187 // #pragma mark - Device Hooks
188
189
190 static status_t
device_open(const char * name,uint32,void ** _cookie)191 device_open(const char* name, uint32 /*flags*/, void** _cookie)
192 {
193 CALLED();
194 int32 id;
195
196 // find accessed device
197 {
198 char* thisName;
199
200 // search for device name
201 for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) {
202 if (!strcmp(name, thisName))
203 break;
204 }
205 if (!thisName)
206 return B_BAD_VALUE;
207 }
208
209 intel_info* info = gDeviceInfo[id];
210
211 mutex_lock(&gLock);
212
213 if (info->open_count == 0) {
214 // This device hasn't been initialized yet, so we
215 // allocate needed resources and initialize the structure
216 info->init_status = intel_extreme_init(*info);
217 if (info->init_status == B_OK) {
218 #ifdef DEBUG_COMMANDS
219 add_debugger_command("ie_reg", getset_register,
220 "dumps or sets the specified intel_extreme register");
221 add_debugger_command("ie_pipe", dump_pipe_info,
222 "show pipe configuration information");
223 #endif
224 }
225 }
226
227 if (info->init_status == B_OK) {
228 info->open_count++;
229 *_cookie = info;
230 } else
231 ERROR("%s: initialization failed!\n", __func__);
232
233 mutex_unlock(&gLock);
234
235 return info->init_status;
236 }
237
238
239 static status_t
device_close(void *)240 device_close(void* /*data*/)
241 {
242 CALLED();
243 return B_OK;
244 }
245
246
247 static status_t
device_free(void * data)248 device_free(void* data)
249 {
250 struct intel_info* info = (intel_info*)data;
251
252 mutex_lock(&gLock);
253
254 if (info->open_count-- == 1) {
255 // release info structure
256 info->init_status = B_NO_INIT;
257 intel_extreme_uninit(*info);
258
259 #ifdef DEBUG_COMMANDS
260 remove_debugger_command("ie_reg", getset_register);
261 remove_debugger_command("ie_pipe", dump_pipe_info);
262 #endif
263 }
264
265 mutex_unlock(&gLock);
266 return B_OK;
267 }
268
269
270 static status_t
device_ioctl(void * data,uint32 op,void * buffer,size_t bufferLength)271 device_ioctl(void* data, uint32 op, void* buffer, size_t bufferLength)
272 {
273 struct intel_info* info = (intel_info*)data;
274
275 switch (op) {
276 case B_GET_ACCELERANT_SIGNATURE:
277 TRACE("accelerant: %s\n", INTEL_ACCELERANT_NAME);
278 if (user_strlcpy((char*)buffer, INTEL_ACCELERANT_NAME,
279 bufferLength) < B_OK)
280 return B_BAD_ADDRESS;
281 return B_OK;
282
283 // needed to share data between kernel and accelerant
284 case INTEL_GET_PRIVATE_DATA:
285 {
286 intel_get_private_data data;
287 if (user_memcpy(&data, buffer, sizeof(intel_get_private_data)) < B_OK)
288 return B_BAD_ADDRESS;
289
290 if (data.magic == INTEL_PRIVATE_DATA_MAGIC) {
291 data.shared_info_area = info->shared_area;
292 return user_memcpy(buffer, &data,
293 sizeof(intel_get_private_data));
294 }
295 break;
296 }
297
298 // needed for cloning
299 case INTEL_GET_DEVICE_NAME:
300 if (user_strlcpy((char* )buffer, gDeviceNames[info->id],
301 bufferLength) < B_OK)
302 return B_BAD_ADDRESS;
303 return B_OK;
304
305 // graphics mem manager
306 case INTEL_ALLOCATE_GRAPHICS_MEMORY:
307 {
308 intel_allocate_graphics_memory allocMemory;
309 if (user_memcpy(&allocMemory, buffer,
310 sizeof(intel_allocate_graphics_memory)) < B_OK)
311 return B_BAD_ADDRESS;
312
313 if (allocMemory.magic != INTEL_PRIVATE_DATA_MAGIC)
314 return B_BAD_VALUE;
315
316 status_t status = intel_allocate_memory(*info, allocMemory.size,
317 allocMemory.alignment, allocMemory.flags,
318 &allocMemory.buffer_base);
319 if (status == B_OK) {
320 // copy result
321 if (user_memcpy(buffer, &allocMemory,
322 sizeof(intel_allocate_graphics_memory)) < B_OK)
323 return B_BAD_ADDRESS;
324 }
325 return status;
326 }
327
328 case INTEL_FREE_GRAPHICS_MEMORY:
329 {
330 intel_free_graphics_memory freeMemory;
331 if (user_memcpy(&freeMemory, buffer,
332 sizeof(intel_free_graphics_memory)) < B_OK)
333 return B_BAD_ADDRESS;
334
335 if (freeMemory.magic == INTEL_PRIVATE_DATA_MAGIC)
336 return intel_free_memory(*info, freeMemory.buffer_base);
337 break;
338 }
339
340 case INTEL_GET_BRIGHTNESS_LEGACY:
341 case INTEL_SET_BRIGHTNESS_LEGACY:
342 {
343 intel_brightness_legacy brightnessLegacy;
344 if (user_memcpy(&brightnessLegacy, buffer,
345 sizeof(brightnessLegacy)) < B_OK)
346 return B_BAD_ADDRESS;
347
348 if (brightnessLegacy.magic != INTEL_PRIVATE_DATA_MAGIC)
349 break;
350 if (op == INTEL_GET_BRIGHTNESS_LEGACY) {
351 brightnessLegacy.lpc = get_pci_config(info->pci, LEGACY_BACKLIGHT_BRIGHTNESS, 1);
352 // copy result
353 if (user_memcpy(buffer, &brightnessLegacy, sizeof(brightnessLegacy)) < B_OK)
354 return B_BAD_ADDRESS;
355 } else {
356 set_pci_config(info->pci, LEGACY_BACKLIGHT_BRIGHTNESS, 1, brightnessLegacy.lpc);
357 }
358 return B_OK;
359 }
360
361 default:
362 ERROR("ioctl() unknown message %" B_PRIu32 " (length = %"
363 B_PRIuSIZE ")\n", op, bufferLength);
364 break;
365 }
366
367 return B_DEV_INVALID_IOCTL;
368 }
369
370
371 static status_t
device_read(void *,off_t,void *,size_t * _length)372 device_read(void* /*data*/, off_t /*pos*/, void* /*buffer*/, size_t* _length)
373 {
374 *_length = 0;
375 return B_NOT_ALLOWED;
376 }
377
378
379 static status_t
device_write(void *,off_t,const void *,size_t * _length)380 device_write(void* /*data*/, off_t /*pos*/, const void* /*buffer*/,
381 size_t* _length)
382 {
383 *_length = 0;
384 return B_NOT_ALLOWED;
385 }
386
387