Subversion Repositories Kolibri OS

Rev

Rev 4587 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4429 Serge 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
3
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
6
;;                                                              ;;
7
;;  PCI32.INC                                                   ;;
8
;;                                                              ;;
9
;;  32 bit PCI driver code                                      ;;
10
;;                                                              ;;
11
;;  Version 0.3  April 9, 2007                                  ;;
12
;;  Version 0.2  December 21st, 2002                            ;;
13
;;                                                              ;;
14
;;  Author: Victor Prodan, victorprodan@yahoo.com               ;;
15
;;          Mihailov Ilia, ghost.nsk@gmail.com                  ;;
16
;;    Credits:                                                  ;;
17
;;          Ralf Brown                                          ;;
18
;;          Mike Hibbett, mikeh@oceanfree.net                   ;;
19
;;                                                              ;;
20
;;  See file COPYING for details                                ;;
21
;;                                                              ;;
22
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23
 
24
$Revision: 4418 $
25
 
26
;***************************************************************************
27
;   Function
28
;      pci_api:
29
;
30
;   Description
31
;       entry point for system PCI calls
32
;***************************************************************************
33
;mmio_pci_addr  equ  0x400               ; set actual PCI address here to activate user-MMIO
34
 
35
iglobal
36
align 4
37
f62call:
38
        dd      pci_fn_0
39
        dd      pci_fn_1
40
        dd      pci_fn_2
41
        dd      pci_service_not_supported       ;3
42
        dd      pci_read_reg            ;4 byte
43
        dd      pci_read_reg            ;5 word
44
        dd      pci_read_reg            ;6 dword
45
        dd      pci_service_not_supported   ;7
46
        dd      pci_write_reg           ;8 byte
47
        dd      pci_write_reg           ;9 word
48
        dd      pci_write_reg           ;10 dword
49
if defined mmio_pci_addr
50
        dd      pci_mmio_init           ;11
51
        dd      pci_mmio_map            ;12
52
        dd      pci_mmio_unmap          ;13
53
end if
54
 
55
endg
56
 
57
align 4
58
 
59
pci_api:
60
 
61
;cross
62
        mov     eax, ebx
63
        mov     ebx, ecx
64
        mov     ecx, edx
65
 
66
        cmp     [pci_access_enabled], 1
67
        jne     pci_service_not_supported
68
 
69
        movzx   edx, al
70
 
71
if defined mmio_pci_addr
72
        cmp     al, 13
73
        ja      pci_service_not_supported
74
else
75
        cmp     al, 10
76
        ja      pci_service_not_supported
77
end if
78
 
79
        call    dword [f62call+edx*4]
80
        mov     dword [esp+32], eax
81
        ret
82
 
83
 
84
align 4
85
pci_api_drv:
86
 
87
        cmp     [pci_access_enabled], 1
88
        jne     .fail
89
 
90
        cmp     eax, 2
91
        ja      .fail
92
 
93
        jmp     dword [f62call+eax*4]
94
 
95
.fail:
96
        or      eax, -1
97
        ret
98
 
99
 
100
;; ============================================
101
 
102
pci_fn_0:
103
; PCI function 0: get pci version (AH.AL)
104
        movzx   eax, word [BOOT_VARS+0x9022]
105
        ret
106
 
107
pci_fn_1:
108
; PCI function 1: get last bus in AL
109
        mov     al, [BOOT_VARS+0x9021]
110
        ret
111
 
112
pci_fn_2:
113
; PCI function 2: get pci access mechanism
114
        mov     al, [BOOT_VARS+0x9020]
115
        ret
116
 
117
pci_service_not_supported:
118
        or      eax, -1
119
        mov     dword [esp+32], eax
120
        ret
121
 
122
;***************************************************************************
123
;   Function
124
;      pci_make_config_cmd
125
;
126
;   Description
127
;       creates a command dword  for use with the PCI bus
128
;       bus # in ah
129
;       device+func in bh (dddddfff)
130
;       register in bl
131
;
132
;      command dword returned in eax ( 10000000 bbbbbbbb dddddfff rrrrrr00 )
133
;***************************************************************************
134
 
135
align 4
136
 
137
pci_make_config_cmd:
138
        shl     eax, 8     ; move bus to bits 16-23
139
        mov     ax, bx     ; combine all
140
        and     eax, 0xffffff
141
        or      eax, 0x80000000
142
        ret
143
 
