// The driver registry. // // One table, one line per driver. This is the same shape as // kernel/sys/table.inc and kernel/dev/cdev.c's devsw: a single place that // lists what exists, so a driver cannot be half-registered. // // It is a plain array rather than the linker-section trick a bigger kernel // would use (a __attribute__((section(".drivers"))) entry per driver, walked // between __start_ and __stop_ symbols). That approach lets a driver register // itself by existing, which is genuinely nicer -- but it also means the list // of what is in your kernel is not written down anywhere you can read, and // a driver silently dropped by the linker looks exactly like one that was // never written. At this size, being able to read the list wins. // // To add a driver: write kernel/drivers///.c exporting a // struct pci_driver, declare it here, add it to the array and to the Makefile's // KERN_DRIVERS -- and, if nothing else in the kernel calls it, give it a // DRV_ option in config/drivers.conf so it can be left out. #include "core/types.h" #include "core/defs.h" #include "core/param.h" #include "core/spinlock.h" #include "core/sleeplock.h" #include "fs/fs.h" #include "fs/file.h" #include "dev/pci.h" #include "dev/usb.h" #include "dev/device.h" // Which of these exist in this kernel is config/drivers.conf: the Makefile // leaves a disabled driver's object out and defines CONFIG_DRV_ for the // ones it keeps. The ones with no option (xHCI) are always here. #ifdef CONFIG_DRV_VGA_PCI extern const struct pci_driver vga_pci_driver; #endif extern const struct pci_driver xhci_driver; #ifdef CONFIG_DRV_VIRTIO_GPU extern const struct pci_driver virtio_gpu_driver; #endif #ifdef CONFIG_DRV_E1000 extern const struct pci_driver e1000_driver; #endif #ifdef CONFIG_DRV_AC97 extern const struct pci_driver ac97_driver; #endif #ifdef CONFIG_DRV_RTL8139 extern const struct pci_driver rtl8139_driver; #endif #ifdef CONFIG_DRV_R8169 extern const struct pci_driver r8169_driver; #endif #ifdef CONFIG_DRV_AHCI extern const struct pci_driver ahci_driver; #endif #ifdef CONFIG_DRV_NVME extern const struct pci_driver nvme_driver; #endif // Order matters here in one respect: virtio-gpu is offered the bus before the // VBE framebuffer driver, so that on a machine with both, the device with real // mode setting and an explicit flush wins the display class. vga_pci still // claims the stdvga card underneath, which is what the boot splash and the // text console are drawn on. static const struct pci_driver *drivers[] = { #ifdef CONFIG_DRV_VIRTIO_GPU &virtio_gpu_driver, #endif #ifdef CONFIG_DRV_VGA_PCI &vga_pci_driver, #endif #ifdef CONFIG_DRV_E1000 &e1000_driver, #endif // The RTL8168 is driven by Linux's own r8169 through LDLS // (etc/schinit/ldls-r8169.job), which a kernel driver here would claim // first -- so DRV_R8169 is off by default. The native driver stays in the // tree as the fallback for a machine without that job. #ifdef CONFIG_DRV_R8169 &r8169_driver, #endif #ifdef CONFIG_DRV_RTL8139 &rtl8139_driver, #endif &xhci_driver, #ifdef CONFIG_DRV_AHCI &ahci_driver, #endif #ifdef CONFIG_DRV_NVME &nvme_driver, #endif #ifdef CONFIG_DRV_AC97 &ac97_driver, #endif 0, // keeps the array non-empty when everything optional is off }; void pci_bind_all(void) { for (unsigned i = 0; drivers[i]; i++) pci_bind(drivers[i]); } // USB class drivers, same arrangement and for the same reason. These are not // found on the PCI bus -- they are offered a device by the USB core once its // interface descriptor has been read -- but a driver you cannot find in a // list is a driver nobody knows is there, whichever bus it sits on. // // To add one: write kernel/drivers/usb_.c exporting a struct // usb_driver, declare it here, add it to the array and to KERN_DRIVERS. extern const struct usb_driver usb_hid_driver; extern const struct usb_driver usb_storage_driver; extern const struct usb_driver usb_hub_driver; static const struct usb_driver *usb_drivers[] = { &usb_hid_driver, &usb_storage_driver, &usb_hub_driver, }; int usb_offer(const struct usb_driver *, struct usb_dev *); void usb_bind_all(struct usb_dev *dev) { for (unsigned i = 0; i < sizeof(usb_drivers) / sizeof(usb_drivers[0]); i++) if (usb_offer(usb_drivers[i], dev)) { // Same as the PCI path: publish it in the bus-agnostic list so that // "what is attached" has one answer covering every bus. Class comes from // the driver that claimed it rather than the USB class code, because a // driver knows what it made of the device and the descriptor only says // what the device claims to be. const char *n = usb_drivers[i]->name; struct device *d = device_add(n, DEVBUS_USB, usb_drivers[i]->devclass, n); if (d) device_set_desc(d, usb_drivers[i]->name); return; } } // Devices that are not enumerated by any bus -- they are simply known to be // there on a PC, and the driver pokes fixed I/O ports to find out whether it // is right. Listing them matters because a device manager that shows the // graphics card but not the keyboard is not showing the machine. // // Registered here rather than inside each driver's init so that the whole set // is visible in one place, which is the same reasoning as the driver arrays // above. void platform_register_devices(uint64 fb_addr) { struct device *d; // The framebuffer first, before anything that might want to draw. It is a // driver call, and this file is where driver names belong -- main() used to // call vga_init() directly, which put one display driver's name in the // kernel's startup path and would have needed editing to boot on a machine // whose framebuffer came from anywhere else. vga_fb_init(fb_addr); if ((d = device_add("kbd", DEVBUS_PLATFORM, DEVCLASS_INPUT, "ps2kbd"))) device_set_desc(d, "PS/2 keyboard"); if ((d = device_add("mouse", DEVBUS_PLATFORM, DEVCLASS_INPUT, "ps2mouse"))) device_set_desc(d, "PS/2 mouse"); if ((d = device_add("uart", DEVBUS_PLATFORM, DEVCLASS_OTHER, "uart8250"))) device_set_desc(d, "16550 serial port"); if ((d = device_add("ide", DEVBUS_PLATFORM, DEVCLASS_STORAGE, "ide"))) device_set_desc(d, "ATA disk controller"); }