Subversion Repositories Kolibri OS

Rev

Rev 4429 | 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
                ; get current state
169
        mov     dx, 0xcf8
170
        in      eax, dx
171
        push    eax
172
                ; set up addressing to config data
173
        mov     eax, ebx
174
        and     al, 0xfc; make address dword-aligned
175
        out     dx, eax
176
                ; get requested DWORD of config data
177
        mov     dl, 0xfc
178
        and     bl, 3
179
        or      dl, bl   ; add to port address first 2 bits of register address
180
 
181
        or      esi, esi
182
        jz      pci_read_byte1
183
        cmp     esi, 1
184
        jz      pci_read_word1
185
        cmp     esi, 2
186
        jz      pci_read_dword1
187
        jmp     pci_fin_read1
188
 
189
pci_read_byte1:
190
        in      al, dx
191
        jmp     pci_fin_read1
192
pci_read_word1:
193
        in      ax, dx
194
        jmp     pci_fin_read1
195
pci_read_dword1:
196
        in      eax, dx
197
        jmp     pci_fin_read1
198
pci_fin_read1:
199
                ; restore configuration control
200
        xchg    eax, [esp]
201
        mov     dx, 0xcf8
202
        out     dx, eax
203
 
204
        pop     eax
205
        pop     esi ebx
206
        ret
207
pci_read_reg_2:
208
 
209
        test    bh, 128 ;mech#2 only supports 16 devices per bus
210
        jnz     pci_read_reg_err
211
 
212
        mov     esi, eax ; save register size into ESI
213
        and     esi, 3
214
 
215
        push    eax
216
                ;store current state of config space
217
        mov     dx, 0xcf8
218
        in      al, dx
219
        mov     ah, al
220
        mov     dl, 0xfa
221
        in      al, dx
222
 
223
        xchg    eax, [esp]
224
                ; out 0xcfa,bus
225
        mov     al, ah
226
        out     dx, al
227
                ; out 0xcf8,0x80
228
        mov     dl, 0xf8
229
        mov     al, 0x80
230
        out     dx, al
231
                ; compute addr
232
        shr     bh, 3; func is ignored in mechanism 2
233
        or      bh, 0xc0
234
        mov     dx, bx
235
 
236
        or      esi, esi
237
        jz      pci_read_byte2
238
        cmp     esi, 1
239
        jz      pci_read_word2
240
        cmp     esi, 2
241
        jz      pci_read_dword2
242
        jmp     pci_fin_read2
243
 
244
pci_read_byte2:
245
        in      al, dx
246
        jmp     pci_fin_read2
247
pci_read_word2:
248
        in      ax, dx
249
        jmp     pci_fin_read2
250
pci_read_dword2:
251
        in      eax, dx
252
;       jmp pci_fin_read2
253
pci_fin_read2:
254
 
255
                ; restore configuration space
256
        xchg    eax, [esp]
257
        mov     dx, 0xcfa
258
        out     dx, al
259
        mov     dl, 0xf8
260
        mov     al, ah
261
        out     dx, al
262
 
263
        pop     eax
264
        pop     esi ebx
265
        ret
266
 
267
pci_read_reg_err:
268
        xor     eax, eax
269
        dec     eax
270
        pop     esi ebx
271
        ret
272
 
273
 
274
;***************************************************************************
275
;   Function
276
;      pci_write_reg:
277
;
278
;   Description
279
;       write a register from ECX/CX/CL into the PCI config space
280
;       IN: ah=bus,device+func=bh,register address (dword aligned)=bl,
281
;           value to write in ecx
282
;           number of bytes to write (1,2,4) coded into AL, bits 0-1
283
;           (0 - byte, 1 - word, 2 - dword)
284
;***************************************************************************
285
 
286
align 4
287
 
288
pci_write_reg:
289
        push    esi ebx
290
        cmp     byte [BOOT_VARS+0x9020], 2;what mechanism will we use?
291
        je      pci_write_reg_2
292
 
293
                ; mechanism 1
294
        mov     esi, eax ; save register size into ESI
295
        and     esi, 3
296
 
297
        call    pci_make_config_cmd
298
        mov     ebx, eax
299
                ; get current state into ecx
300
        mov     dx, 0xcf8
301
        in      eax, dx
302
        push    eax
303
                ; set up addressing to config data
304
        mov     eax, ebx
305
        and     al, 0xfc; make address dword-aligned
306
        out     dx, eax
307
                ; write DWORD of config data
308
        mov     dl, 0xfc
309
        and     bl, 3
310
        or      dl, bl
311
        mov     eax, ecx
312
 
313
        or      esi, esi
314
        jz      pci_write_byte1
315
        cmp     esi, 1
316
        jz      pci_write_word1
317
        cmp     esi, 2
318
        jz      pci_write_dword1