144
;***************************************************************************
145
;   Function
146
;      pci_read_reg:
147
;
148
;   Description
149
;       read a register from the PCI config space into EAX/AX/AL
150
;       IN: ah=bus,device+func=bh,register address=bl
151
;           number of bytes to read (1,2,4) coded into AL, bits 0-1
152
;           (0 - byte, 1 - word, 2 - dword)
153
;***************************************************************************
154
 
155
align 4
156
 
157
pci_read_reg:
158
        push    ebx esi
159
        cmp     byte [BOOT_VARS+0x9020], 2;what mechanism will we use?
160
        je      pci_read_reg_2
161
 
162
                ; mechanism 1
163
        mov     esi, eax ; save register size into ESI
164
        and     esi, 3
165
 
166
        call    pci_make_config_cmd
167
        mov     ebx, eax
168
        mov     dx, 0xcf8
169
                ; set up addressing to config data
170
        mov     eax, ebx
171
        and     al, 0xfc; make address dword-aligned
172
        out     dx, eax
173
                ; get requested DWORD of config data
174
        mov     dl, 0xfc
175
        and     bl, 3
176
        or      dl, bl   ; add to port address first 2 bits of register address
177
 
178
        or      esi, esi
179
        jz      pci_read_byte1
180
        cmp     esi, 1
181
        jz      pci_read_word1
182
        cmp     esi, 2
183
        jz      pci_read_dword1
184
        jmp     pci_fin_read1
185
 
186
pci_read_byte1:
187
        in      al, dx
188
        jmp     pci_fin_read1
189
pci_read_word1:
190
        in      ax, dx
191
        jmp     pci_fin_read1
192
pci_read_dword1:
193
        in      eax, dx
194
pci_fin_read1:
195
        pop     esi ebx
196
        ret
197
pci_read_reg_2:
198
 
199
        test    bh, 128 ;mech#2 only supports 16 devices per bus
200
        jnz     pci_read_reg_err
201
 
202
        mov     esi, eax ; save register size into ESI
203
        and     esi, 3
204
 
4923 Serge 205
        mov     dx, 0xcfa
4429 Serge 206
 
207
                ; out 0xcfa,bus
208
        mov     al, ah
209
        out     dx, al
210
                ; out 0xcf8,0x80
211
        mov     dl, 0xf8
212
        mov     al, 0x80
213
        out     dx, al
214
                ; compute addr
215
        shr     bh, 3; func is ignored in mechanism 2
216
        or      bh, 0xc0
217
        mov     dx, bx
218
 
219
        or      esi, esi
220
        jz      pci_read_byte2
221
        cmp     esi, 1
222
        jz      pci_read_word2
223
        cmp     esi, 2
224
        jz      pci_read_dword2
225
        jmp     pci_fin_read2
226
 
227
pci_read_byte2:
228
        in      al, dx
229
        jmp     pci_fin_read2
230
pci_read_word2:
231
        in      ax, dx
232
        jmp     pci_fin_read2
233
pci_read_dword2:
234
        in      eax, dx
235
pci_fin_read2:
236
 
237
        pop     esi ebx
238
        ret
239
 
240
pci_read_reg_err:
241
        xor     eax, eax
242
        dec     eax
243
        pop     esi ebx
244
        ret
245
 
246
 
247
;***************************************************************************
248
;   Function
249
;      pci_write_reg:
250
;
251
;   Description
252
;       write a register from ECX/CX/CL into the PCI config space
253
;       IN: ah=bus,device+func=bh,register address (dword aligned)=bl,
254
;           value to write in ecx
255
;           number of bytes to write (1,2,4) coded into AL, bits 0-1
256
;           (0 - byte, 1 - word, 2 - dword)
257
;***************************************************************************
258
 
259
align 4
260
 
261
pci_write_reg:
262
        push    esi ebx
263
        cmp     byte [BOOT_VARS+0x9020], 2;what mechanism will we use?
264
        je      pci_write_reg_2
265
 
266
                ; mechanism 1
267
        mov     esi, eax ; save register size into ESI
268
        and     esi, 3
269
 
270
        call    pci_make_config_cmd
271
        mov     ebx, eax
272
        mov     dx, 0xcf8
273
                ; set up addressing to config data
274
        mov     eax, ebx
275
        and     al, 0xfc; make address dword-aligned
276
        out     dx, eax
277
                ; write DWORD of config data
278
        mov     dl, 0xfc
279
        and     bl, 3
280
        or      dl, bl
281
        mov     eax, ecx
282
 
283
        or      esi, esi
284
        jz      pci_write_byte1
285
        cmp     esi, 1
286
        jz      pci_write_word1
287
        cmp     esi, 2
288
        jz      pci_write_dword1
289
        jmp     pci_fin_write1
290
 
