Rev 5866 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4476 | hidnplayr | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
||
8038 | hidnplayr | 3 | ;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;; |
4476 | hidnplayr | 4 | ;; Distributed under terms of the GNU General Public License ;; |
5 | ;; ;; |
||
6 | ;; PCMCIA aka cardbus driver for KolibriOS ;; |
||
7 | ;; Written by hidnplayr@gmail.com ;; |
||
8 | ;; ;; |
||
9 | ;; Many credits go to Paolo Franchetti for his HWTEST program ;; |
||
10 | ;; (https://sites.google.com/site/pfranz73/) from which large ;; |
||
11 | ;; parts of code have been borrowed. ;; |
||
12 | ;; ;; |
||
13 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
14 | |||
15 | ; This module detects and initialises all Cardbus/pc-card/PCMCIA cards. |
||
16 | |||
17 | ; WARNING: Cards must be inserted before the driver starts, and shouldn't be removed. |
||
18 | ; This module doesn't handle insertions and removals. |
||
19 | |||
5866 | hidnplayr | 20 | ; TODO: |
21 | ; |
||
22 | ; Use GetPCIList instead of reading directly from PCI bus to detect bridge. |
||
23 | ; (See #5544 agp.asm for example). |
||
24 | ; Export a function in kernel to re-scan PCI device list (fix 'dirty hack'). |
||
25 | ; Fix bugs (currently not working on all PCMCIA bridges). |
||
26 | |||
5066 | hidnplayr | 27 | format PE DLL native |
28 | entry START |
||
4476 | hidnplayr | 29 | |
5066 | hidnplayr | 30 | CURRENT_API = 0x0200 |
31 | COMPATIBLE_API = 0x0100 |
||
32 | API_VERSION = (COMPATIBLE_API shl 16) + CURRENT_API |
||
4476 | hidnplayr | 33 | |
8038 | hidnplayr | 34 | CARDBUS_IO_BASE = 0x1400 |
35 | CARDBUS_IO_SIZE = 0x100 |
||
36 | CARDBUS_IRQ = 0x0A |
||
4476 | hidnplayr | 37 | |
38 | __DEBUG__ = 1 |
||
39 | __DEBUG_LEVEL__ = 1 |
||
40 | |||
5066 | hidnplayr | 41 | section '.flat' readable writable executable |
4476 | hidnplayr | 42 | |
5066 | hidnplayr | 43 | include '../proc32.inc' |
4476 | hidnplayr | 44 | include '../struct.inc' |
45 | include '../macros.inc' |
||
5074 | hidnplayr | 46 | include '../pci.inc' |
4476 | hidnplayr | 47 | include '../fdo.inc' |
48 | |||
49 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
50 | ;; ;; |
||
51 | ;; proc START ;; |
||
52 | ;; ;; |
||
53 | ;; (standard driver proc) ;; |
||
54 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
55 | |||
5066 | hidnplayr | 56 | proc START c, reason:dword, cmdline:dword |
4476 | hidnplayr | 57 | |
5066 | hidnplayr | 58 | cmp [reason], DRV_ENTRY |
59 | jne .fail |
||
4476 | hidnplayr | 60 | |
61 | DEBUGF 1, "Loading cardbus driver\n" |
||
5066 | hidnplayr | 62 | invoke RegService, my_service, service_proc |
4476 | hidnplayr | 63 | |
64 | call detect |
||
65 | |||
66 | ret |
||
67 | |||
68 | .fail: |
||
69 | xor eax, eax |
||
70 | ret |
||
71 | |||
72 | endp |
||
73 | |||
74 | |||
75 | |||
76 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
77 | ;; ;; |
||
78 | ;; proc SERVICE_PROC ;; |
||
79 | ;; ;; |
||
80 | ;; (standard driver proc) ;; |
||
81 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
82 | |||
83 | proc service_proc stdcall, ioctl:dword |
||
84 | |||
85 | mov edx, [ioctl] |
||
86 | mov eax, [edx + IOCTL.io_code] |
||
87 | |||
88 | ;------------------------------------------------------ |
||
89 | |||
90 | cmp eax, 0 ;SRV_GETVERSION |
||
91 | jne .fail |
||
92 | |||
93 | cmp [edx + IOCTL.out_size], 4 |
||
94 | jb .fail |
||
95 | mov eax, [edx + IOCTL.output] |
||
96 | mov [eax], dword API_VERSION |
||
97 | |||
98 | xor eax, eax |
||
99 | ret |
||
100 | |||
101 | .fail: |
||
102 | or eax, -1 |
||
103 | ret |
||
104 | |||
105 | endp |
||
106 | |||
107 | align 4 |
||
108 | proc detect |
||
109 | |||
110 | locals |
||
111 | last_bus dd ? |
||
112 | card_bus dd ? |
||
113 | bus dd ? |
||
114 | devfn dd ? |
||
115 | endl |
||
116 | |||
117 | DEBUGF 1, "Searching for cardbus bridges...\n" |
||
118 | |||
119 | xor eax, eax |
||
120 | mov [bus], eax |
||
121 | inc eax |
||
5066 | hidnplayr | 122 | invoke PciApi |
4476 | hidnplayr | 123 | cmp eax, -1 |
124 | je .err |
||
125 | mov [last_bus], eax |
||
126 | |||
127 | inc eax |
||
128 | mov [card_bus], eax |
||
129 | |||
130 | .next_bus: |
||
131 | and [devfn], 0 |
||
132 | .next_dev: |
||
5172 | hidnplayr | 133 | invoke PciRead32, [bus], [devfn], PCI_header.vendor_id |
4476 | hidnplayr | 134 | test eax, eax |
135 | jz .next |
||
136 | cmp eax, -1 |
||
137 | je .next |
||
138 | |||
5172 | hidnplayr | 139 | invoke PciRead16, [bus], [devfn], PCI_header.subclass ; class & subclass |
4476 | hidnplayr | 140 | cmp ax, 0x0607 |
141 | je .found |
||
142 | |||
143 | .next: |
||
5172 | hidnplayr | 144 | test [devfn], 7 |
145 | jnz .next_fn |
||
146 | invoke PciRead8, [bus], [devfn], PCI_header.header_type |
||
147 | test al, al |
||
148 | js .next_fn |
||
149 | or [devfn], 7 |
||
150 | |||
151 | .next_fn: |
||
4476 | hidnplayr | 152 | inc [devfn] |
153 | cmp [devfn], 256 |
||
154 | jb .next_dev |
||
155 | mov eax, [bus] |
||
156 | inc eax |
||
157 | mov [bus], eax |
||
158 | cmp eax, [last_bus] |
||
159 | jna .next_bus |
||
160 | |||
161 | DEBUGF 1, "Search complete\n" |
||
162 | xor eax, eax |
||
163 | inc eax |
||
164 | ret |
||
165 | |||
166 | .found: |
||
167 | DEBUGF 1, "Found cardbus bridge: bus=0x%x, dev=0x%x\n", [bus], [devfn] |
||
168 | |||
5066 | hidnplayr | 169 | invoke PciRead8, [bus], [devfn], PCI_header.header_type |
5172 | hidnplayr | 170 | and al, not 0x80 ; Mask the multifunction device bit |
4476 | hidnplayr | 171 | DEBUGF 1, "Header type=0x%x\n", eax:2 |
5066 | hidnplayr | 172 | cmp al, 2 |
173 | jne .next |
||
4476 | hidnplayr | 174 | |
175 | ; Write PCI and cardbus numbers |
||
176 | |||
5066 | hidnplayr | 177 | invoke PciRead32, [bus], [devfn], PCI_header02.pci_bus_nr ; PCcard latency settings + Card bus number, PCI bus number |
178 | and eax, 0xff000000 ; Keep original latency setting, clear the rest |
||
4476 | hidnplayr | 179 | mov al, byte[bus] |
180 | mov ah, byte[card_bus] |
||
8038 | hidnplayr | 181 | mov ebx, [card_bus] ; sub bus nr??? |
4476 | hidnplayr | 182 | shl ebx, 16 |
183 | or eax, ebx |
||
184 | DEBUGF 1, "Latency, bus,.. 0x%x\n", eax |
||
5066 | hidnplayr | 185 | invoke PciWrite32, [bus], [devfn], PCI_header02.pci_bus_nr, eax |
4476 | hidnplayr | 186 | |
187 | ; set ExCA legacy mode base |
||
188 | |||
5066 | hidnplayr | 189 | invoke PciWrite32, [bus], [devfn], 0x44, 1 |
4476 | hidnplayr | 190 | |
191 | ; Enable power |
||
192 | |||
5066 | hidnplayr | 193 | invoke PciRead8, [bus], [devfn], 0x14 ; get capabilities offset |
4476 | hidnplayr | 194 | movzx eax, al ; (A0 for TI bridges) |
195 | DEBUGF 1, "Capabilities offset=0x%x\n", eax:2 |
||
196 | add al, 4 ; Power management control/status |
||
5066 | hidnplayr | 197 | invoke PciWrite16, [bus], [devfn], eax, 0x0100 ; Enable PME signaling, power state=D0 |
4476 | hidnplayr | 198 | |
199 | ; Enable Bus master, io space, memory space |
||
200 | |||
5066 | hidnplayr | 201 | invoke PciWrite16, [bus], [devfn], PCI_header02.command, 0x0007 |
4476 | hidnplayr | 202 | |
203 | ; Write CardBus Socket/ExCA base address |
||
204 | |||
205 | mov eax, 0x7f000000 |
||
206 | push eax |
||
5066 | hidnplayr | 207 | invoke PciWrite32, [bus], [devfn], PCI_header02.base_addr, eax ; base is 4 Kbyte aligned |
4476 | hidnplayr | 208 | pop ebx |
8038 | hidnplayr | 209 | invoke MapIoMem, ebx, 4096, PG_SW+PG_NOCACHE |
4476 | hidnplayr | 210 | mov ecx, eax |
211 | |||
212 | ; Check if a card is present in the socket |
||
213 | |||
214 | mov eax, [ecx + 8] ; Socket present state register |
||
215 | DEBUGF 1, "Socket present state reg: 0x%x\n", eax |
||
216 | and al, 10110110b ; NotACard | CBCard | 16bitCard | CDetect1 | CDetect2 |
||
217 | cmp al, 00100000b ; Check for inserted cardbus card |
||
218 | je .CardbusInserted |
||
219 | |||
220 | ; No card found... set PCI command back to 0 |
||
221 | |||
5066 | hidnplayr | 222 | invoke PciWrite16, [bus], [devfn], PCI_header02.command, 0 ; To avoid conflicts with other sockets |
4476 | hidnplayr | 223 | DEBUGF 1, "Cardbus KO\n" |
224 | jmp .next |
||
225 | |||
226 | .CardbusInserted: |
||
227 | DEBUGF 1, "Card inserted\n" |
||
228 | ;mov word[ecx + 0x802], 0x00F9 ; Assert reset, output enable, vcc=vpp=3.3V |
||
229 | mov dword[ecx + 0x10], 0x33 ; Request 3.3V for Vcc and Vpp (Control register) |
||
230 | ;push ecx |
||
8038 | hidnplayr | 231 | ;mov esi, 1 |
5066 | hidnplayr | 232 | ;invoke Sleep |
4476 | hidnplayr | 233 | ;pop ecx |
234 | ;mov byte[ecx + 0x803], 0x40 ; stop reset |
||
235 | mov dword[ecx + 0xC], 0x4000 ; force Card CV test (Force register) ;;; WHY??? |
||
236 | DEBUGF 1, "Resetting card\n" |
||
237 | |||
238 | ; Next power up test can be deferred until before writing to Bridge control PCI reg 0x3E |
||
239 | .waitpower: ; For TI, you can check that bits 8-11 in PCI reg 80h are all 0 |
||
240 | test dword[ecx + 8], 1 shl 3 ; Test PWRCYCLE bit |
||
241 | jz .waitpower ; Wait for power to go up |
||
242 | |||
243 | DEBUGF 1, "Interface is powered up\n" |
||
244 | |||
245 | ; Write MemBase-Limit 0 and 1, then IOBase-Limit 0 and 1 |
||
246 | ; mem0 space limit = base => size is 4 kilobytes |
||
247 | ; set to 0 the second interval (mem1 and IO1) |
||
248 | ; IO0: size is 256 bytes |
||
249 | |||
8038 | hidnplayr | 250 | invoke PciWrite32, [bus], [devfn], PCI_header02.mbar_0, 0x7EFFF000 |
251 | invoke PciWrite32, [bus], [devfn], PCI_header02.mlimit_0, 0x7EFFF000 |
||
252 | invoke PciWrite32, [bus], [devfn], PCI_header02.mbar_1, 0 |
||
253 | invoke PciWrite32, [bus], [devfn], PCI_header02.mlimit_1, 0 |
||
254 | invoke PciWrite32, [bus], [devfn], PCI_header02.iobar_0, CARDBUS_IO |
||
255 | invoke PciWrite32, [bus], [devfn], PCI_header02.iolimit_0, CARDBUS_IO + 0xFC |
||
256 | invoke PciWrite32, [bus], [devfn], PCI_header02.iobar_1, 0 |
||
257 | invoke PciWrite32, [bus], [devfn], PCI_header02.iolimit_1, 0 |
||
258 | invoke PciWrite8, [bus], [devfn], PCI_header02.interrupt_line, CARDBUS_IRQ ; IRQ line |
||
259 | invoke PciRead16, [bus], [devfn], PCI_header02.bridge_ctrl ; Bridge control |
||
4476 | hidnplayr | 260 | or ax, 0x0700 ; Enable write posting, both memory windows prefetchable |
5066 | hidnplayr | 261 | invoke PciWrite16, [bus], [devfn], PCI_header02.bridge_ctrl, eax |
4476 | hidnplayr | 262 | DEBUGF 1, "Write posting enabled\n" |
263 | |||
264 | |||
265 | DEBUGF 1, "Bridge PCI registers:\n" |
||
266 | rept 17 reg |
||
267 | { |
||
5066 | hidnplayr | 268 | invoke PciRead32, [bus], [devfn], 4*(reg-1) |
4476 | hidnplayr | 269 | DEBUGF 1, "0x%x\n", eax |
270 | } |
||
271 | |||
272 | inc byte[0x80009021] ; LAST PCI bus count in kernel (dirty HACK!) |
||
273 | |||
274 | |||
275 | mov ecx, 100 |
||
276 | .waitactive: |
||
277 | push ecx |
||
8038 | hidnplayr | 278 | invoke PciRead32, [card_bus], 0, PCI_header.vendor_id ; Check if the card is awake yet |
4476 | hidnplayr | 279 | inc eax |
280 | jnz .got_it |
||
281 | mov esi, 2 |
||
5066 | hidnplayr | 282 | invoke Sleep |
4476 | hidnplayr | 283 | pop ecx |
284 | dec ecx |
||
285 | jnz .waitactive |
||
286 | |||
287 | DEBUGF 1, "Timeout!\n" |
||
288 | ; TODO: disable card/bridge again ? |
||
289 | jmp .next |
||
290 | |||
291 | .got_it: |
||
292 | pop eax |
||
293 | DEBUGF 1, "Card is enabled!\n" |
||
294 | |||
5066 | hidnplayr | 295 | invoke PciWrite32, [card_bus], 0, PCI_header02.base_addr, CARDBUS_IO ; Supposing it's IO space that is needed |
296 | invoke PciWrite8, [card_bus], 0, PCI_header02.interrupt_line, 0xC ; FIXME |
||
297 | invoke PciWrite16, [card_bus], 0, PCI_header02.command, PCI_CMD_PIO or PCI_CMD_MMIO |
||
4476 | hidnplayr | 298 | |
299 | DEBUGF 1, "done\n" |
||
300 | |||
301 | jmp .next |
||
302 | |||
303 | .err: |
||
304 | DEBUGF 1, "Error\n" |
||
305 | xor eax, eax |
||
306 | |||
307 | ret |
||
308 | |||
309 | endp |
||
310 | |||
311 | |||
5066 | hidnplayr | 312 | ; End of code |
4476 | hidnplayr | 313 | |
5066 | hidnplayr | 314 | data fixups |
315 | end data |
||
4476 | hidnplayr | 316 | |
5066 | hidnplayr | 317 | include '../peimport.inc' |
4476 | hidnplayr | 318 | |
319 | my_service db 'CARDBUS',0 ; max 16 chars include zero |
||
320 | |||
321 | include_debug_strings ; All data wich FDO uses will be included here |