319
        jmp     pci_fin_write1
320
 
321
pci_write_byte1:
322
        out     dx, al
323
        jmp     pci_fin_write1
324
pci_write_word1:
325
        out     dx, ax
326
        jmp     pci_fin_write1
327
pci_write_dword1:
328
        out     dx, eax
329
        jmp     pci_fin_write1
330
pci_fin_write1:
331
 
332
                ; restore configuration control
333
        pop     eax
334
        mov     dl, 0xf8
335
        out     dx, eax
336
 
337
        xor     eax, eax
338
        pop     ebx esi
339
 
340
        ret
341
pci_write_reg_2:
342
 
343
        test    bh, 128 ;mech#2 only supports 16 devices per bus
344
        jnz     pci_write_reg_err
345
 
346
 
347
        mov     esi, eax ; save register size into ESI
348
        and     esi, 3
349
 
350
        push    eax
351
                ;store current state of config space
352
        mov     dx, 0xcf8
353
        in      al, dx
354
        mov     ah, al
355
        mov     dl, 0xfa
356
        in      al, dx
357
        xchg    eax, [esp]
358
                ; out 0xcfa,bus
359
        mov     al, ah
360
        out     dx, al
361
                ; out 0xcf8,0x80
362
        mov     dl, 0xf8
363
        mov     al, 0x80
364
        out     dx, al
365
                ; compute addr
366
        shr     bh, 3; func is ignored in mechanism 2
367
        or      bh, 0xc0
368
        mov     dx, bx
369
                ; write register
370
        mov     eax, ecx
371
 
372
        or      esi, esi
373
        jz      pci_write_byte2
374
        cmp     esi, 1
375
        jz      pci_write_word2
376
        cmp     esi, 2
377
        jz      pci_write_dword2
378
        jmp     pci_fin_write2
379
 
380
pci_write_byte2:
381
        out     dx, al
382
        jmp     pci_fin_write2
383
pci_write_word2:
384
        out     dx, ax
385
        jmp     pci_fin_write2
386
pci_write_dword2:
387
        out     dx, eax
388
        jmp     pci_fin_write2
389
pci_fin_write2:
390
                ; restore configuration space
391
        pop     eax
392
        mov     dx, 0xcfa
393
        out     dx, al
394
        mov     dl, 0xf8
395
        mov     al, ah
396
        out     dx, al
397
 
398
        xor     eax, eax
399
        pop     ebx esi
400
        ret
401
 
402
pci_write_reg_err:
403
        xor     eax, eax
404
        dec     eax
405
        pop     ebx esi
406
        ret
407
 
408
if defined mmio_pci_addr        ; must be set above
409
;***************************************************************************
410
;   Function
411
;      pci_mmio_init
412
;
413
;   Description
414
;       IN:  bx = device's PCI bus address (bbbbbbbbdddddfff)
415
;   Returns  eax = user heap space available (bytes)
416
;   Error codes
417
;       eax = -1 : PCI user access blocked,
418
;       eax = -2 : device not registered for uMMIO service
419
;       eax = -3 : user heap initialization failure
420
;***************************************************************************
421
pci_mmio_init:
422
        cmp     bx, mmio_pci_addr
423
        jz      @f
424
        mov     eax, -2
425
        ret
426
@@:
427
        call    init_heap  ; (if not initialized yet)
428
        or      eax, eax
429
        jz      @f
430
        ret
431
@@:
432
        mov     eax, -3
433
        ret
434
 
435
 
436
;***************************************************************************
437
;   Function
438
;      pci_mmio_map
439
;
440
;   Description
441
;       maps a block of PCI memory to user-accessible linear address
442
;
443
;       WARNING! This VERY EXPERIMENTAL service is for one chosen PCI device only!
444
;       The target device address should be set in kernel var mmio_pci_addr
445
;
446
;       IN:  ah = BAR#;
447
;       IN: ebx = block size (bytes);
448
;       IN: ecx = offset in MMIO block (in 4K-pages, to avoid misaligned pages);
449
;
450
;   Returns eax = MMIO block's linear address in the userspace (if no error)
451
;
452
;
453
;   Error codes
454
;       eax = -1 : user access to PCI blocked,
455
;       eax = -2 : an invalid BAR register referred
456
;       eax = -3 : no i/o space on that BAR
457
;       eax = -4 : a port i/o BAR register referred
458
;       eax = -5 : dynamic userspace allocation problem
459
;***************************************************************************
460
 
461
pci_mmio_map:
462
        and     edx, 0x0ffff
463
        cmp     ah, 6
464
        jc      .bar_0_5
465
        jz      .bar_rom
466
        mov     eax, -2
467
        ret
468
.bar_rom:
469
        mov     ah, 8   ; bar6 = Expansion ROM base address
470
.bar_0_5:
471
        push    ecx