291
pci_write_byte1:
292
        out     dx, al
293
        jmp     pci_fin_write1
294
pci_write_word1:
295
        out     dx, ax
296
        jmp     pci_fin_write1
297
pci_write_dword1:
298
        out     dx, eax
299
pci_fin_write1:
300
 
301
        xor     eax, eax
302
        pop     ebx esi
303
 
304
        ret
305
pci_write_reg_2:
306
 
307
        test    bh, 128 ;mech#2 only supports 16 devices per bus
308
        jnz     pci_write_reg_err
309
 
310
 
311
        mov     esi, eax ; save register size into ESI
312
        and     esi, 3
313
 
4923 Serge 314
        mov     dx, 0xcfa
4429 Serge 315
                ; out 0xcfa,bus
316
        mov     al, ah
317
        out     dx, al
318
                ; out 0xcf8,0x80
319
        mov     dl, 0xf8
320
        mov     al, 0x80
321
        out     dx, al
322
                ; compute addr
323
        shr     bh, 3; func is ignored in mechanism 2
324
        or      bh, 0xc0
325
        mov     dx, bx
326
                ; write register
327
        mov     eax, ecx
328
 
329
        or      esi, esi
330
        jz      pci_write_byte2
331
        cmp     esi, 1
332
        jz      pci_write_word2
333
        cmp     esi, 2
334
        jz      pci_write_dword2
335
        jmp     pci_fin_write2
336
 
337
pci_write_byte2:
338
        out     dx, al
339
        jmp     pci_fin_write2
340
pci_write_word2:
341
        out     dx, ax
342
        jmp     pci_fin_write2
343
pci_write_dword2:
344
        out     dx, eax
345
pci_fin_write2:
346
 
347
        xor     eax, eax
348
        pop     ebx esi
349
        ret
350
 
351
pci_write_reg_err:
352
        xor     eax, eax
353
        dec     eax
354
        pop     ebx esi
355
        ret
356
 
357
if defined mmio_pci_addr        ; must be set above
358
;***************************************************************************
359
;   Function
360
;      pci_mmio_init
361
;
362
;   Description
363
;       IN:  bx = device's PCI bus address (bbbbbbbbdddddfff)
364
;   Returns  eax = user heap space available (bytes)
365
;   Error codes
366
;       eax = -1 : PCI user access blocked,
367
;       eax = -2 : device not registered for uMMIO service
368
;       eax = -3 : user heap initialization failure
369
;***************************************************************************
370
pci_mmio_init:
371
        cmp     bx, mmio_pci_addr
372
        jz      @f
373
        mov     eax, -2
374
        ret
375
@@:
376
        call    init_heap  ; (if not initialized yet)
377
        or      eax, eax
378
        jz      @f
379
        ret
380
@@:
381
        mov     eax, -3
382
        ret
383
 
384
 
385
;***************************************************************************
386
;   Function
387
;      pci_mmio_map
388
;
389
;   Description
390
;       maps a block of PCI memory to user-accessible linear address
391
;
392
;       WARNING! This VERY EXPERIMENTAL service is for one chosen PCI device only!
393
;       The target device address should be set in kernel var mmio_pci_addr
394
;
395
;       IN:  ah = BAR#;
396
;       IN: ebx = block size (bytes);
397
;       IN: ecx = offset in MMIO block (in 4K-pages, to avoid misaligned pages);
398
;
399
;   Returns eax = MMIO block's linear address in the userspace (if no error)
400
;
401
;
402
;   Error codes
403
;       eax = -1 : user access to PCI blocked,
404
;       eax = -2 : an invalid BAR register referred
405
;       eax = -3 : no i/o space on that BAR
406
;       eax = -4 : a port i/o BAR register referred
407
;       eax = -5 : dynamic userspace allocation problem
408
;***************************************************************************
409
 
410
pci_mmio_map:
411
        and     edx, 0x0ffff
412
        cmp     ah, 6
413
        jc      .bar_0_5
414
        jz      .bar_rom
415
        mov     eax, -2
416
        ret
417
.bar_rom:
418
        mov     ah, 8   ; bar6 = Expansion ROM base address
419
.bar_0_5:
420
        push    ecx
421
        add     ebx, 4095
422
        and     ebx, -4096
423
        push    ebx
424
        mov     bl, ah  ; bl = BAR# (0..5), however bl=8 for BAR6
425
        shl     bl, 1
426
        shl     bl, 1
427
        add     bl, 0x10; now bl = BAR offset in PCI config. space
428
        mov     ax, mmio_pci_addr
429
        mov     bh, al  ; bh = dddddfff
