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