472
        add     ebx, 4095
473
        and     ebx, -4096
474
        push    ebx
475
        mov     bl, ah  ; bl = BAR# (0..5), however bl=8 for BAR6
476
        shl     bl, 1
477
        shl     bl, 1
478
        add     bl, 0x10; now bl = BAR offset in PCI config. space
479
        mov     ax, mmio_pci_addr
480
        mov     bh, al  ; bh = dddddfff
481
        mov     al, 2   ; al : DW to read
482
        call    pci_read_reg
483
        or      eax, eax
484
        jnz     @f
485
        mov     eax, -3 ; empty I/O space
486
        jmp     mmio_ret_fail
487
@@:
488
        test    eax, 1
489
        jz      @f
490
        mov     eax, -4 ; damned ports (not MMIO space)
491
        jmp     mmio_ret_fail
492
@@:
493
        pop     ecx     ; ecx = block size, bytes (expanded to whole page)
494
        mov     ebx, ecx; user_alloc destroys eax, ecx, edx, but saves ebx
495
        and     eax, 0xFFFFFFF0
496
        push    eax           ; store MMIO physical address + keep 2DWords in the stack
497
        stdcall user_alloc, ecx
498
        or      eax, eax
499
        jnz     mmio_map_over
500
        mov     eax, -5 ; problem with page allocation
501
 
502
mmio_ret_fail:
503
        pop     ecx
504
        pop     edx
505
        ret
506
 
507
mmio_map_over:
508
        mov     ecx, ebx; ecx = size (bytes, expanded to whole page)
509
        shr     ecx, 12 ; ecx = number of pages
510
        mov     ebx, eax; ebx = linear address
511
        pop     eax     ; eax = MMIO start
512
        pop     edx     ; edx = MMIO shift (pages)
513
        shl     edx, 12 ; edx = MMIO shift (bytes)
514
        add     eax, edx; eax = uMMIO physical address
515
        or      eax, PG_SHARED
516
        or      eax, PG_UW
517
        or      eax, PG_NOCACHE
518
        mov     edi, ebx
519
        call    commit_pages
520
        mov     eax, edi
521
        ret
522
 
523
;***************************************************************************
524
;   Function
525
;      pci_mmio_unmap_page
526
;
527
;   Description
528
;       unmaps the linear space previously tied to a PCI memory block
529
;
530
;       IN: ebx = linear address of space previously allocated by pci_mmio_map
531
;       returns eax = 1 if successfully unmapped
532
;
533
;   Error codes
534
;       eax = -1 if no user PCI access allowed,
535
;       eax =  0 if unmapping failed
536
;***************************************************************************
537
 
538
pci_mmio_unmap:
539
        stdcall user_free, ebx
540
        ret
541
 
542
end if
543
 
544
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
545
uglobal
546
align 4
547
; VendID (2), DevID (2), Revision = 0 (1), Class Code (3), FNum (1), Bus (1)
548
pci_emu_dat:
549
                times   30*10 db 0
550
endg
551
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
552
align 4
553
sys_pcibios:
554
        cmp     [pci_access_enabled], 1
555
        jne     .unsupported_func
556
        cmp     [pci_bios_entry], 0
557
        jz      .emulate_bios
558
 
559
        push    ds
560
        mov     ax, pci_data_sel
561
        mov     ds, ax
562
        mov     eax, ebp
563
        mov     ah, 0B1h
564
        call    pword [cs:pci_bios_entry]
565
        pop     ds
566
 
567
        jmp     .return
568
        ;-=-=-=-=-=-=-=-=
569
.emulate_bios:
570
        cmp     ebp, 1                  ; PCI_FUNCTION_ID
571
        jnz     .not_PCI_BIOS_PRESENT
572
        mov     edx, 'PCI '
573
        mov     al, [BOOT_VARS + 0x9020]
574
        mov     bx, [BOOT_VARS + 0x9022]
575
        mov     cl, [BOOT_VARS + 0x9021]
576
        xor     ah, ah
577
        jmp     .return_abcd
578
 
579
.not_PCI_BIOS_PRESENT:
580
        cmp     ebp, 2                  ; FIND_PCI_DEVICE
581
        jne     .not_FIND_PCI_DEVICE
582
        mov     ebx, pci_emu_dat
583
..nxt:
584
        cmp     [ebx], dx
585
        jne     ..no
586
        cmp     [ebx + 2], cx
587
        jne     ..no
588
        dec     si
589
        jns     ..no
590
        mov     bx, [ebx + 4]
591
        xor     ah, ah
592
        jmp     .return_ab
593
..no:
594
        cmp     word[ebx], 0
595
        je      ..dev_not_found
596
        add     ebx, 10
597
        jmp     ..nxt
598
..dev_not_found:
599
        mov     ah, 0x86                ; DEVICE_NOT_FOUND