430
        mov     al, 2   ; al : DW to read
431
        call    pci_read_reg
432
        or      eax, eax
433
        jnz     @f
434
        mov     eax, -3 ; empty I/O space
435
        jmp     mmio_ret_fail
436
@@:
437
        test    eax, 1
438
        jz      @f
439
        mov     eax, -4 ; damned ports (not MMIO space)
440
        jmp     mmio_ret_fail
441
@@:
442
        pop     ecx     ; ecx = block size, bytes (expanded to whole page)
443
        mov     ebx, ecx; user_alloc destroys eax, ecx, edx, but saves ebx
444
        and     eax, 0xFFFFFFF0
445
        push    eax           ; store MMIO physical address + keep 2DWords in the stack
446
        stdcall user_alloc, ecx
447
        or      eax, eax
448
        jnz     mmio_map_over
449
        mov     eax, -5 ; problem with page allocation
450
 
451
mmio_ret_fail:
452
        pop     ecx
453
        pop     edx
454
        ret
455
 
456
mmio_map_over:
457
        mov     ecx, ebx; ecx = size (bytes, expanded to whole page)
458
        shr     ecx, 12 ; ecx = number of pages
459
        mov     ebx, eax; ebx = linear address
460
        pop     eax     ; eax = MMIO start
461
        pop     edx     ; edx = MMIO shift (pages)
462
        shl     edx, 12 ; edx = MMIO shift (bytes)
463
        add     eax, edx; eax = uMMIO physical address
464
        or      eax, PG_SHARED
465
        or      eax, PG_UW
466
        or      eax, PG_NOCACHE
467
        mov     edi, ebx
468
        call    commit_pages
469
        mov     eax, edi
470
        ret
471
 
472
;***************************************************************************
473
;   Function
474
;      pci_mmio_unmap_page
475
;
476
;   Description
477
;       unmaps the linear space previously tied to a PCI memory block
478
;
479
;       IN: ebx = linear address of space previously allocated by pci_mmio_map
480
;       returns eax = 1 if successfully unmapped
481
;
482
;   Error codes
483
;       eax = -1 if no user PCI access allowed,
484
;       eax =  0 if unmapping failed
485
;***************************************************************************
486
 
487
pci_mmio_unmap:
488
        stdcall user_free, ebx
489
        ret
490
 
491
end if
492
 
493
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
494
uglobal
495
align 4
496
; VendID (2), DevID (2), Revision = 0 (1), Class Code (3), FNum (1), Bus (1)
497
pci_emu_dat:
498
                times   30*10 db 0
499
endg
500
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
501
align 4
502
sys_pcibios:
503
        cmp     [pci_access_enabled], 1
504
        jne     .unsupported_func
505
        cmp     [pci_bios_entry], 0
506
        jz      .emulate_bios
507
 
508
        push    ds
509
        mov     ax, pci_data_sel
510
        mov     ds, ax
511
        mov     eax, ebp
512
        mov     ah, 0B1h
513
        call    pword [cs:pci_bios_entry]
514
        pop     ds
515
 
516
        jmp     .return
517
        ;-=-=-=-=-=-=-=-=
518
.emulate_bios:
519
        cmp     ebp, 1                  ; PCI_FUNCTION_ID
520
        jnz     .not_PCI_BIOS_PRESENT
521
        mov     edx, 'PCI '
522
        mov     al, [BOOT_VARS + 0x9020]
523
        mov     bx, [BOOT_VARS + 0x9022]
524
        mov     cl, [BOOT_VARS + 0x9021]
525
        xor     ah, ah
526
        jmp     .return_abcd
527
 
528
.not_PCI_BIOS_PRESENT:
529
        cmp     ebp, 2                  ; FIND_PCI_DEVICE
530
        jne     .not_FIND_PCI_DEVICE
531
        mov     ebx, pci_emu_dat
532
..nxt:
533
        cmp     [ebx], dx
534
        jne     ..no
535
        cmp     [ebx + 2], cx
536
        jne     ..no
537
        dec     si
538
        jns     ..no
539
        mov     bx, [ebx + 4]
540
        xor     ah, ah
541
        jmp     .return_ab
542
..no:
543
        cmp     word[ebx], 0
544
        je      ..dev_not_found
545
        add     ebx, 10
546
        jmp     ..nxt
547
..dev_not_found:
548
        mov     ah, 0x86                ; DEVICE_NOT_FOUND
549
        jmp     .return_a
550
 
551
.not_FIND_PCI_DEVICE:
552
        cmp     ebp, 3                  ; FIND_PCI_CLASS_CODE
