Subversion Repositories Kolibri OS

Rev

Rev 4453 | Details | Compare with Previous | 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
 
5351 serge 29
struct  RWSEM
30
        wait_list       LHEAD
31
        count           dd ?
32
ends
33
 
4453 clevermous 34
; Some structures
35
struct  display_t
36
        x               dd ?
37
        y               dd ?
38
        width           dd ?
39
        height          dd ?
5351 serge 40
        bits_per_pixel  dd ?
4453 clevermous 41
        vrefresh        dd ?
42
        lfb             dd ?
5351 serge 43
        lfb_pitch       dd ?
4453 clevermous 44
 
5351 serge 45
        win_map_lock    RWSEM
46
        win_map         dd ?
47
        win_map_pitch   dd ?
48
        win_map_size    dd ?
49
 
4453 clevermous 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 ?
5351 serge 69
 
70
        bytes_per_pixel dd ?
4453 clevermous 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