Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4453 clevermous 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