Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ; RDC M2010/M2012 video driver.
  2.  
  3. ; Standard driver stuff
  4. format PE DLL native at 0
  5. entry start
  6. __DEBUG__ equ 1
  7. __DEBUG_LEVEL__ equ 1
  8. section '.flat' readable writable executable
  9. include '../proc32.inc'
  10. include '../struct.inc'
  11. include '../macros.inc'
  12. include '../fdo.inc'
  13.  
  14. ; Display-specific driver stuff
  15. ; Kernel passes to init_cursor cursors with fixed size 32x32
  16. KERNEL_CURSOR_WIDTH = 32
  17. KERNEL_CURSOR_HEIGHT = 32
  18.  
  19. ; Constants for IOCTL codes
  20. SRV_GETVERSION = 0
  21. SRV_ENUM_MODES = 1
  22. SRV_SET_MODE   = 2
  23.  
  24. ; Constants for SRV_GETVERSION result
  25. CURRENT_API     = 0x0200
  26. COMPATIBLE_API  = 0x0100
  27. API_VERSION     = (COMPATIBLE_API shl 16) + CURRENT_API
  28.  
  29. ; Some structures
  30. struct  display_t
  31.         x               dd ?
  32.         y               dd ?
  33.         width           dd ?
  34.         height          dd ?
  35.         bpp             dd ?
  36.         vrefresh        dd ?
  37.         pitch           dd ?
  38.         lfb             dd ?
  39.  
  40.         modes           dd ?
  41.         ddev            dd ?
  42.         connector       dd ?
  43.         crtc            dd ?
  44.  
  45.         cr_list.next    dd ?
  46.         cr_list.prev    dd ?
  47.  
  48.         cursor          dd ?
  49.  
  50.         init_cursor     dd ?
  51.         select_cursor   dd ?
  52.         show_cursor     dd ?
  53.         move_cursor     dd ?
  54.         restore_cursor  dd ?
  55.         disable_mouse   dd ?
  56.         mask_seqno      dd ?
  57.         check_mouse     dd ?
  58.         check_m_pixel   dd ?
  59. ends
  60.  
  61. struct  APPOBJ                  ; common object header
  62.         magic           dd ?    ;
  63.         destroy         dd ?    ; internal destructor
  64.         fd              dd ?    ; next object in list
  65.         bk              dd ?    ; prev object in list
  66.         pid             dd ?    ; owner id
  67. ends
  68.  
  69. struct  CURSOR          APPOBJ
  70.         base            dd ?   ;allocated memory
  71.         hot_x           dd ?   ;hotspot coords
  72.         hot_y           dd ?
  73.  
  74.         list_next       dd ?   ;next cursor in cursor list
  75.         list_prev       dd ?   ;prev cursor in cursor list
  76.         dev_obj         dd ?   ;device depended data
  77. ends
  78.  
  79. ; Constants specific to our drivers
  80. ; We are handling two videocards: M2010 and M2012
  81. PCI_VENDOR_RDC          = 0x17F3
  82. ; I like this approach to select device IDs!
  83. PCI_CHIP_M2010          = 0x2010
  84. PCI_CHIP_M2012          = 0x2012
  85.  
  86. ; I/O ports for CRT registers
  87. COLOR_CRTC_INDEX        = 0x3D4
  88. COLOR_CRTC_DATA         = 0x3D5
  89. ; The value that unlocks extended CRT registers:
  90. ; index 0x80, value 0xA8
  91. ENABLE_EXTENDED_REGS    = 0xA880
  92.  
  93. ; Hardware cursors have size 64x64
  94. HW_CURSOR_WIDTH = 64
  95. HW_CURSOR_HEIGHT = 64
  96. ; Multiplication to powers of two can be replaced with shifts,
  97. ; x*HW_CURSOR_WIDTH = x shl HW_CURSOR_WIDTH_SHIFT
  98. HW_CURSOR_WIDTH_SHIFT = 6
  99. HW_CURSOR_HEIGHT_SHIFT = 6
  100.  
  101. ; MMIO registers responsible for hardware cursor, see PRM
  102. HWC_MMIO_CTRL           = 0x580
  103. HWC_MMIO_OFFSET         = 0x584
  104. HWC_MMIO_POSITION       = 0x588
  105. HWC_MMIO_ADDRESS        = 0x58C
  106.  
  107. ; Data for hardware cursors must be stored in videomemory,
  108. ; so we need an allocator for objects inside videomemory.
  109. ; Currently, we just reserve a fixed amount of memory for cursors
  110. ; (cursor size is the same for all cursors) and keep a bitfield
  111. ; that describes free blocks. 32 bits fit nicely in one dword.
  112. MAX_CURSORS = 32
  113.  
  114. ; === Entry points for external code ===
  115.  
  116. ; Called once when driver is loading and once at shutdown.
  117. ; When loading, must initialize itself, register itself in the system
  118. ; and return eax = value obtained when registering.
  119. ; Cdecl with two parameters.
  120. proc start
  121.         push    ebx esi ; save used registers to be stdcall
  122. virtual at esp
  123.                 rd      2 ; saved registers
  124.                 dd      ? ; return address
  125. .reason         dd      ? ; DRV_ENTRY or DRV_EXIT
  126. .cmdline        dd      ? ; normally NULL
  127. end virtual
  128. ; 1. Check the reason for the call, do nothing unless initializing.
  129.         cmp     [.reason], DRV_ENTRY
  130.         jnz     .nothing
  131. ; 2. Find the PCI device for our videocard.
  132. ; If not found, just return zero.
  133.         invoke  GetPCIList
  134.         mov     ebx, eax
  135. .look_pcidev_loop:
  136.         mov     ebx, [ebx+PCIDEV.fd]
  137.         cmp     ebx, eax
  138.         jz      .pcidev_notfound
  139.         cmp     [ebx+PCIDEV.vendor_device_id], PCI_VENDOR_RDC + (PCI_CHIP_M2010 shl 16)
  140.         jz      .pcidev_found
  141.         cmp     [ebx+PCIDEV.vendor_device_id], PCI_VENDOR_RDC + (PCI_CHIP_M2012 shl 16)
  142.         jnz     .look_pcidev_loop
  143. .pcidev_found:
  144. ; 3. Get addresses, sizes and pointers from the hardware.
  145. ; 3a. Create mapping for MMIO.
  146.         invoke  PciRead32, dword [ebx+PCIDEV.bus], dword [ebx+PCIDEV.devfn], 14h
  147.         and     al, not 0xF
  148.         invoke  MapIoMem, eax, 10000h, PG_NOCACHE+PG_SW
  149.         test    eax, eax
  150.         jz      .nothing
  151.         mov     [mmio], eax
  152. ; 3b. Get videomemory size. It is stored in 3 lower bits of 0xAA extended register
  153. ; logarithmically started with 8Mb.
  154.         mov     dx, COLOR_CRTC_INDEX
  155.         mov     ax, ENABLE_EXTENDED_REGS
  156.         out     dx, ax
  157.         mov     al, 0xAA
  158.         out     dx, al
  159.         inc     edx
  160.         in      al, dx
  161.         and     eax, 7
  162.         mov     ecx, eax
  163.         mov     eax, 8 shl 20
  164.         shl     eax, cl
  165.         mov     [video_mem_size], eax
  166. ; 3c. Reserve area for cursors in the last part of videomemory.
  167.         sub     eax, MAX_CURSORS * HW_CURSOR_WIDTH * HW_CURSOR_HEIGHT * 4
  168.         mov     [cursors_base_offset], eax
  169. ; 3d. Create mapping for part of videomemory that we have reserved for cursors.
  170. ; Note: we can't just use system-wide mapping at 0xFE000000, it is too short.
  171.         invoke  PciRead32, dword [ebx+PCIDEV.bus], dword [ebx+PCIDEV.devfn], 10h
  172.         and     al, not 0xF
  173.         add     eax, [cursors_base_offset]
  174.         invoke  MapIoMem, eax, MAX_CURSORS * HW_CURSOR_WIDTH * HW_CURSOR_HEIGHT * 4, PG_SW
  175.         test    eax, eax
  176.         jz      .nothing
  177.         mov     [cursors_base_va], eax
  178. ; 4. Install cursor handlers.
  179. ; 4a. Get pointer to the structure that keeps everything display-related.
  180.         invoke  GetDisplay
  181.         mov     ebx, eax
  182. ; 4b. Make sure that no one tries to use partially-changed structure.
  183.         pushf
  184.         cli
  185. ; 4c. Ask the previous handler to restore image hidden beyond cursor.
  186.         stdcall [ebx+display_t.restore_cursor], 0, 0
  187. ; 4d. Store pointers to our functions.
  188.         mov     [ebx+display_t.init_cursor], init_cursor
  189.         mov     [ebx+display_t.select_cursor], select_cursor
  190.         mov     [ebx+display_t.show_cursor], 0
  191.         mov     [ebx+display_t.move_cursor], move_cursor
  192.         mov     [ebx+display_t.restore_cursor], restore_cursor
  193.         mov     [ebx+display_t.disable_mouse], disable_mouse
  194. ; 4e. The kernel will pass all new cursors to our init_cursor,
  195. ; but we must process already created cursors ourselves to be able to
  196. ; select_cursor them when requested. Do it now: pass every cursor
  197. ; in the list display_t.cr_list to init_cursor.
  198.         add     ebx, display_t.cr_list.next
  199.         mov     esi, ebx
  200. .init_old_cursors_loop:
  201.         mov     esi, [esi]
  202.         cmp     esi, ebx
  203.         jz      .init_old_cursors_done
  204.         lea     eax, [esi-CURSOR.list_next]
  205.         push    eax
  206.         call    init_cursor
  207.         pop     eax
  208.         jmp     .init_old_cursors_loop
  209. .init_old_cursors_done:
  210. ; 4f. Setup the current cursor.
  211.         stdcall move_cursor, [ebx+display_t.cursor-display_t.cr_list.next], 0, 0
  212.         stdcall select_cursor, [ebx+display_t.cursor-display_t.cr_list.next]
  213. ; 4g. It is safe now to work with display structure; restore after 4b.
  214.         popf
  215. ; 5. Say something happy to the (curious) user.
  216.         mov     esi, success_msg
  217.         invoke  SysMsgBoardStr
  218. ; 6. Register ourselves as a service.
  219. ; Note: not really needed currently as we don't do any useful in ioctl_handler,
  220. ; but do it nevertheless for future expansion.
  221.         invoke  RegService, rdc_name, ioctl_handler
  222. .nothing:
  223.         pop     esi ebx ; restore used registers to be stdcall
  224.         ret
  225. .pcidev_notfound:
  226.         xor     eax, eax
  227.         jmp     .nothing
  228. endp
  229.  
  230. ; Service procedure for the driver - handle all IOCTL requests for the driver.
  231. ; Stdcall with one parameter.
  232. proc ioctl_handler
  233. virtual at esp
  234.                 dd      ?       ; return address
  235. .ioctl          dd      ?
  236. end virtual
  237. ; Not very useful currently - just return API_VERSION as a response to SRV_GETVERSION = 0.
  238.         mov     edx, [.ioctl]
  239.         mov     eax, [edx+IOCTL.io_code]
  240.         test    eax, eax
  241.         jz      .getversion
  242. .error:
  243.         or      eax, -1         ; fail everything unknown
  244.         retn    4
  245. .getversion:
  246.         cmp     [edx+IOCTL.out_size], 4
  247.         jnz     .error
  248.         mov     eax, [edx+IOCTL.output]
  249.         mov     dword [eax], API_VERSION
  250.         xor     eax, eax
  251.         retn    4
  252. endp
  253.  
  254. ; === Cursors ===
  255.  
  256. ; This function is called when an application registers a new cursor.
  257. ; Cdecl with one parameter, return value ignored.
  258. proc init_cursor
  259.         push    esi edi
  260. virtual at esp
  261.                 rd      2       ; saved registers
  262.                 dd      ?       ; return address
  263. .cursor         dd      ?
  264. end virtual
  265. ; We store one specific dword in CURSOR.dev_obj,
  266. ; index in cursors area from 0 to NUM_CURSORS-1, or -1 for error.
  267. ; 1. Prepare: store -1 to CURSOR.dev_obj and pointer to destroy function.
  268.         mov     edx, [.cursor]
  269.         mov     [edx+CURSOR.dev_obj], -1
  270.         mov     [edx+CURSOR.destroy], destroy_cursor
  271. ; 2. Allocate videomemory.
  272.         bsr     edi, [free_cursors]
  273.         jz      .nocopy
  274.         btr     [free_cursors], edi
  275. ; 3. Store the allocated item to CURSOR.dev_obj.
  276.         mov     [edx+CURSOR.dev_obj], edi
  277. ; 4. Copy data from kernel-provided cursor to videomemory,
  278. ; transforming KERNEL_CURSOR_WIDTH*KERNEL_CURSOR_HEIGHT*(4 bytes RGBA) to
  279. ; HW_CURSOR_WIDTH*HW_CURSOR_HEIGHT*(4 bytes RGBA).
  280.         shl     edi, HW_CURSOR_WIDTH_SHIFT + HW_CURSOR_HEIGHT_SHIFT + 2
  281.         add     edi, [cursors_base_va]
  282.         mov     esi, [edx+CURSOR.base]
  283.         push    KERNEL_CURSOR_HEIGHT
  284.         xor     eax, eax
  285. @@:
  286.         mov     ecx, KERNEL_CURSOR_WIDTH
  287.         rep movsd
  288.         mov     ecx, HW_CURSOR_WIDTH - KERNEL_CURSOR_WIDTH
  289.         rep stosd
  290.         dec     dword [esp]
  291.         jnz     @b
  292.         pop     ecx
  293.         mov     ecx, HW_CURSOR_WIDTH * (HW_CURSOR_HEIGHT - KERNEL_CURSOR_HEIGHT)
  294.         rep stosd
  295. .nocopy:
  296. ; 5. We don't need kernel-provided data anymore; free it now.
  297.         invoke  KernelFree, [edx+CURSOR.base]
  298.         pop     edi esi
  299.         ret
  300. endp
  301.  
  302. ; This function is called when a thread that has created a cursor
  303. ; is terminating and we need to free the cursor.
  304. proc destroy_cursor
  305. ; 1. Free allocated videomemory.
  306.         mov     edx, [eax+CURSOR.dev_obj]
  307.         test    edx, edx
  308.         js      .nofree
  309.         bts     [free_cursors], edx
  310. .nofree:
  311. ; 2. Remove the cursor from the overall list at display_t.cr_list.
  312.         pushf
  313.         cli
  314.         mov     ecx, [eax+CURSOR.list_next]
  315.         mov     edx, [eax+CURSOR.list_prev]
  316.         mov     [ecx+4], edx
  317.         mov     [edx], ecx
  318.         popf
  319. ; 3. Free memory allocated for kernel object.
  320.         jmp     [DestroyObject]
  321. endp
  322.  
  323. ; This function is called when cursor shape needs to be changed,
  324. ; either due to explicit request from application
  325. ; or due to moving from one window to another.
  326. ; Stdcall with one parameter, return value ignored.
  327. proc select_cursor
  328. virtual at esp
  329.                 dd      ?       ; return address
  330. .cursor         dd      ?
  331. end virtual
  332.         mov     eax, [.cursor]
  333.         mov     eax, [eax+CURSOR.dev_obj]
  334.         cmp     eax, -1
  335.         jz      .nothing
  336. ; Setup base address of cursor, relative to videomemory,
  337. ; and enable hardware cursor.
  338. ; See PRM for details.
  339.         shl     eax, HW_CURSOR_WIDTH_SHIFT + HW_CURSOR_HEIGHT_SHIFT + 2
  340.         add     eax, [cursors_base_offset]
  341.         shr     eax, 3
  342.         mov     edx, [mmio]
  343.         mov     [edx+HWC_MMIO_ADDRESS], eax
  344.         mov     dword [edx+HWC_MMIO_CTRL], (1 shl 31) + (1 shl 1) + (1 shl 0)
  345. .nothing:
  346.         ret     4
  347. endp
  348.  
  349. ; This function is called when cursor is moved to a new place.
  350. ; Stdcall with three parameters, return value ignored.
  351. proc move_cursor
  352. virtual at esp
  353.                 dd      ?       ; return address
  354. .cursor         dd      ?
  355. .x              dd      ?
  356. .y              dd      ?
  357. .xoffset        dd      ?
  358. .yoffset        dd      ?
  359. end virtual
  360. ; If cursor x is smaller than hotspot x,
  361. ; only part of cursor is shown at position x=0
  362. ; with x offset = (hotspot x) - (cursor x).
  363. ; Otherwise, the entire cursor is shown (x offset = 0)
  364. ; at position x = (cursor x) - (hotspot x).
  365. ; Similar for y. Refer to PRM for details.
  366.         xor     ecx, ecx
  367.         mov     edx, [.cursor]
  368.         mov     eax, [.x]
  369.         sub     eax, [edx+CURSOR.hot_x]
  370.         jae     @f
  371.         sub     ecx, eax
  372.         xor     eax, eax
  373. @@:
  374.         mov     [.x], eax
  375.         mov     eax, [.y]
  376.         sub     eax, [edx+CURSOR.hot_y]
  377.         jae     @f
  378.         shl     eax, 8
  379.         sub     ecx, eax
  380.         xor     eax, eax
  381. @@:
  382.         mov     [.y], eax
  383.         mov     edx, [mmio]
  384.         mov     eax, [.y]
  385.         add     eax, HW_CURSOR_HEIGHT - 1       ; no scaling
  386.         shl     eax, 16
  387.         add     eax, ecx
  388.         mov     [edx+HWC_MMIO_OFFSET], eax
  389.         mov     eax, [.y]
  390.         shl     eax, 16
  391.         add     eax, [.x]
  392.         mov     [edx+HWC_MMIO_POSITION], eax
  393.         mov     eax, [edx+HWC_MMIO_CTRL]
  394.         mov     [edx+HWC_MMIO_CTRL], eax
  395.         ret     12
  396. endp
  397.  
  398. ; Stdcall with two parameters, return value ignored.
  399. proc restore_cursor
  400. ; No-operation for hardware cursors.
  401.         ret     8
  402. endp
  403.  
  404. ; No parameters, return value ignored.
  405. proc disable_mouse
  406. ; No-operation for hardware cursors.
  407.         ret
  408. endp
  409.  
  410. ; === Data ===
  411. rdc_name db 'DISPLAY',0
  412. success_msg db 'RDC: using hardware cursors',13,10,0
  413.  
  414. align 4
  415. ; Look at the comment before definition of NUM_CURSORS.
  416. free_cursors    dd      0xFFFFFFFF
  417.  
  418. data fixups
  419. end data
  420.  
  421. include '../peimport.inc'
  422. ;include_debug_strings
  423. IncludeIGlobals
  424. IncludeUGlobals
  425. align 4
  426. mmio            dd      ?       ; virtual address of MMIO for our device
  427. video_mem_size  dd      ?       ; total size of video memory, in bytes
  428. cursors_base_offset     dd      ?       ; base of cursor data, relative to video memory start
  429. cursors_base_va         dd      ?       ; mapped virtual address of cursor data
  430.