ec15a2bd3db71a7edd571a30297e9bb20bf1f90a
[reactos.git] / reactos / drivers / video / miniport / xboxvmp / xboxvmp.c
1 /*
2 * ReactOS Xbox miniport video driver
3 * Copyright (C) 2004 Gé van Geldorp
4 *
5 * Based on VBE miniport video driver
6 * Copyright (C) 2004 Filip Navara
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * TODO:
23 * - Check input parameters everywhere.
24 * - Call VideoPortVerifyAccessRanges to reserve the memory we're about
25 * to map.
26 */
27
28 /* INCLUDES *******************************************************************/
29
30 #include "xboxvmp.h"
31
32 #define I2C_IO_BASE 0xc000
33
34 #define CONTROL_FRAMEBUFFER_ADDRESS_OFFSET 0x600800
35
36 /* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/
37
38 VP_STATUS STDCALL
39 DriverEntry(IN PVOID Context1, IN PVOID Context2)
40 {
41 VIDEO_HW_INITIALIZATION_DATA InitData;
42
43 VideoPortZeroMemory(&InitData, sizeof(InitData));
44 InitData.AdapterInterfaceType = PCIBus;
45 InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
46 InitData.HwFindAdapter = XboxVmpFindAdapter;
47 InitData.HwInitialize = XboxVmpInitialize;
48 InitData.HwStartIO = XboxVmpStartIO;
49 InitData.HwResetHw = XboxVmpResetHw;
50 InitData.HwGetPowerState = XboxVmpGetPowerState;
51 InitData.HwSetPowerState = XboxVmpSetPowerState;
52 InitData.HwDeviceExtensionSize = sizeof(XBOXVMP_DEVICE_EXTENSION);
53
54 return VideoPortInitialize(Context1, Context2, &InitData, NULL);
55 }
56
57 /*
58 * XboxVmpFindAdapter
59 *
60 * Detects the Xbox Nvidia display adapter.
61 */
62
63 VP_STATUS STDCALL
64 XboxVmpFindAdapter(
65 IN PVOID HwDeviceExtension,
66 IN PVOID HwContext,
67 IN PWSTR ArgumentString,
68 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
69 OUT PUCHAR Again)
70 {
71 PXBOXVMP_DEVICE_EXTENSION XboxVmpDeviceExtension;
72 VIDEO_ACCESS_RANGE AccessRanges[3];
73 VP_STATUS Status;
74
75 VideoPortDebugPrint(Trace, "XboxVmpFindAdapter\n");
76
77 XboxVmpDeviceExtension = (PXBOXVMP_DEVICE_EXTENSION) HwDeviceExtension;
78 Status = VideoPortGetAccessRanges(HwDeviceExtension, 0, NULL, 3, AccessRanges,
79 NULL, NULL, NULL);
80
81 if (NO_ERROR == Status)
82 {
83 XboxVmpDeviceExtension->PhysControlStart = AccessRanges[0].RangeStart;
84 XboxVmpDeviceExtension->ControlLength = AccessRanges[0].RangeLength;
85 XboxVmpDeviceExtension->PhysFrameBufferStart = AccessRanges[1].RangeStart;
86 }
87
88 return Status;
89 }
90
91 /*
92 * XboxVmpInitialize
93 *
94 * Performs the first initialization of the adapter, after the HAL has given
95 * up control of the video hardware to the video port driver.
96 */
97
98 BOOLEAN STDCALL
99 XboxVmpInitialize(PVOID HwDeviceExtension)
100 {
101 PXBOXVMP_DEVICE_EXTENSION XboxVmpDeviceExtension;
102 ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY;
103 ULONG Length;
104
105 VideoPortDebugPrint(Trace, "XboxVmpInitialize\n");
106
107 XboxVmpDeviceExtension = (PXBOXVMP_DEVICE_EXTENSION) HwDeviceExtension;
108
109 Length = XboxVmpDeviceExtension->ControlLength;
110 XboxVmpDeviceExtension->VirtControlStart = NULL;
111 if (NO_ERROR != VideoPortMapMemory(HwDeviceExtension,
112 XboxVmpDeviceExtension->PhysControlStart,
113 &Length, &inIoSpace,
114 &XboxVmpDeviceExtension->VirtControlStart))
115 {
116 VideoPortDebugPrint(Error, "Failed to map control memory\n");
117 return FALSE;
118 }
119 VideoPortDebugPrint(Info, "Mapped 0x%x bytes of control mem at 0x%x to virt addr 0x%x\n",
120 XboxVmpDeviceExtension->ControlLength,
121 XboxVmpDeviceExtension->PhysControlStart.u.LowPart,
122 XboxVmpDeviceExtension->VirtControlStart);
123
124 return TRUE;
125 }
126
127 /*
128 * XboxVmpStartIO
129 *
130 * Processes the specified Video Request Packet.
131 */
132
133 BOOLEAN STDCALL
134 XboxVmpStartIO(
135 PVOID HwDeviceExtension,
136 PVIDEO_REQUEST_PACKET RequestPacket)
137 {
138 BOOL Result;
139
140 RequestPacket->StatusBlock->Status = STATUS_UNSUCCESSFUL;
141
142 switch (RequestPacket->IoControlCode)
143 {
144 case IOCTL_VIDEO_SET_CURRENT_MODE:
145 VideoPortDebugPrint(Trace, "XboxVmpStartIO IOCTL_VIDEO_SET_CURRENT_MODE\n");
146 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
147 {
148 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
149 return TRUE;
150 }
151 Result = XboxVmpSetCurrentMode(
152 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
153 (PVIDEO_MODE)RequestPacket->InputBuffer,
154 RequestPacket->StatusBlock);
155 break;
156
157 case IOCTL_VIDEO_RESET_DEVICE:
158 VideoPortDebugPrint(Trace, "XboxVmpStartIO IOCTL_VIDEO_RESET_DEVICE\n");
159 Result = XboxVmpResetDevice(
160 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
161 RequestPacket->StatusBlock);
162 break;
163
164 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
165 VideoPortDebugPrint(Trace, "XboxVmpStartIO IOCTL_VIDEO_MAP_VIDEO_MEMORY\n");
166 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
167 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
168 {
169 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
170 return TRUE;
171 }
172 Result = XboxVmpMapVideoMemory(
173 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
174 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
175 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
176 RequestPacket->StatusBlock);
177 break;
178
179 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
180 VideoPortDebugPrint(Trace, "XboxVmpStartIO IOCTL_VIDEO_UNMAP_VIDEO_MEMORY\n");
181 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
182 {
183 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
184 return TRUE;
185 }
186 Result = XboxVmpUnmapVideoMemory(
187 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
188 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
189 RequestPacket->StatusBlock);
190 break;
191
192 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
193 VideoPortDebugPrint(Trace, "XboxVmpStartIO IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES\n");
194 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
195 {
196 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
197 return TRUE;
198 }
199 Result = XboxVmpQueryNumAvailModes(
200 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
201 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
202 RequestPacket->StatusBlock);
203 break;
204
205 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
206 VideoPortDebugPrint(Trace, "XboxVmpStartIO IOCTL_VIDEO_QUERY_AVAIL_MODES\n");
207 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
208 {
209 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
210 return TRUE;
211 }
212 Result = XboxVmpQueryAvailModes(
213 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
214 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
215 RequestPacket->StatusBlock);
216 break;
217
218 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
219 VideoPortDebugPrint(Trace, "XboxVmpStartIO IOCTL_VIDEO_QUERY_CURRENT_MODE\n");
220 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
221 {
222 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
223 return TRUE;
224 }
225 Result = XboxVmpQueryCurrentMode(
226 (PXBOXVMP_DEVICE_EXTENSION)HwDeviceExtension,
227 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
228 RequestPacket->StatusBlock);
229 break;
230
231 default:
232 VideoPortDebugPrint(Warn, "XboxVmpStartIO 0x%x not implemented\n");
233 RequestPacket->StatusBlock->Status = STATUS_NOT_IMPLEMENTED;
234 return FALSE;
235 }
236
237 if (Result)
238 {
239 RequestPacket->StatusBlock->Status = STATUS_SUCCESS;
240 }
241
242 return TRUE;
243 }
244
245 /*
246 * XboxVmpResetHw
247 *
248 * This function is called to reset the hardware to a known state.
249 */
250
251 BOOLEAN STDCALL
252 XboxVmpResetHw(
253 PVOID DeviceExtension,
254 ULONG Columns,
255 ULONG Rows)
256 {
257 VideoPortDebugPrint(Trace, "XboxVmpResetHw\n");
258
259 if (! XboxVmpResetDevice((PXBOXVMP_DEVICE_EXTENSION) DeviceExtension, NULL))
260 {
261 return FALSE;
262 }
263
264 return TRUE;
265 }
266
267 /*
268 * XboxVmpGetPowerState
269 *
270 * Queries whether the device can support the requested power state.
271 */
272
273 VP_STATUS STDCALL
274 XboxVmpGetPowerState(
275 PVOID HwDeviceExtension,
276 ULONG HwId,
277 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
278 {
279 VideoPortDebugPrint(Error, "XboxVmpGetPowerState is not supported\n");
280
281 return ERROR_NOT_SUPPORTED;
282 }
283
284 /*
285 * XboxVmpSetPowerState
286 *
287 * Sets the power state of the specified device
288 */
289
290 VP_STATUS STDCALL
291 XboxVmpSetPowerState(
292 PVOID HwDeviceExtension,
293 ULONG HwId,
294 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
295 {
296 VideoPortDebugPrint(Error, "XboxVmpSetPowerState not supported\n");
297
298 return ERROR_NOT_SUPPORTED;
299 }
300
301 /*
302 * VBESetCurrentMode
303 *
304 * Sets the adapter to the specified operating mode.
305 */
306
307 BOOL FASTCALL
308 XboxVmpSetCurrentMode(
309 PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
310 PVIDEO_MODE RequestedMode,
311 PSTATUS_BLOCK StatusBlock)
312 {
313 if (0 != RequestedMode->RequestedMode)
314 {
315 return FALSE;
316 }
317
318 /* Nothing to do, really. We only support a single mode and we're already
319 in that mode */
320 return TRUE;
321 }
322
323 /*
324 * XboxVmpResetDevice
325 *
326 * Resets the video hardware to the default mode, to which it was initialized
327 * at system boot.
328 */
329
330 BOOL FASTCALL
331 XboxVmpResetDevice(
332 PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
333 PSTATUS_BLOCK StatusBlock)
334 {
335 /* There is nothing to be done here */
336
337 return TRUE;
338 }
339
340 /*
341 * XboxVmpMapVideoMemory
342 *
343 * Maps the video hardware frame buffer and video RAM into the virtual address
344 * space of the requestor.
345 */
346
347 BOOL FASTCALL
348 XboxVmpMapVideoMemory(
349 PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
350 PVIDEO_MEMORY RequestedAddress,
351 PVIDEO_MEMORY_INFORMATION MapInformation,
352 PSTATUS_BLOCK StatusBlock)
353 {
354 PHYSICAL_ADDRESS FrameBuffer;
355 ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY;
356 SYSTEM_BASIC_INFORMATION BasicInfo;
357 ULONG Length;
358
359 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
360
361 FrameBuffer.u.HighPart = 0;
362 if (NT_SUCCESS(ZwQuerySystemInformation(SystemBasicInformation,
363 (PVOID) &BasicInfo,
364 sizeof(SYSTEM_BASIC_INFORMATION),
365 &Length)))
366 {
367 FrameBuffer.u.LowPart = BasicInfo.HighestPhysicalPageNumber * PAGE_SIZE;
368 }
369 else
370 {
371 VideoPortDebugPrint(Error, "ZwQueryBasicInformation failed, assuming 64MB total memory\n");
372 FrameBuffer.u.LowPart = 60 * 1024 * 1024;
373 }
374
375 FrameBuffer.QuadPart += DeviceExtension->PhysFrameBufferStart.QuadPart;
376 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
377 MapInformation->VideoRamLength = 4 * 1024 * 1024;
378 VideoPortMapMemory(DeviceExtension, FrameBuffer,
379 &MapInformation->VideoRamLength, &inIoSpace,
380 &MapInformation->VideoRamBase);
381
382 MapInformation->FrameBufferBase = MapInformation->VideoRamBase;
383 MapInformation->FrameBufferLength = MapInformation->VideoRamLength;
384
385 /* Tell the nVidia controller about the framebuffer */
386 *((PULONG)((char *) DeviceExtension->VirtControlStart + CONTROL_FRAMEBUFFER_ADDRESS_OFFSET)) = FrameBuffer.u.LowPart;
387
388 VideoPortDebugPrint(Info, "Mapped 0x%x bytes of phys mem at 0x%lx to virt addr 0x%p\n",
389 MapInformation->VideoRamLength, FrameBuffer.u.LowPart, MapInformation->VideoRamBase);
390
391 return TRUE;
392 }
393
394 /*
395 * VBEUnmapVideoMemory
396 *
397 * Releases a mapping between the virtual address space and the adapter's
398 * frame buffer and video RAM.
399 */
400
401 BOOL FASTCALL
402 XboxVmpUnmapVideoMemory(
403 PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
404 PVIDEO_MEMORY VideoMemory,
405 PSTATUS_BLOCK StatusBlock)
406 {
407 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress,
408 NULL);
409
410 return TRUE;
411 }
412
413 /*
414 * XboxVmpQueryNumAvailModes
415 *
416 * Returns the number of video modes supported by the adapter and the size
417 * in bytes of the video mode information, which can be used to allocate a
418 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
419 */
420
421 BOOL FASTCALL
422 XboxVmpQueryNumAvailModes(
423 PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
424 PVIDEO_NUM_MODES Modes,
425 PSTATUS_BLOCK StatusBlock)
426 {
427 Modes->NumModes = 1;
428 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
429 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
430 return TRUE;
431 }
432
433 static BOOL
434 ReadfromSMBus(UCHAR Address, UCHAR bRegister, UCHAR Size, ULONG *Data_to_smbus)
435 {
436 int nRetriesToLive=50;
437
438 while (0 != (VideoPortReadPortUshort((PUSHORT) (I2C_IO_BASE + 0)) & 0x0800))
439 {
440 ; /* Franz's spin while bus busy with any master traffic */
441 }
442
443 while (0 != nRetriesToLive--)
444 {
445 UCHAR b;
446 int temp;
447
448 VideoPortWritePortUchar((PUCHAR) (I2C_IO_BASE + 4), (Address << 1) | 1);
449 VideoPortWritePortUchar((PUCHAR) (I2C_IO_BASE + 8), bRegister);
450
451 temp = VideoPortReadPortUshort((PUSHORT) (I2C_IO_BASE + 0));
452 VideoPortWritePortUshort((PUSHORT) (I2C_IO_BASE + 0), temp); /* clear down all preexisting errors */
453
454 switch (Size)
455 {
456 case 4:
457 VideoPortWritePortUchar((PUCHAR) (I2C_IO_BASE + 2), 0x0d); /* DWORD modus ? */
458 break;
459 case 2:
460 VideoPortWritePortUchar((PUCHAR) (I2C_IO_BASE + 2), 0x0b); /* WORD modus */
461 break;
462 default:
463 VideoPortWritePortUchar((PUCHAR) (I2C_IO_BASE + 2), 0x0a); // BYTE
464 break;
465 }
466
467 b = 0;
468
469 while (0 == (b & 0x36))
470 {
471 b = VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 0));
472 }
473
474 if (0 != (b & 0x24))
475 {
476 /* printf("I2CTransmitByteGetReturn error %x\n", b); */
477 }
478
479 if(0 == (b & 0x10))
480 {
481 /* printf("I2CTransmitByteGetReturn no complete, retry\n"); */
482 }
483 else
484 {
485 switch (Size)
486 {
487 case 4:
488 VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 6));
489 VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 9));
490 VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 9));
491 VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 9));
492 VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 9));
493 break;
494 case 2:
495 *Data_to_smbus = VideoPortReadPortUshort((PUSHORT) (I2C_IO_BASE + 6));
496 break;
497 default:
498 *Data_to_smbus = VideoPortReadPortUchar((PUCHAR) (I2C_IO_BASE + 6));
499 break;
500 }
501
502
503 return TRUE;
504 }
505 }
506
507 return FALSE;
508 }
509
510
511 static BOOL
512 I2CTransmitByteGetReturn(UCHAR bPicAddressI2cFormat, UCHAR bDataToWrite, ULONG *Return)
513 {
514 return ReadfromSMBus(bPicAddressI2cFormat, bDataToWrite, 1, Return);
515 }
516
517 /*
518 * XboxVmpQueryAvailModes
519 *
520 * Returns information about each video mode supported by the adapter.
521 */
522
523 BOOL FASTCALL
524 XboxVmpQueryAvailModes(
525 PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
526 PVIDEO_MODE_INFORMATION VideoMode,
527 PSTATUS_BLOCK StatusBlock)
528 {
529 return XboxVmpQueryCurrentMode(DeviceExtension, VideoMode, StatusBlock);
530 }
531
532 /*
533 * VBEQueryCurrentMode
534 *
535 * Returns information about current video mode.
536 */
537
538 BOOL FASTCALL
539 XboxVmpQueryCurrentMode(
540 PXBOXVMP_DEVICE_EXTENSION DeviceExtension,
541 PVIDEO_MODE_INFORMATION VideoMode,
542 PSTATUS_BLOCK StatusBlock)
543 {
544 ULONG AvMode;
545
546 VideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
547 VideoMode->ModeIndex = 0;
548 if (I2CTransmitByteGetReturn(0x10, 0x04, &AvMode))
549 {
550 if (1 == AvMode) /* HDTV */
551 {
552 VideoMode->VisScreenWidth = 720;
553 }
554 else
555 {
556 /* FIXME Other possible values of AvMode:
557 * 0 - AV_SCART_RGB
558 * 2 - AV_VGA_SOG
559 * 4 - AV_SVIDEO
560 * 6 - AV_COMPOSITE
561 * 7 - AV_VGA
562 * other AV_COMPOSITE
563 */
564 VideoMode->VisScreenWidth = 640;
565 }
566 }
567 else
568 {
569 VideoMode->VisScreenWidth = 640;
570 }
571 VideoMode->VisScreenHeight = 480;
572 VideoMode->ScreenStride = VideoMode->VisScreenWidth * 4;
573 VideoMode->NumberOfPlanes = 1;
574 VideoMode->BitsPerPlane = 32;
575 VideoMode->Frequency = 1;
576 VideoMode->XMillimeter = 0; /* FIXME */
577 VideoMode->YMillimeter = 0; /* FIXME */
578 VideoMode->NumberRedBits = 8;
579 VideoMode->NumberGreenBits = 8;
580 VideoMode->NumberBlueBits = 8;
581 VideoMode->RedMask = 0xff0000;
582 VideoMode->GreenMask = 0x00ff00;
583 VideoMode->BlueMask = 0x0000ff;
584 VideoMode->VideoMemoryBitmapWidth = VideoMode->VisScreenWidth;
585 VideoMode->VideoMemoryBitmapHeight = VideoMode->VisScreenHeight;
586 VideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR |
587 VIDEO_MODE_NO_OFF_SCREEN;
588 VideoMode->DriverSpecificAttributeFlags = 0;
589
590 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
591
592 return TRUE;
593 }
594
595 /* EOF */