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