9 /* TODO figure this out better */
11 struct pci_class_code_desc {
14 } pci_class_code_description[256] = {
15 /* Class Code Description */
16 {0x00, "Unclassified Device" },
17 {0x01, "Mass Storage Controller" },
18 {0x02, "Network Controller" },
19 {0x03, "Display Controller" },
20 {0x04, "Multimedia Controller" },
21 {0x05, "Memory Controller" },
23 {0x07, "Communication Controller" },
24 {0x08, "Generic System Peripheral" },
25 {0x09, "Input Device Controller" },
26 {0x0A, "Docking Station" },
28 {0x0C, "Serial Bus Controller" },
29 {0x0D, "Wireless Controller" },
30 {0x0E, "Intelligent Controller" },
31 {0x0F, "Satellite Communications Controller" },
32 {0x10, "Encryption Controller" },
33 {0x11, "Signal Processing Controller" },
34 {0x12, "Processing accelerators"},
35 {0x13, "Non-Essential Instrumentation"},
271 {0xFF, "Device does not fit any defined class." }
274 #define PCI_ADDR(bus, dev, func, offset) ( (uint32_t) ( \
275 ((uint32_t)bus << 16) \
276 | ((uint32_t)device << 11) \
277 | ((uint32_t)function << 8) \
278 | ((uint32_t)0x80000000U) \
279 | (offset & 0xfc) ) )
281 uint32_t pci_read_config(uint32_t base, uint8_t offset) {
283 base = base | (offset & 0xfc);
284 outport32(0xcf8, base);
285 data = inport32(0xcfc);
289 void pci_write_config(uint32_t base, uint8_t offset, uint32_t val) {
290 base = base | (offset & 0xfc);
291 outport32(0xcf8, base);
292 outport32(0xcfc, val);
296 int pci_read_header(struct pci_header *h, uint8_t bus, uint8_t device, uint8_t function) {
305 addr = PCI_ADDR(bus,device,function,0); /* offset 0 for device and vendor id */
306 outport32(0xcf8, addr);
307 data = inport32(0xcfc);
308 h->vendorid = data & 0xffff;
309 h->deviceid = data >> 16;
310 if (h->vendorid == 0xffff) return 0;
313 /* might as well read in the rest */
315 //printk("read in vendor id %x\n", h->vendorid);
316 switch (h->headertype & 0x7F) {
317 case 0x00: size = 0x40; break; /* general device */
318 case 0x01: size = 0x40; break; /* PCI to PCI bridge */
319 case 0x02: size = 0x48; break; /* PCI to CardBus bridge */
320 default: size = 0x10; break;
323 for (offset = 4; offset < size ; offset += 4) {
324 addr = PCI_ADDR(bus,device,function,offset);
325 outport32(0xcf8, addr);
326 data = inport32(0xcfc);
332 void pci_debug_info(struct pci_header *h) {
333 printk("pci: id %0x:%0x, type %0x, class %0x:%0x, %s / %s\n",
334 h->vendorid, h->deviceid, h->headertype, h->classcode, h->subclass,
335 pci_class_code_description[h->classcode].description,
336 pci_func_desc(h->classcode, h->subclass, h->progif)
340 void pci_scan_bus(uint8_t bus);
342 void pci_scan_device(uint8_t bus, uint8_t device) {
344 uint8_t function = 0;
345 struct pci_info *pci;
347 pci_read_header((struct pci_header *)&h, 0, device, function);
349 if (h.header.vendorid == 0xffff) return;
351 //printk("read pci header\n");
352 //pci_debug_info((struct pci_header *)&h);
354 if (h.header.classcode == 0x06 && h.header.subclass == 0x04) {
355 /* this is a bridge */
356 uint8_t secbus = h.bridge.secondary_bus_number;
357 pci_scan_bus(secbus);
360 if (h.header.headertype & 0x80 != 0) {
361 for (function = 1; function < 8; function++) {
362 pci_read_header((struct pci_header *)&h, 0, device, function);
363 if (h.header.vendorid == 0xffff) continue;
364 // pci_debug_info((struct pci_header *)&h);
365 if (h.header.classcode == 0x06 && h.header.subclass == 0x04) {
366 /* this is a bridge */
367 uint8_t secbus = h.bridge.secondary_bus_number;
368 pci_scan_bus(secbus);
372 pci = koalloc(sizeof *pci);
373 memcpy(&pci->device, &h, sizeof h);
374 pci->base = PCI_ADDR(bus,device,function,0);
375 if (pci_devices == NULL) {
376 // printk("setting up list\n");
381 // printk("adding to list\n");
383 pci->prev = pci_devices->prev;
384 pci->next = pci_devices;
386 pci_devices->prev->next = pci;
387 pci_devices->prev = pci;
391 void pci_scan_bus(uint8_t bus) {
394 for (device = 0; device < 32; device++) {
395 pci_scan_device(bus, device);
399 struct pci_info *pci_devices;
400 paddr_t pci_start; /* the start of pci space */
403 struct pci_info *dev;
405 /* align the start of PCI memory to 1 MB */
406 /* TODO we could probably free any remaining physical pages
407 * between the _kernel_phys_end and the new alignment
409 pci_start = mem_align(_kernel_phys_end, MB(1));
411 //printk("sizeof pci_header = %x\n", sizeof h);
413 /* TODO free the list if it's not null? */
418 for (dev = pci_devices; dev; dev = dev->next) {
419 pci_debug_info(&dev->device.header);
420 if (dev->next == pci_devices) break;