123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- MODULE PCITools; (** AUTHOR "pjm/staubesv"; PURPOSE "PCI Bus Tools"; *)
- (**
- * This module provide two kinds of services related to PCI:
- * - Display information about all PCI busses/devices installed in the system
- * - Map PCI function to PCI device drivers
- *
- * Usage:
- *
- * PCITools.Scan ~ displays information about all installed PCI busses/devices
- * PCITools.Scan details ~ displays excessively detailed information
- * PCITools.DetectHardware ~ performs a PCI function to device driver mapping for all devices found
- *
- * System.Free PCITools ~
- *
- * Port of Oberon PCITools.Mod from "pjm" which is based on Linux pci.c and PCI Local Bus Specification Revision 2.0
- *
- * History:
- *
- * 18.06.2003 Fix for non-continuously numbered device functions (tf)
- * 15.09.2005 Ported to Bluebottle, added DetectHardware(), InstallPCIDrivers() & Extract(), removed ShowInterrupts() (staubesv)
- * 17.01.2006 Added WriteRegs & WriteCmdSts (staubesv)
- *)
- IMPORT
- SYSTEM, PCI, KernelLog, Streams, Files, Commands, Options, DriverDatabase;
- CONST
- HdrType = 0EH;
- Verbose = FALSE;
- ShowDrivers = TRUE; (* Also show available device/class drivers *)
- PCIIDS = "pci.ids"; (* File containing PCI vendor ID to vendor string mapping *)
- TYPE
- Device = POINTER TO RECORD
- bus: Bus; (* bus this device is on *)
- sibling: Device; (* next device on this bus *)
- next, prev: Device; (* chain of all devices *)
- devfn: LONGINT; (* dev = top 5 bits, fn = lower 3 bits *)
- device: LONGINT; (* device id *)
- vendor: LONGINT; (* vendor id *)
- class: LONGINT; (* base, sub, prog-if bytes *)
- revision : LONGINT; (* device revision *)
- irq, pin: LONGINT
- END;
- Bus = POINTER TO RECORD
- parent : Bus; (* parent bus this bridge is on *)
- children : Bus; (* chain of P2P bridges on this bus *)
- next : Bus; (* chain of all PCI buses *)
- self: Device; (* bridge device as seen by parent *)
- devices: Device; (* devices behind this bridge *)
- number: LONGINT; (* bus number *)
- primary, secondary: LONGINT; (* bridge numbers *)
- subordinate: LONGINT (* max number of subordinate buses *)
- END;
- PROCEDURE ScanBus(VAR bus: Bus; VAR devices : Device): LONGINT;
- VAR devfn, max, x, hdrtype, ht, buses: LONGINT; ismulti: BOOLEAN; dev: Device; child: Bus;
- BEGIN (* Only call from within EXCLUSIVE regions *)
- max := bus.secondary; ismulti := FALSE;
- FOR devfn := 0 TO 0FEH DO
- IF (devfn MOD 8 = 0) OR ismulti THEN
- ReadConfigByte(bus.number, devfn, HdrType, hdrtype);
- IF devfn MOD 8 = 0 THEN ismulti := ODD(hdrtype DIV 80H) END;
- ReadConfigDword(bus.number, devfn, PCI.DevReg, x);
- IF (x # -1) & (x # 0) THEN (* some boards return 0 instead of -1 for empty slot, according to Linux *)
- NEW(dev);
- dev.bus := bus; dev.devfn := devfn;
- dev.vendor := x MOD 10000H;
- dev.device := ASH(x, -16) MOD 10000H;
- ReadConfigByte(bus.number, devfn, PCI.IntlReg, dev.irq);
- ReadConfigByte(bus.number, devfn, PCI.IntlReg+1, dev.pin);
- ReadConfigDword(bus.number, devfn, PCI.RevIdReg, x);
- dev.class := ASH(x, -8) MOD 1000000H; (* upper 3 bytes *)
- dev.revision := x MOD 100H; (* lowest byte *)
- CASE ASH(dev.class, -8) OF
- 604H: ht := 1 (* bridge pci *)
- |607H: ht := 2 (* bridge cardbus *)
- ELSE ht := 0
- END;
- IF ht = hdrtype MOD 80H THEN
- dev.next := devices; devices := dev; dev.prev := NIL;
- dev.sibling := bus.devices; bus.devices := dev;
- IF ASH(dev.class, -8) = 604H THEN (* bridge pci *)
- NEW(child);
- child.next := bus.children; bus.children := child;
- child.self := dev; child.parent := bus;
- INC(max); child.secondary := max; child.number := max;
- child.primary := bus.secondary; child.subordinate := 0FFH;
- ReadConfigDword(bus.number, devfn, 18H, buses);
- IF buses MOD 1000000 # 0 THEN
- child.primary := buses MOD 100H;
- child.secondary := ASH(buses, -8) MOD 100H;
- child.subordinate := ASH(buses, -16) MOD 100H;
- child.number := child.secondary;
- max := ScanBus(child, devices)
- ELSE (* configure bus numbers for this bridge *)
- KernelLog.String("PCI: Warning: Bus numbers not configured."); KernelLog.Ln;
- END
- END
- ELSE
- KernelLog.String("PCI: Warning: Unknown header type (Bus: "); KernelLog.Int(bus.number, 0);
- KernelLog.String(", device: "); KernelLog.Int(dev.devfn DIV 8, 0);
- KernelLog.String(", function: "); KernelLog.Int(dev.devfn MOD 8, 0);
- KernelLog.String(", Header Type: "); KernelLog.Int(hdrtype, 0); KernelLog.Ln;
- END;
- (* ELSE
- ismulti := FALSE *) (* not all functions are continuously numbered *)
- END
- END
- END;
- RETURN max
- END ScanBus;
- PROCEDURE Extract(classcode : LONGINT; VAR class, subclass, protocol : LONGINT);
- BEGIN
- class := LSH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, classcode) * {16..23}), -16);
- subclass := LSH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, classcode) * {8..15}), -8);
- protocol := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, classcode) * {0..7});
- END Extract;
- PROCEDURE InstallPCIDrivers;
- VAR root : Bus; device : Device; nbrOfDevices : LONGINT; class, subclass, protocol : LONGINT;
- BEGIN {EXCLUSIVE}
- KernelLog.String("Looking for PCI devices..."); KernelLog.Ln;
- NEW(root);
- nbrOfDevices := ScanBus(root, device);
- WHILE(device # NIL) DO
- IF Verbose THEN
- KernelLog.String("Bus: "); IF device.bus = NIL THEN KernelLog.String("n/a"); ELSE KernelLog.Int(device.bus.number, 2); END;
- KernelLog.String(", Device: "); KernelLog.Int(ASH(device.devfn, -3) MOD 20H, 2); KernelLog.String(", Function: "); KernelLog.Int(device.devfn MOD 8, 2);
- KernelLog.String(": "); KernelLog.String("VendorID: "); KernelLog.Hex(device.vendor, -4); KernelLog.String(", DeviceID: "); KernelLog.Hex(device.device, -4);
- KernelLog.Ln;
- END;
- IF DriverDatabase.InstallDeviceDriver(DriverDatabase.PCI, device.vendor, device.device, device.revision) THEN
- ELSE
- Extract(device.class, class, subclass, protocol);
- IF DriverDatabase.InstallClassDriver(DriverDatabase.PCI, class, subclass, protocol, device.revision) THEN
- END;
- END;
- device := device.next;
- END;
- END InstallPCIDrivers;
- PROCEDURE HexDigit(ch: CHAR): BOOLEAN;
- BEGIN
- RETURN (ch >= "0") & (ch <= "9") OR (CAP(ch) >= "A") & (CAP(ch) <= "F")
- END HexDigit;
- PROCEDURE Read(VAR r: Files.Reader; VAR ch: CHAR);
- BEGIN
- IF ch = Streams.EOT THEN ch := 0X ELSE r.Char(ch) END
- END Read;
- PROCEDURE WriteDevice(w: Streams.Writer; class: BOOLEAN; p1, p2, p3: LONGINT; CONST l1, l2, l3: ARRAY OF CHAR; pciids : Files.File);
- VAR r: Files.Reader; ch: CHAR; level, value: LONGINT;
- PROCEDURE SkipLine(write: BOOLEAN);
- BEGIN
- WHILE (ch # 0X) & (ch # 0DX) & (ch # 0AX) DO
- IF write THEN w.Char(ch) END;
- Read(r, ch)
- END;
- REPEAT Read(r, ch) UNTIL (ch # 0DX) & (ch # 0AX)
- END SkipLine;
- PROCEDURE ReadHex(VAR x: LONGINT);
- BEGIN
- x := 0;
- LOOP
- IF (ch >= "0") & (ch <= "9") THEN
- x := x * 16 + (ORD(ch)-ORD("0"))
- ELSIF (CAP(ch) >= "A") & (CAP(ch) <= "F") THEN
- x := x * 16 + (ORD(CAP(ch))-ORD("A")+10)
- ELSE
- EXIT
- END;
- Read(r, ch)
- END
- END ReadHex;
- PROCEDURE GetLine(VAR level, value: LONGINT);
- BEGIN
- IF class THEN
- IF ch = "C" THEN Read(r, ch); Read(r, ch) END
- END;
- WHILE (ch # 0X) & (ch # 9X) & ~HexDigit(ch) DO SkipLine(FALSE) END;
- level := 0; WHILE ch = 9X DO INC(level); Read(r, ch) END;
- ReadHex(value);
- WHILE ch = " " DO Read(r, ch) END
- END GetLine;
- PROCEDURE Label(CONST l: ARRAY OF CHAR);
- BEGIN
- w.String(l); w.String(": ");
- END Label;
- BEGIN
- IF pciids = NIL THEN
- Label(l1); w.String("Unknown");
- Label(l2); w.String("Unknown");
- ELSE
- NEW(r, pciids, 0); Read(r, ch);
- IF class THEN WHILE (ch # 0X) & (ch # "C") DO SkipLine(FALSE) END; END;
- LOOP
- GetLine(level, value);
- IF (ch = 0X) OR (level = 0) & (value = p1) THEN EXIT END;
- SkipLine(FALSE)
- END;
- Label(l1);
- IF (ch # 0X) & (level = 0) & (value = p1) THEN
- SkipLine(TRUE); w.String(", ");
- LOOP
- GetLine(level, value);
- IF (ch = 0X) OR (level = 0) OR (level = 1) & (value = p2) THEN EXIT END;
- SkipLine(FALSE)
- END;
- Label(l2);
- IF (ch # 0X) & (level = 1) & (value = p2) THEN
- SkipLine(TRUE);
- LOOP
- GetLine(level, value);
- IF (ch = 0X) OR (level < 2) OR (level = 2) & (value = p3) THEN EXIT END;
- SkipLine(FALSE)
- END;
- IF (ch # 0X) & (level = 2) & (value = p3) THEN
- w.String(", "); Label(l3); SkipLine(TRUE)
- END
- ELSE
- w.String("Unknown")
- END
- ELSE
- w.String("Unknown")
- END
- END;
- END WriteDevice;
- PROCEDURE WriteB(w: Streams.Writer; x: LONGINT);
- CONST K = 1024; M = K*K; G = K*M;
- VAR mult: CHAR;
- BEGIN
- IF x MOD K # 0 THEN
- w.Int(x, 1)
- ELSE
- IF x MOD M # 0 THEN mult := "K"; x := x DIV K
- ELSIF x MOD G # 0 THEN mult := "M"; x := x DIV M
- ELSE mult := "G"; x := x DIV G
- END;
- w.Int(x, 1); w.Char(mult)
- END;
- w.String("B")
- END WriteB;
- PROCEDURE WriteBase(w: Streams.Writer; bus, devfn, reg: LONGINT; VAR double: BOOLEAN);
- VAR base, basehi, type, size: LONGINT; mask: SET;
- BEGIN
- double := FALSE; basehi := 0; size := 0;
- ReadConfigDword(bus, devfn, reg, base);
- IF base # 0 THEN
- WriteConfigDword(bus, devfn, reg, -1);
- ReadConfigDword(bus, devfn, reg, size);
- WriteConfigDword(bus, devfn, reg, base);
- IF ODD(base) THEN (* I/O *)
- IF ASH(base, -16) = 0 THEN mask := {2..15} ELSE mask := {2..31} END;
- type := base MOD 4
- ELSE (* memory *)
- mask := {4..31}; type := base MOD 10H
- END;
- size := SYSTEM.VAL(LONGINT, -(SYSTEM.VAL(SET, size) * mask))+1;
- size := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, size) * mask);
- IF type MOD 8 = 4 THEN (* 64-bit *)
- ReadConfigDword(bus, devfn, reg+4, basehi); double := TRUE
- END;
- DEC(base, type);
- (* write *)
- w.Char(9X); w.Char(9X);
- WriteB(w, size); w.String(" ");
- CASE type OF
- 0: w.String("32-bit memory")
- |1: w.String("I/O")
- |4: w.String("64-bit memory")
- |8: w.String("prefetchable 32-bit memory")
- |12: w.String("prefetchable 64-bit memory")
- ELSE w.String("type "); w.Int(type, 1)
- END;
- w.String(" at ");
- IF basehi # 0 THEN w.Hex(basehi, -2) END;
- w.Hex(base, -8); w.String("-");
- IF basehi # 0 THEN w.Hex(basehi, -8) END;
- w.Hex(base + size - 1, -8); w.Ln;
- END
- END WriteBase;
- PROCEDURE WriteDriver(w : Streams.Writer; dev : Device);
- VAR d, c : DriverDatabase.Driver; class, subclass, progintf : LONGINT;
- BEGIN
- w.String("Driver: ");
- d := DriverDatabase.GetDeviceSpecific(DriverDatabase.PCI, dev.vendor, dev.device, dev.revision);
- Extract(dev.class, class, subclass, progintf);
- c := DriverDatabase.GetClassSpecific(DriverDatabase.PCI, class, subclass, progintf, dev.revision);
- IF (c = NIL) & (d = NIL) THEN w.String("n/a");
- ELSIF (d # NIL) THEN
- w.String(d.commands^);
- ELSIF (c # NIL) THEN
- w.String(c.commands^);
- END;
- END WriteDriver;
- PROCEDURE WriteDev(w: Streams.Writer; dev: Device; pciids : Files.File; details : BOOLEAN);
- VAR bus, devfn, hdrtype, classrev, vendor, device, cmd, status, lastreg, reg, base: LONGINT; double: BOOLEAN;
- BEGIN
- bus := dev.bus.number; devfn := dev.devfn;
- ReadConfigByte(bus, devfn, HdrType, hdrtype);
- ReadConfigDword(bus, devfn, PCI.RevIdReg, classrev);
- ReadConfigWord(bus, devfn, PCI.DevReg, vendor);
- ReadConfigWord(bus, devfn, PCI.DevReg+2, device);
- ReadConfigWord(bus, devfn, PCI.CmdReg+2, status);
- ReadConfigWord(bus, devfn, PCI.CmdReg, cmd);
- w.String("Bus "); w.Int(bus, 1);
- w.String(", device "); w.Int(ASH(devfn, -3) MOD 20H, 1);
- w.String(", function "); w.Int(devfn MOD 8, 1);
- w.String(": class/rev "); w.Hex(classrev, -8);
- w.String(", vendor/device "); w.Hex(ASH(vendor, 16) + device, -8);
- w.String(", status/cmd "); w.Hex(ASH(status, 16) + cmd, -8);
- w.Ln;
- w.Char(9X);
- WriteDevice(w, TRUE, ASH(classrev, -24) MOD 100H, ASH(classrev, -16) MOD 100H, ASH(classrev, -8) MOD 100H, "Class", "Sub-class", "ProgIntfc", pciids);
- w.Ln;
- w.Char(9X);
- WriteDevice(w, FALSE, vendor, device, -1, "Vendor", "Device", "", pciids);
- w.Ln;
- IF ShowDrivers THEN
- w.Char(9X); WriteDriver(w, dev); w.Ln;
- END;
- IF (dev.irq # 0) OR (dev.pin # 0) THEN
- w.Char( 9X); w.Char( 9X);
- w.String("IRQ"); w.Int( dev.irq, 1);
- IF dev.pin # 0 THEN
- w.String(", INT"); w.Char( CHR(ORD("A")+dev.pin-1))
- END;
- w.Ln;
- END;
- CASE hdrtype MOD 80H OF
- 0: lastreg := PCI.Adr5Reg
- |1: lastreg := PCI.Adr1Reg
- ELSE lastreg := 0
- END;
- FOR reg := PCI.Adr0Reg TO lastreg BY 4 DO
- WriteBase(w, bus, devfn, reg, double);
- IF double THEN INC(reg, 4) END (* modifying FOR variable *)
- END;
- IF hdrtype MOD 80H = 0 THEN
- ReadConfigDword(bus, devfn, PCI.ROMReg, base);
- IF base # 0 THEN
- w.Char(9X); w.Char(9X);
- w.String("ROM at");
- w.Hex(base, -8); w.Ln;
- END
- END;
- IF details THEN WriteRegs(w, dev); WriteCmdSts(w, dev); END;
- w.Ln;
- END WriteDev;
- (* Dump PCI configuration space *)
- PROCEDURE WriteRegs(w : Streams.Writer; dev : Device);
- VAR value, offset : LONGINT;
- BEGIN
- w.Char(9X); w.String("PCI Configuration Space Registers: "); w.Ln;
- w.Char(0EX); (* KernelLog: non-proportional font *)
- FOR offset := 0 TO 3CH BY 4 DO
- w.Char(9X); w.Char(9X); w.Hex(offset, -2); w.Char("h"); w.Char(9X); w.Char(9X);
- ReadConfigDword(dev.bus.number, dev.devfn, PCI.DevReg + offset, value);
- w.Hex(value, -8); w.Ln;
- END;
- w.Char(0FX); (* KernelLog: proportional font *)
- END WriteRegs;
- (* Decode & display the command and the status register *)
- PROCEDURE WriteCmdSts(w : Streams.Writer; dev : Device);
- VAR value : LONGINT; dword : SET;
- BEGIN
- ReadConfigDword(dev.bus.number, dev.devfn, PCI.CmdReg, value); dword := SYSTEM.VAL(SET, value);
- w.Char(9X); w.String("Command Register: "); w.Ln;
- w.Char(9X); w.Char(9X);
- w.String("IO Space: "); IF 0 IN dword THEN w.String("On"); ELSE w.String("Off"); END;
- w.String(", Memory Space: "); IF 1 IN dword THEN w.String("On"); ELSE w.String("Off"); END;
- w.String(", Bus Master: "); IF 2 IN dword THEN w.String("On"); ELSE w.String("Off"); END;
- w.String(", Special Cycles: "); IF 3 IN dword THEN w.String("On"); ELSE w.String("Off"); END;
- w.String(", Memory Write and Invalidate: "); IF 4 IN dword THEN w.String("On"); ELSE w.String("Off"); END;
- w.Ln;
- w.Char(9X); w.Char(9X);
- w.String("VGA Palette Snoop: "); IF 5 IN dword THEN w.String("On"); ELSE w.String("Off"); END;
- w.String(", Parity Error Response: "); IF 6 IN dword THEN w.String("On"); ELSE w.String("Off"); END;
- w.String(", Stepping Control: "); IF 7 IN dword THEN w.String("On"); ELSE w.String("Off"); END;
- w.String(", SERR#: "); IF 8 IN dword THEN w.String("On"); ELSE w.String("Off"); END;
- w.String(", Fast Back-to-Back: "); IF 9 IN dword THEN w.String("On"); ELSE w.String("Off"); END;
- w.Ln;
- w.Char(9X); w.String("Status Register: "); w.Ln;
- w.Char(9X); w.Char(9X);
- w.String("Capabilities List: "); IF 4 + 16 IN dword THEN w.String("Yes"); ELSE w.String("No"); END;
- w.String(", 66MHz Capable: "); IF 5 + 16 IN dword THEN w.String("Yes"); ELSE w.String("No"); END;
- w.String(", Fast Back-to-Back Capable: "); IF 7 + 16 IN dword THEN w.String("Yes"); ELSE w.String("No"); END;
- w.String(", Master Data Parity Error: "); IF 8 + 16 IN dword THEN w.String("Yes"); ELSE w.String("No"); END;
- w.Ln;
- w.Char(9X); w.Char(9X);
- w.String("DEVSEL timing: ");
- IF {9+16, 10+16} * dword = {} THEN w.String("Fast");
- ELSIF {9+16, 10+16} * dword = {9+16} THEN w.String("Medium");
- ELSIF {9+16, 10+16} * dword = {10+16} THEN w.String("Slow");
- ELSE w.String("ERROR");
- END;
- w.Ln;
- w.Char(9X); w.Char(9X);
- w.String("Signaled Target Abort: "); IF 11 + 16 IN dword THEN w.String("Yes"); ELSE w.String("No"); END;
- w.String(", Received Target Abort: "); IF 12 + 16 IN dword THEN w.String("Yes"); ELSE w.String("No"); END;
- w.String(", Received Master Abort: "); IF 13 + 16 IN dword THEN w.String("Yes"); ELSE w.String("No"); END;
- w.String(", Signaled System Error: "); IF 14 + 16 IN dword THEN w.String("Yes"); ELSE w.String("No"); END;
- w.String(", Detected Parity Error: "); IF 15 + 16 IN dword THEN w.String("Yes"); ELSE w.String("No"); END;
- w.Ln;
- END WriteCmdSts;
- PROCEDURE ReadConfigByte(bus, devfn, ofs: LONGINT; VAR val: LONGINT);
- VAR res: WORD;
- BEGIN
- res := PCI.ReadConfigByte(bus, ASH(devfn, -3) MOD 20H, devfn MOD 8, ofs, val);
- ASSERT(res = PCI.Done)
- END ReadConfigByte;
- PROCEDURE ReadConfigWord(bus, devfn, ofs: LONGINT; VAR val: LONGINT);
- VAR res: WORD;
- BEGIN
- res := PCI.ReadConfigWord(bus, ASH(devfn, -3) MOD 20H, devfn MOD 8, ofs, val);
- ASSERT(res = PCI.Done)
- END ReadConfigWord;
- PROCEDURE ReadConfigDword(bus, devfn, ofs: LONGINT; VAR val: LONGINT);
- VAR res: WORD;
- BEGIN
- res := PCI.ReadConfigDword(bus, ASH(devfn, -3) MOD 20H, devfn MOD 8, ofs, val);
- ASSERT(res = PCI.Done)
- END ReadConfigDword;
- PROCEDURE WriteConfigDword(bus, devfn, ofs, val: LONGINT);
- VAR res: WORD;
- BEGIN
- res := PCI.WriteConfigDword(bus, ASH(devfn, -3) MOD 20H, devfn MOD 8, ofs, val);
- ASSERT(res = PCI.Done)
- END WriteConfigDword;
- (** Exported commands *)
- (** Perform bus enumeration and display information about found PCI busses/devices *)
- PROCEDURE Scan*(context : Commands.Context); (** ["-d"|"--details"] ~ *)
- VAR
- options : Options.Options;
- root : Bus; dev, prev: Device;
- version, lastPCIBus, hw, count: LONGINT;
- pciids : Files.File;
- BEGIN {EXCLUSIVE}
- NEW(options);
- options.Add("d", "details", Options.Flag);
- IF options.Parse(context.arg, context.error) THEN
- context.out.String("PCITools: PCI bus enumeration:"); context.out.Ln;
- IF PCI.PCIPresent(version, lastPCIBus, hw) = PCI.Done THEN
- context.out.String("PCI Bus Information: "); context.out.Int(lastPCIBus + 1, 0); context.out.String(" bus(ses) found, PCI version: ");
- context.out.Hex(version DIV 256, -2); context.out.Char("."); context.out.Hex(version MOD 256, -2); context.out.Ln;
- context.out.Ln;
- NEW(root);
- root.subordinate := ScanBus(root, dev);
- count := 0; prev := NIL;
- WHILE dev # NIL DO
- dev.prev := prev; prev := dev;
- dev := dev.next; INC(count)
- END;
- pciids := Files.Old(PCIIDS);
- WHILE prev # NIL DO
- WriteDev(context.out, prev, pciids, options.GetFlag("details"));
- prev := prev.prev
- END;
- context.out.Int(count, 1); context.out.String(" devices found"); context.out.Ln;
- ELSE
- context.out.String("PCI not present"); context.out.Ln;
- END;
- END;
- END Scan;
- (** Perform bus enumeration and install appropriate device drivers if available *)
- PROCEDURE DetectHardware*(context : Commands.Context);
- VAR ver, last, hw : LONGINT;
- BEGIN
- IF DriverDatabase.enabled THEN
- IF (PCI.PCIPresent(ver, last, hw) = PCI.Done) THEN
- InstallPCIDrivers;
- ELSE
- context.out.String("PCITools: No PCI bus found."); context.out.Ln;
- END;
- ELSE
- context.out.String("PCITools: Automatic hardware detedtion is disabled."); context.out.Ln;
- END;
- END DetectHardware;
- END PCITools.
- PCITools.Scan ~ System.Free PCITools DriverDatabase ~
- PCITools.Scan details ~
- PCITools.DetectHardware ~
|