553
        jne     .not_FIND_PCI_CLASS_CODE
554
        mov     esi, pci_emu_dat
555
        shl     ecx, 8
556
..nxt2:
557
        cmp     [esi], ecx
558
        jne     ..no2
559
        mov     bx, [esi]
560
        xor     ah, ah
561
        jmp     .return_ab
562
..no2:
563
        cmp     dword[esi], 0
564
        je      ..dev_not_found
565
        add     esi, 10
566
        jmp     ..nxt2
567
 
568
.not_FIND_PCI_CLASS_CODE:
569
        cmp     ebp, 8                  ; READ_CONFIG_*
570
        jb      .not_READ_CONFIG
571
        cmp     ebp, 0x0A
572
        ja      .not_READ_CONFIG
573
        mov     eax, ebp
574
        mov     ah, bh
575
        mov     edx, edi
576
        mov     bh, bl
577
        mov     bl, dl
578
        call    pci_read_reg
579
        mov     ecx, eax
580
        xor     ah, ah                  ; SUCCESSFUL
581
        jmp     .return_abc
582
.not_READ_CONFIG:
583
        cmp     ebp, 0x0B               ; WRITE_CONFIG_*
584
        jb      .not_WRITE_CONFIG
585
        cmp     ebp, 0x0D
586
        ja      .not_WRITE_CONFIG
587
        lea     eax, [ebp+1]
588
        mov     ah, bh
589
        mov     edx, edi
590
        mov     bh, bl
591
        mov     bl, dl
592
        call    pci_write_reg
593
        xor     ah, ah                  ; SUCCESSFUL
594
        jmp     .return_abc
595
.not_WRITE_CONFIG:
596
.unsupported_func:
597
        mov     ah, 0x81                ; FUNC_NOT_SUPPORTED
598
.return:
599
        mov     dword[esp + 4 ], edi
600
        mov     dword[esp + 8], esi
601
.return_abcd:
602
        mov     dword[esp + 24], edx
603
.return_abc:
604
        mov     dword[esp + 28], ecx
605
.return_ab:
606
        mov     dword[esp + 20], ebx
607
.return_a:
608
        mov     dword[esp + 32], eax
609
        ret
610
 
611
proc pci_enum
612
        push    ebp
613
        mov     ebp, esp
614
        push    0
615
virtual at ebp-4
616
.devfn          db      ?
617
.bus            db      ?
618
end virtual
619
.loop:
620
        mov     ah, [.bus]
621
        mov     al, 2
622
        mov     bh, [.devfn]
623
        mov     bl, 0
624
        call    pci_read_reg
625
        cmp     eax, 0xFFFFFFFF
626
        jnz     .has_device
627
        test    byte [.devfn], 7
628
        jnz     .next_func
629
        jmp     .no_device
630
.has_device:
631
        push    eax
632
        movi    eax, sizeof.PCIDEV
633
        call    malloc
634
        pop     ecx
635
        test    eax, eax
636
        jz      .nomemory
637
        mov     edi, eax
638
        mov     [edi+PCIDEV.vendor_device_id], ecx
639
        mov     eax, pcidev_list
640
        mov     ecx, [eax+PCIDEV.bk]
641
        mov     [edi+PCIDEV.bk], ecx
642
        mov     [edi+PCIDEV.fd], eax
643
        mov     [ecx+PCIDEV.fd], edi
644
        mov     [eax+PCIDEV.bk], edi
645
        mov     eax, dword [.devfn]
646
        mov     dword [edi+PCIDEV.devfn], eax
647
        mov     dword [edi+PCIDEV.owner], 0
648
        mov     bh, al
649
        mov     al, 2
650
        mov     bl, 8
651
        call    pci_read_reg
652
        shr     eax, 8
653
        mov     [edi+PCIDEV.class], eax
654
        test    byte [.devfn], 7
655
        jnz     .next_func
656
        mov     ah, [.bus]
657
        mov     al, 0
658
        mov     bh, [.devfn]
659
        mov     bl, 0Eh
660
        call    pci_read_reg
661
        test    al, al
662
        js      .next_func
663
.no_device:
664
        or      byte [.devfn], 7
665
.next_func:
666
        inc     dword [.devfn]
667
        mov     ah, [.bus]
668
        cmp     ah, [BOOT_VARS+0x9021]
669
        jbe     .loop
670
.nomemory:
671
        leave
672
        ret
673
endp
4587 Serge 674
 
675
; Export for drivers. Just returns the pointer to the pci-devices list.
676
proc get_pcidev_list
677
        mov     eax, pcidev_list
678
        ret
679
endp