Subversion Repositories Kolibri OS

Rev

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