BIOS.PCI.Mod 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. MODULE PCI; (** author: fof -- PCI without using PCI bios (using PCI tables described in OSDev wiki ) *)
  2. IMPORT SYSTEM, Machine, KernelLog;
  3. CONST
  4. Trace = TRUE;
  5. PciAdrReg=0CF8H;
  6. PciDataReg = 0CFCH;
  7. (* PCI Configuration Registers *)
  8. DevReg* = 0H; CmdReg* = 4H; RevIdReg* = 8H; CLSReg* = 0CH;
  9. Adr0Reg* = 10H; Adr1Reg* = 14H; Adr2Reg* = 18H;
  10. Adr3Reg* = 1CH; Adr4Reg* = 20H; Adr5Reg* = 24H;
  11. CISReg* = 28H; SubvReg* = 2CH; ROMReg* = 30H; IntlReg* = 3CH;
  12. (* PCI Command register encoding, used as arguments for Enable *)
  13. IOSpace* = {0};
  14. MemorySpace* = {1};
  15. BusMaster* = {2};
  16. debug = TRUE;
  17. Done* = 0; NoPCI* = -1; NoBios32* = -1; Error* = -2;
  18. FuncNotSupported* = 81H; BadVendorId* = 83H; DeviceNotFound* = 86H;
  19. BadRegisterNumber* = 87H; SetFailed* = 88H; BufferTooSmall* = 89H;
  20. PCIServiceId = 49435024H; (* "$PCI" *)
  21. PCIString = 20494350H; (* " PCI" *)
  22. PCIFunctionId = 0B1H*256;
  23. PCIBiosPresent = 1H; findPCIDevice = 2H; findPCIClassCode = 3H; generateSpecialCycle = 6H;
  24. readConfigByte = 8H; readConfigWord = 9H; readConfigDword = 0AH;
  25. writeConfigByte = 0BH; writeConfigWord = 0CH; writeConfigDword = 0DH;
  26. getIrqRoutingOptions = 0EH; setPCIIrq = 0FH;
  27. TYPE
  28. RouteTable* = POINTER TO RouteTableDesc;
  29. RouteTableDesc* = RECORD
  30. busNr*, devNr*, slotNr*: LONGINT;
  31. linkValIntA*, linkValIntB*, linkValIntC*, linkValIntD*: CHAR;
  32. IrqBitmapA*, IrqBitmapB*, IrqBitmapC*, IrqBitmapD*: SET;
  33. next*: RouteTable
  34. END;
  35. (*
  36. RouteBuffer = RECORD
  37. BufferSize, SegSelector: INTEGER;
  38. DataBufferAdr: ADDRESS
  39. END;
  40. *)
  41. Pci* = RECORD bus*, device*, function*: LONGINT END;
  42. VAR
  43. pciEnabled: BOOLEAN;
  44. PROCEDURE PCIPresent*(VAR version, lastPCIbus, hwMech: LONGINT): WORD;
  45. VAR res: WORD; pci: Pci; r0: LONGINT;
  46. BEGIN {EXCLUSIVE}
  47. IF pciEnabled THEN
  48. StartIterate(pci);
  49. lastPCIbus := 0;
  50. REPEAT
  51. res := PCIReadConfig32(pci.bus, pci.device, pci.function, 0, r0);
  52. IF r0 # LONGINT(0FFFFFFFFH) THEN
  53. IF lastPCIbus < pci.bus THEN lastPCIbus := pci.bus END;
  54. END;
  55. UNTIL ~Iterate(pci);
  56. res := Done;
  57. IF debug THEN
  58. KernelLog.String("PCIPresent, lastbus ="); KernelLog.Int(lastPCIbus,1); KernelLog.Ln;
  59. END
  60. ELSE
  61. res := NoPCI
  62. END;
  63. RETURN res
  64. END PCIPresent;
  65. PROCEDURE FindPCIDevice*(devId, vendId, idx: LONGINT; VAR busNr, devNr, fktNr: LONGINT): WORD;
  66. VAR pci: Pci; r0, vendorId, deviceId, index: LONGINT; res: WORD;
  67. BEGIN {EXCLUSIVE}
  68. IF pciEnabled THEN
  69. StartIterate(pci); index := 0;
  70. REPEAT
  71. res := PCIReadConfig32(pci.bus, pci.device, pci.function, 0, r0);
  72. IF r0 # LONGINT(0FFFFFFFFH) THEN
  73. vendorId := r0 MOD 10000H;
  74. deviceId := r0 DIV 10000H MOD 10000H;
  75. IF (devId = deviceId) & (vendId = vendorId) THEN
  76. IF idx = index THEN
  77. busNr := pci.bus; devNr := pci.device; fktNr := pci.function;
  78. IF debug THEN
  79. KernelLog.String("FindPCIDevice ");
  80. KernelLog.Int(devId,1); KernelLog.String(", ");
  81. KernelLog.Int(vendId,1); KernelLog.String(",");
  82. KernelLog.Int(idx,1);
  83. KernelLog.String(" found."); KernelLog.Ln;
  84. END;
  85. RETURN Done
  86. ELSE INC(index)
  87. END;
  88. END;
  89. END;
  90. UNTIL ~Iterate(pci);
  91. res := DeviceNotFound
  92. ELSE
  93. res := NoPCI
  94. END;
  95. RETURN res
  96. END FindPCIDevice;
  97. PROCEDURE FindPCIClassCode*(classCode, idx: LONGINT; VAR busNr, devNr, fktNr: LONGINT): WORD;
  98. VAR pci: Pci; r0, r8, index, class: LONGINT; res: WORD;
  99. BEGIN {EXCLUSIVE}
  100. IF pciEnabled THEN
  101. StartIterate(pci);
  102. REPEAT
  103. res := PCIReadConfig32(pci.bus, pci.device, pci.function, 0, r0);
  104. IF r0 # LONGINT(0FFFFFFFFH) THEN
  105. res := PCIReadConfig32(pci.bus, pci.device, pci.function, 8, r8);
  106. class := r8 DIV 100H MOD 1000000H;
  107. IF (classCode = class) THEN
  108. IF idx = index THEN
  109. busNr := pci.bus; devNr := pci.device; fktNr := pci.function;
  110. IF debug THEN
  111. KernelLog.String("FindPCIClassCode ");
  112. KernelLog.Int(classCode,1); KernelLog.String(","); KernelLog.Int(idx,1);
  113. KernelLog.String(" found."); KernelLog.Ln;
  114. END;
  115. RETURN Done
  116. ELSE INC(index)
  117. END;
  118. END;
  119. END;
  120. UNTIL ~Iterate(pci);
  121. res := DeviceNotFound;
  122. ELSE
  123. res := NoPCI
  124. END;
  125. RETURN res
  126. END FindPCIClassCode;
  127. PROCEDURE GenerateSpecialCycle*(busNr, specCycleData: LONGINT): WORD;
  128. VAR res: WORD;
  129. BEGIN {EXCLUSIVE}
  130. IF pciEnabled THEN
  131. (*
  132. eax := PCIFunctionId + generateSpecialCycle;
  133. ebx := busNr*100H; edx := specCycleData;
  134. state := Machine.DisableInterrupts();
  135. pcicall(pciEntry, eax, ebx, ecx, edx, esi, edi, eflags);
  136. Machine.RestoreInterrupts(state);
  137. res := (eax DIV 100H) MOD 100H; ASSERT(~((0 IN eflags) & (res=0)));
  138. IF debug THEN
  139. KernelLog.String("GenerateSpecialCycle:"); KernelLog.Ln;
  140. OutRegs(eax, ebx, ecx, edx, esi, edi, eflags)
  141. END
  142. *)
  143. ELSE
  144. res := NoPCI
  145. END;
  146. RETURN res
  147. END GenerateSpecialCycle;
  148. PROCEDURE GetIrqRoutingOptions*(VAR rt: RouteTable; VAR IrqBitmap: SET): WORD;
  149. CONST dbN = 16*8;
  150. VAR
  151. res: WORD;
  152. (*eflags, state: SET;
  153. rb: RouteBuffer; db: ARRAY dbN OF CHAR;
  154. last: RouteTable;
  155. *)
  156. BEGIN {EXCLUSIVE}
  157. IF pciEnabled THEN
  158. (*
  159. eax := PCIFunctionId + getIrqRoutingOptions;
  160. rb.BufferSize := dbN; rb.SegSelector := 0; rb.DataBufferAdr := ADDRESSOF(db[0]);
  161. ebx := 0H; edi := Machine.Ensure32BitAddress(SYSTEM.VAL (ADDRESS, rb));
  162. state := Machine.DisableInterrupts();
  163. pcicall(pciEntry, eax, ebx, ecx, edx, esi, edi, eflags);
  164. Machine.RestoreInterrupts(state);
  165. res := (eax DIV 100H) MOD 100H; ASSERT(~((0 IN eflags) & (res=0)));
  166. ASSERT(res # BufferTooSmall); (* Increase dbN on Trap *)
  167. IF ~(0 IN eflags) & (res = Done) THEN
  168. IrqBitmap := SYSTEM.VAL(SET, ebx);
  169. NEW(rt); rt.next := NIL; last := rt; i := 0;
  170. WHILE i < rb.BufferSize DO
  171. NEW(last.next); last := last.next; last.next := NIL;
  172. last.busNr := ORD(db[i]); INC(i);
  173. last.devNr := ORD(db[i]) DIV 8; INC(i);
  174. last.linkValIntA := db[i]; INC(i);
  175. last.IrqBitmapA := SYSTEM.VAL(SET, LONG(ORD(db[i])+ORD(db[i+1])*100H)); INC(i, 2);
  176. last.linkValIntB := db[i]; INC(i);
  177. last.IrqBitmapB := SYSTEM.VAL(SET, LONG(ORD(db[i])+ORD(db[i+1])*100H)); INC(i, 2);
  178. last.linkValIntC:= db[i]; INC(i);
  179. last.IrqBitmapC := SYSTEM.VAL(SET, LONG(ORD(db[i])+ORD(db[i+1])*100H)); INC(i, 2);
  180. last.linkValIntD := db[i]; INC(i);
  181. last.IrqBitmapD := SYSTEM.VAL(SET, LONG(ORD(db[i])+ORD(db[i+1])*100H)); INC(i, 2);
  182. last.slotNr := ORD(db[i]); INC(i);
  183. INC(i) (* reserved byte *)
  184. END;
  185. rt := rt.next
  186. END;
  187. IF debug THEN
  188. KernelLog.String("GetIrqRoutingOptions:"); KernelLog.Ln;
  189. OutRegs(eax, ebx, ecx, edx, esi, edi, eflags)
  190. END
  191. *)
  192. ELSE
  193. res := NoPCI
  194. END;
  195. RETURN res
  196. END GetIrqRoutingOptions;
  197. PROCEDURE SetPCIIrq*(IntPin, IrqNum, busNr, devNr, fktNr: LONGINT): WORD;
  198. VAR res: WORD;
  199. BEGIN {EXCLUSIVE}
  200. IF pciEnabled THEN
  201. (*
  202. eax := PCIFunctionId + setPCIIrq;
  203. ecx := IrqNum*100H + IntPin; ebx := busNr*100H+devNr*8+fktNr;
  204. state := Machine.DisableInterrupts();
  205. pcicall(pciEntry, eax, ebx, ecx, edx, esi, edi, eflags);
  206. Machine.RestoreInterrupts(state);
  207. res := (eax DIV 100H) MOD 100H; ASSERT(~((0 IN eflags) & (res=0)));
  208. IF debug THEN
  209. KernelLog.String("SetPCIHwInt:"); KernelLog.Ln;
  210. OutRegs(eax, ebx, ecx, edx, esi, edi, eflags)
  211. END
  212. *)
  213. ELSE
  214. res := NoPCI
  215. END;
  216. RETURN res
  217. END SetPCIIrq;
  218. (** Set bits included in <mask> in the PCI command register if not set already *)
  219. PROCEDURE Enable*(mask : SET; busNr, devNr, fktNr : LONGINT) : WORD;
  220. VAR cmdReg : LONGINT; res : WORD;
  221. BEGIN
  222. res := ReadConfigWord(busNr, devNr, fktNr, CmdReg, cmdReg);
  223. IF (res = Done) THEN
  224. IF mask - SYSTEM.VAL(SET, cmdReg) # {} THEN
  225. cmdReg := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, cmdReg) + mask);
  226. res := WriteConfigWord(busNr, devNr, fktNr, CmdReg, cmdReg);
  227. IF (res = Done) THEN (* maybe the device does not implement all bits writable... check! *)
  228. res := ReadConfigWord(busNr, devNr, fktNr, CmdReg, cmdReg);
  229. IF (res = Done) THEN
  230. IF mask - SYSTEM.VAL(SET, cmdReg) # {} THEN (* at least one bit is not set *)
  231. res := Error;
  232. END;
  233. END;
  234. END;
  235. END;
  236. END;
  237. RETURN res;
  238. END Enable;
  239. PROCEDURE ReadConfigByte*(busNr, devNr, fktNr, regNr: LONGINT; VAR regVal: LONGINT): WORD;
  240. BEGIN
  241. RETURN PCIReadConfig8(busNr, devNr, fktNr, regNr, regVal)
  242. END ReadConfigByte;
  243. PROCEDURE ReadConfigWord*(busNr, devNr, fktNr, regNr: LONGINT; VAR regVal: LONGINT): WORD;
  244. BEGIN
  245. ASSERT(regNr MOD 2 = 0);
  246. RETURN PCIReadConfig16(busNr, devNr, fktNr, regNr, regVal)
  247. END ReadConfigWord;
  248. PROCEDURE ReadConfigDword*(busNr, devNr, fktNr, regNr: LONGINT; VAR regVal: LONGINT): WORD;
  249. BEGIN
  250. ASSERT(regNr MOD 4 = 0);
  251. RETURN PCIReadConfig32(busNr, devNr, fktNr, regNr, regVal)
  252. END ReadConfigDword;
  253. PROCEDURE WriteConfigByte*(busNr, devNr, fktNr, regNr, regVal: LONGINT): WORD;
  254. BEGIN
  255. RETURN PCIWriteConfig8(busNr, devNr, fktNr, regNr, regVal)
  256. END WriteConfigByte;
  257. PROCEDURE WriteConfigWord*(busNr, devNr, fktNr, regNr, regVal: LONGINT): WORD;
  258. BEGIN
  259. ASSERT(regNr MOD 2 = 0);
  260. RETURN PCIWriteConfig16(busNr, devNr, fktNr, regNr, regVal)
  261. END WriteConfigWord;
  262. PROCEDURE WriteConfigDword*(busNr, devNr, fktNr, regNr, regVal: LONGINT): WORD;
  263. BEGIN
  264. ASSERT(regNr MOD 4 = 0);
  265. RETURN PCIWriteConfig32(busNr, devNr, fktNr, regNr, regVal)
  266. END WriteConfigDword;
  267. PROCEDURE Show*;
  268. VAR version, lastPCIBus, hwMech: LONGINT; res : WORD;
  269. BEGIN
  270. IF ~PCIDisabled() THEN
  271. res := PCIPresent(version, lastPCIBus, hwMech);
  272. IF (res = Done) THEN
  273. KernelLog.Enter;
  274. KernelLog.String("PCI: "); KernelLog.Int(lastPCIBus + 1, 0); KernelLog.String(" bus(ses) found, PCI version: ");
  275. KernelLog.Hex(version DIV 256, -2); KernelLog.Char("."); KernelLog.Hex(version MOD 256, -2);
  276. KernelLog.Exit;
  277. ELSE
  278. KernelLog.Enter; KernelLog.String("PCI: No bus found."); KernelLog.Exit;
  279. END;
  280. ELSE
  281. KernelLog.Enter; KernelLog.String("PCI: Not available (Disabled by user)."); KernelLog.Exit;
  282. END;
  283. END Show;
  284. PROCEDURE GetAdr1(pciBus, pciDev, pciFn, reg, len: LONGINT; VAR adr, dataAdr: LONGINT);
  285. BEGIN
  286. adr := LONGINT(80000000H) + ASH(pciBus,16) + ASH(pciDev, 11) + ASH(pciFn, 8);
  287. adr := adr + SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET,reg) * SYSTEM.VAL(SET,0FCH));
  288. adr := adr + ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET,reg) * SYSTEM.VAL(SET,0F00H)), 16);
  289. CASE len OF
  290. 8: dataAdr := PciDataReg + SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET,reg) * SYSTEM.VAL(SET,3));
  291. |16: dataAdr := PciDataReg + SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET,reg) * SYSTEM.VAL(SET,2));
  292. |32: dataAdr := PciDataReg;
  293. END;
  294. END GetAdr1;
  295. PROCEDURE PCIReadConfig32(pciBus, pciDev, pciFn, reg: LONGINT; VAR val: LONGINT): WORD;
  296. VAR adr, dataAdr: LONGINT; state: SET; res: WORD;
  297. BEGIN
  298. IF pciEnabled THEN
  299. state := Machine.DisableInterrupts();
  300. GetAdr1(pciBus, pciDev, pciFn, reg, 32, adr, dataAdr);
  301. Machine.Portout32(PciAdrReg, adr);
  302. Machine.Portin32(dataAdr, val);
  303. Machine.RestoreInterrupts(state);
  304. res := Done;
  305. ELSE
  306. res := NoPCI
  307. END;
  308. RETURN res
  309. END PCIReadConfig32;
  310. PROCEDURE PCIReadConfig16(pciBus, pciDev, pciFn, reg: LONGINT; VAR val: LONGINT): WORD;
  311. VAR adr, dataAdr: LONGINT; state: SET; res: WORD; int: INTEGER;
  312. BEGIN
  313. IF pciEnabled THEN
  314. state := Machine.DisableInterrupts();
  315. GetAdr1(pciBus, pciDev, pciFn, reg, 16, adr, dataAdr);
  316. Machine.Portout32(PciAdrReg, adr);
  317. Machine.Portin16(dataAdr, int);
  318. val := int;
  319. Machine.RestoreInterrupts(state);
  320. res := Done;
  321. ELSE
  322. res := NoPCI
  323. END;
  324. RETURN res
  325. END PCIReadConfig16;
  326. PROCEDURE PCIReadConfig8(pciBus, pciDev, pciFn, reg: LONGINT; VAR val: LONGINT): WORD;
  327. VAR adr, dataAdr: LONGINT; state: SET; res: WORD; chr: CHAR;
  328. BEGIN
  329. IF pciEnabled THEN
  330. state := Machine.DisableInterrupts();
  331. GetAdr1(pciBus, pciDev, pciFn, reg, 8, adr, dataAdr);
  332. Machine.Portout32(PciAdrReg, adr);
  333. Machine.Portin8(dataAdr, chr);
  334. val := ORD(chr);
  335. Machine.RestoreInterrupts(state);
  336. res := Done;
  337. ELSE
  338. res := NoPCI
  339. END;
  340. RETURN res
  341. END PCIReadConfig8;
  342. PROCEDURE PCIWriteConfig32(pciBus, pciDev, pciFn: LONGINT; reg: LONGINT; val: LONGINT): WORD;
  343. VAR adr, dataAdr: LONGINT; state: SET; res: WORD;
  344. BEGIN
  345. IF pciEnabled THEN
  346. state := Machine.DisableInterrupts();
  347. GetAdr1(pciBus, pciDev, pciFn, reg, 32, adr, dataAdr);
  348. Machine.Portout32(PciAdrReg, adr);
  349. Machine.Portout32(dataAdr, val);
  350. Machine.RestoreInterrupts(state);
  351. res := Done;
  352. ELSE
  353. res := NoPCI
  354. END;
  355. RETURN res
  356. END PCIWriteConfig32;
  357. PROCEDURE PCIWriteConfig16(pciBus, pciDev, pciFn: LONGINT; reg: LONGINT; val: LONGINT): WORD;
  358. VAR adr, dataAdr: LONGINT; state: SET; res: WORD;
  359. BEGIN
  360. IF pciEnabled THEN
  361. state := Machine.DisableInterrupts();
  362. GetAdr1(pciBus, pciDev, pciFn, reg, 16, adr, dataAdr);
  363. Machine.Portout32(PciAdrReg, adr);
  364. Machine.Portout16(dataAdr, SHORT(val));
  365. Machine.RestoreInterrupts(state);
  366. res := Done;
  367. ELSE
  368. res := NoPCI
  369. END;
  370. RETURN res
  371. END PCIWriteConfig16;
  372. PROCEDURE PCIWriteConfig8(pciBus, pciDev, pciFn: LONGINT; reg: LONGINT; val: LONGINT): WORD;
  373. VAR adr, dataAdr: LONGINT; state: SET; res: WORD;
  374. BEGIN
  375. IF pciEnabled THEN
  376. state := Machine.DisableInterrupts();
  377. GetAdr1(pciBus, pciDev, pciFn, reg, 8, adr, dataAdr);
  378. Machine.Portout32(PciAdrReg, adr);
  379. Machine.Portout8(dataAdr, CHR(val));
  380. Machine.RestoreInterrupts(state);
  381. res := Done;
  382. ELSE
  383. res := NoPCI
  384. END;
  385. RETURN res
  386. END PCIWriteConfig8;
  387. PROCEDURE PCICheckType1(): BOOLEAN;
  388. VAR in,temp: LONGINT; works: BOOLEAN; state: SET;
  389. BEGIN
  390. state := Machine.DisableInterrupts();
  391. Machine.Portout8(PciDataReg, 1X);
  392. Machine.Portin32(PciAdrReg, temp);
  393. Machine.Portout32(PciAdrReg, LONGINT(80000000H));
  394. Machine.Portin32(PciAdrReg, in);
  395. IF in = LONGINT(80000000H) THEN works := TRUE ELSE works := FALSE END;
  396. Machine.Portout32(PciAdrReg, temp);
  397. Machine.RestoreInterrupts(state);
  398. RETURN works
  399. END PCICheckType1;
  400. (* not implemented type 2 implemented on older machines ...
  401. PROCEDURE PCICheckType2(): BOOLEAN;
  402. CONST PciAdr=0CF8H; DataAdr=0CFBH; PciAdr2 = 0CFAH;
  403. VAR i,j:CHAR;
  404. VAR works: BOOLEAN;
  405. BEGIN
  406. Machine.Portout8(DataAdr, 0X);
  407. Machine.Portout8(PciAdr, 0X);
  408. Machine.Portout8(PciAdr2, 0X);
  409. Machine.Portin8(PciAdr, i);
  410. Machine.Portin8(PciAdr2, j);
  411. IF (i=0X) & (j=0X) THEN works := TRUE ELSE works := FALSE END;
  412. RETURN works
  413. END PCICheckType2;
  414. *)
  415. PROCEDURE StartIterate*(VAR pci: Pci);
  416. BEGIN pci.bus := 0; pci.device := 0; pci.function := 0
  417. END StartIterate;
  418. PROCEDURE Iterate*(VAR pci: Pci): BOOLEAN;
  419. VAR hdrType: LONGINT; multifunction: BOOLEAN; res: WORD;
  420. BEGIN
  421. IF pci.function = 0 THEN
  422. (* check if multi-function device *)
  423. res := PCIReadConfig32(pci.bus, pci.device, pci.function, 0CH, hdrType);
  424. multifunction := 23 IN SYSTEM.VAL(SET, hdrType);
  425. ELSE multifunction := TRUE
  426. END;
  427. INC(pci.function);
  428. IF ~multifunction OR (pci.function >= 8) THEN
  429. pci.function := 0;
  430. INC(pci.device);
  431. IF pci.device >= 32 THEN
  432. pci.device := 0;
  433. INC(pci.bus);
  434. IF pci.bus > 255 THEN RETURN FALSE END;
  435. END;
  436. END;
  437. RETURN TRUE
  438. END Iterate;
  439. PROCEDURE DisplayDeviceClass(class, subclass: LONGINT);
  440. BEGIN
  441. CASE class OF
  442. 1: KernelLog.String("disk controller:");
  443. CASE subclass OF
  444. 0: KernelLog.String("SCSI")
  445. |1: KernelLog.String("IDE")
  446. |2: KernelLog.String("floppy");
  447. |3: KernelLog.String("IPI");
  448. |4: KernelLog.String("RAID");
  449. |80H: KernelLog.String("Other ");
  450. ELSE KernelLog.String("unkown")
  451. END;
  452. |2: KernelLog.String("network controller:");
  453. CASE subclass OF
  454. 0: KernelLog.String("Ethernet");
  455. |1: KernelLog.String("Token ring");
  456. |2: KernelLog.String("FDDI");
  457. |3: KernelLog.String("ATM");
  458. |80H: KernelLog.String("other");
  459. ELSE KernelLog.String("unknown");
  460. END;
  461. |3: KernelLog.String("display controller:");
  462. CASE subclass OF
  463. 0: KernelLog.String("VGA");
  464. |1: KernelLog.String("XGA");
  465. |80H: KernelLog.String("other");
  466. ELSE KernelLog.String("unknown");
  467. END;
  468. |4: KernelLog.String("multimedia controller:");
  469. CASE subclass OF
  470. 0: KernelLog.String("Video");
  471. |1: KernelLog.String("Audio");
  472. |80H: KernelLog.String("other");
  473. ELSE KernelLog.String("unknown");
  474. END;
  475. |5: KernelLog.String("memory:");
  476. CASE subclass OF
  477. 0: KernelLog.String("RAM");
  478. |1: KernelLog.String("Flash");
  479. |80H: KernelLog.String("other");
  480. ELSE KernelLog.String("unknown");
  481. END;
  482. |6: KernelLog.String("bridge:");
  483. CASE subclass OF
  484. 0: KernelLog.String("Host/PCI")
  485. |1: KernelLog.String("PCI/ISA")
  486. |2: KernelLog.String("PCI/EISA");
  487. |3: KernelLog.String("PCI/Microchannel");
  488. |4: KernelLog.String("PCI/PCI");
  489. |5: KernelLog.String("PCI/PCMCIA");
  490. |6: KernelLog.String("PCI/NuBus");
  491. |7: KernelLog.String("PCI/CardBus");
  492. |80H: KernelLog.String("Other ");
  493. ELSE KernelLog.String("unkown")
  494. END;
  495. |7: KernelLog.String("communications device:");
  496. CASE subclass OF
  497. 0: KernelLog.String("Serial")
  498. |1: KernelLog.String("Parallel")
  499. |80H: KernelLog.String("Other ");
  500. ELSE KernelLog.String("unkown")
  501. END;
  502. |8: KernelLog.String("system device:");
  503. CASE subclass OF
  504. 0: KernelLog.String("PIC")
  505. |1: KernelLog.String("DMA")
  506. |2: KernelLog.String("Timer")
  507. |3: KernelLog.String("RTC")
  508. |80H: KernelLog.String("Other ");
  509. ELSE KernelLog.String("unkown")
  510. END;
  511. |9: KernelLog.String("HID:");
  512. CASE subclass OF
  513. 0: KernelLog.String("Keyboard")
  514. |1: KernelLog.String("Digitizer")
  515. |2: KernelLog.String("Mouse")
  516. |80H: KernelLog.String("Other ");
  517. ELSE KernelLog.String("unkown")
  518. END;
  519. |10: KernelLog.String("dock:");
  520. CASE subclass OF
  521. 0: KernelLog.String("Generic")
  522. |80H: KernelLog.String("Other ");
  523. ELSE KernelLog.String("unkown")
  524. END;
  525. |11: KernelLog.String("CPU:");
  526. CASE subclass OF
  527. 0: KernelLog.String("386")
  528. |1: KernelLog.String("486")
  529. |2: KernelLog.String("Pentium")
  530. |10H: KernelLog.String("Alpha")
  531. |20H: KernelLog.String("PowerPC")
  532. |40H: KernelLog.String("Coprocessor")
  533. |80H: KernelLog.String("Other ");
  534. ELSE KernelLog.String("unkown")
  535. END;
  536. |12: KernelLog.String("serial bus controller:");
  537. CASE subclass OF
  538. 0: KernelLog.String("Firewire")
  539. |1: KernelLog.String("ACCESS")
  540. |2: KernelLog.String("SSA")
  541. |3: KernelLog.String("USB")
  542. ELSE KernelLog.String("unkown")
  543. END;
  544. ELSE
  545. KernelLog.String("unknown class");
  546. END;
  547. END DisplayDeviceClass;
  548. PROCEDURE TracePCIDevices;
  549. VAR r0,r8,r10 : LONGINT; pci: Pci; class, subclass, api, vendorId, deviceId: LONGINT; res: WORD;
  550. BEGIN
  551. IF pciEnabled THEN
  552. KernelLog.String("PCI Devices"); KernelLog.Ln;
  553. StartIterate(pci);
  554. REPEAT
  555. res := PCIReadConfig32(pci.bus, pci.device, pci.function, 0, r0);
  556. IF r0 # LONGINT(0FFFFFFFFH) THEN
  557. res := PCIReadConfig32(pci.bus, pci.device, pci.function, 8, r8);
  558. IF r8 # LONGINT(0FFFFFFFFH) THEN
  559. vendorId := r0 MOD 10000H;
  560. deviceId := r0 DIV 10000H MOD 10000H;
  561. class := r8 DIV 1000000H MOD 100H;
  562. subclass := r8 DIV 10000H MOD 100H;
  563. api := r8 DIV 100H MOD 100H;
  564. KernelLog.String("device bus="); KernelLog.Int(pci.bus,1);
  565. KernelLog.String(" pciDev="); KernelLog.Int(pci.device,1);
  566. KernelLog.String(" pciFn="); KernelLog.Int(pci.function,1);
  567. KernelLog.String(" vendorId="); KernelLog.Int(vendorId,1);
  568. KernelLog.String(" deviceId="); KernelLog.Int(deviceId,1);
  569. KernelLog.String(" class="); KernelLog.Int(class,1);
  570. KernelLog.String(" subclass="); KernelLog.Int(subclass,1);
  571. KernelLog.String(" api="); KernelLog.Int(api,1);
  572. KernelLog.String(" classCode= "); KernelLog.Address(r8 DIV 100H MOD 1000000H);
  573. KernelLog.String(" : ");
  574. DisplayDeviceClass(class, subclass);
  575. KernelLog.Ln;
  576. END;
  577. END;
  578. UNTIL ~Iterate(pci);
  579. ELSE
  580. KernelLog.String("No PCI type 1 found"); KernelLog.Ln;
  581. END;
  582. END TracePCIDevices;
  583. PROCEDURE PCIDisabled() : BOOLEAN;
  584. VAR string : ARRAY 2 OF CHAR;
  585. BEGIN
  586. Machine.GetConfig("DisablePCI", string);
  587. RETURN string = "1";
  588. END PCIDisabled;
  589. BEGIN
  590. pciEnabled := FALSE;
  591. IF ~PCIDisabled() THEN
  592. pciEnabled := PCICheckType1();
  593. IF Trace THEN TracePCIDevices END;
  594. END;
  595. Show;
  596. END PCI.
  597. useful sources:
  598. http://tldp.org/LDP/tlk/dd/pci.html
  599. http://my.execpc.com/~geezer/code/pci.c
  600. (**
  601. Notes
  602. PCI devices are uniquely identified by their vendor ID and device ID. For example, a 3Com 905B Etherlink XL ethernet card has vendor ID 10B7H (3Com) and device ID 9055H. To get access to this card, use the FindPCIDevice call. The third parameter (idx) is used to find multiple instances of the card. If set to 0, the first card is returned; if set to 1, the second; etc. The last three parameters return the bus number, device number and function number of the card, respectively. This triple can be used with the other calls (e.g., ReadConfig..., WriteConfig...) to address a specific card.
  603. Example:
  604. VAR res, bus, dev, fkt: LONGINT;
  605. (* look for a 3Com 905B ethernet card *)
  606. res := PCI.FindPCIDevice(9055H, 10B7H, 0, bus, dev, fkt);
  607. IF res = PCI.Done THEN (* found at (bus, dev, fkt) *) END
  608. The PCI configuration area is a standardized set of registers provided by every PCI device. It can be accessed using the ReadConfig... and WriteConfig... calls. Typically, registers 10H, 14H, ..., 24H specify the base addresses of a card. Bit 0 is 1 if the address is in the I/O space, and 0 if it is in the physical memory space. For I/O addresses, the bottom two bits should be masked off, and for physical memory addresses, the bottom 4 bits should be masked off.
  609. Example:
  610. VAR res, adr: LONGINT;
  611. (* find the I/O base address of the ethernet controller *)
  612. res := PCI.ReadConfigDword(bus, dev, fkt, 10H, adr);
  613. IF res = PCI.Done THEN
  614. ASSERT(ODD(adr)); (* must be I/O mapped *)
  615. DEC(adr, adr MOD 4); (* strip lower 2 bits *)
  616. ...
  617. SYSTEM.PORTIN(adr+X, x) (* read some device register *)
  618. END
  619. To access a memory-mapped device, its address range has to be mapped into the virtual address space first.
  620. Example:
  621. CONST Size = 4096; (* the device has 4KB of registers *)
  622. VAR res, physAdr, virtAdr: LONGINT;
  623. (* find the base address of a memory-mapped device *)
  624. res := PCI.ReadConfigDword(bus, dev, fkt, 10H, physAdr);
  625. IF res = PCI.Done THEN
  626. ASSERT(~ODD(physAdr)); (* must be memory mapped *)
  627. DEC(physAdr, physAdr MOD 16); (* strip lower 4 bits *)
  628. Machine.MapPhysical(physAdr, Size, virtAdr);
  629. ...
  630. x := SYSTEM.GET32(virtAdr+X); (* read some device register *)
  631. ...
  632. Machine.UnmapPhysical(virtAdr, Size)
  633. END
  634. *)