600
        jmp     .return_a
601
 
602
.not_FIND_PCI_DEVICE:
603
        cmp     ebp, 3                  ; FIND_PCI_CLASS_CODE
604
        jne     .not_FIND_PCI_CLASS_CODE
605
        mov     esi, pci_emu_dat
606
        shl     ecx, 8
607
..nxt2:
608
        cmp     [esi], ecx
609
        jne     ..no2
610
        mov     bx, [esi]
611
        xor     ah, ah
612
        jmp     .return_ab
613
..no2:
614
        cmp     dword[esi], 0
615
        je      ..dev_not_found
616
        add     esi, 10
617
        jmp     ..nxt2
618
 
619
.not_FIND_PCI_CLASS_CODE:
620
        cmp     ebp, 8                  ; READ_CONFIG_*
621
        jb      .not_READ_CONFIG
622
        cmp     ebp, 0x0A
623
        ja      .not_READ_CONFIG
624
        mov     eax, ebp
625
        mov     ah, bh
626
        mov     edx, edi
627
        mov     bh, bl
628
        mov     bl, dl
629
        call    pci_read_reg
630
        mov     ecx, eax
631
        xor     ah, ah                  ; SUCCESSFUL
632
        jmp     .return_abc
633
.not_READ_CONFIG:
634
        cmp     ebp, 0x0B               ; WRITE_CONFIG_*
635
        jb      .not_WRITE_CONFIG
636
        cmp     ebp, 0x0D
637
        ja      .not_WRITE_CONFIG
638
        lea     eax, [ebp+1]
639
        mov     ah, bh
640
        mov     edx, edi
641
        mov     bh, bl
642
        mov     bl, dl
643
        call    pci_write_reg
644
        xor     ah, ah                  ; SUCCESSFUL
645
        jmp     .return_abc
646
.not_WRITE_CONFIG:
647
.unsupported_func:
648
        mov     ah, 0x81                ; FUNC_NOT_SUPPORTED
649
.return:
650
        mov     dword[esp + 4 ], edi
651
        mov     dword[esp + 8], esi
652
.return_abcd:
653
        mov     dword[esp + 24], edx
654
.return_abc:
655
        mov     dword[esp + 28], ecx
656
.return_ab:
657
        mov     dword[esp + 20], ebx
658
.return_a:
659
        mov     dword[esp + 32], eax
660
        ret
661
 
662
proc pci_enum
663
        push    ebp
664
        mov     ebp, esp
665
        push    0
666
virtual at ebp-4
667
.devfn          db      ?
668
.bus            db      ?
669
end virtual
670
.loop:
671
        mov     ah, [.bus]
672
        mov     al, 2
673
        mov     bh, [.devfn]
674
        mov     bl, 0
675
        call    pci_read_reg
676
        cmp     eax, 0xFFFFFFFF
677
        jnz     .has_device
678
        test    byte [.devfn], 7
679
        jnz     .next_func
680
        jmp     .no_device
681
.has_device:
682
        push    eax
683
        movi    eax, sizeof.PCIDEV
684
        call    malloc
685
        pop     ecx
686
        test    eax, eax
687
        jz      .nomemory
688
        mov     edi, eax
689
        mov     [edi+PCIDEV.vendor_device_id], ecx
690
        mov     eax, pcidev_list
691
        mov     ecx, [eax+PCIDEV.bk]
692
        mov     [edi+PCIDEV.bk], ecx
693
        mov     [edi+PCIDEV.fd], eax
694
        mov     [ecx+PCIDEV.fd], edi
695
        mov     [eax+PCIDEV.bk], edi
696
        mov     eax, dword [.devfn]
697
        mov     dword [edi+PCIDEV.devfn], eax
698
        mov     dword [edi+PCIDEV.owner], 0
699
        mov     bh, al
700
        mov     al, 2
701
        mov     bl, 8
702
        call    pci_read_reg
703
        shr     eax, 8
704
        mov     [edi+PCIDEV.class], eax
705
        test    byte [.devfn], 7
706
        jnz     .next_func
707
        mov     ah, [.bus]
708
        mov     al, 0
709
        mov     bh, [.devfn]
710
        mov     bl, 0Eh
711
        call    pci_read_reg
712
        test    al, al
713
        js      .next_func
714
.no_device:
715
        or      byte [.devfn], 7
716
.next_func:
717
        inc     dword [.devfn]
718
        mov     ah, [.bus]
719
        cmp     ah, [BOOT_VARS+0x9021]
720
        jbe     .loop
721
.nomemory:
722
        leave
723
        ret
724
endp
4587 Serge 725
 
726
; Export for drivers. Just returns the pointer to the pci-devices list.
727
proc get_pcidev_list
728
        mov     eax, pcidev_list
729
        ret
730
endp