Less aggressive colour change in the title
[snowy-minesweeper.git] / cdi / cdi.c
blob0c8c6f4678ad81b186391c59167b30988df106be
1 #include <stdlib.h>
2 #include <cdi.h>
3 #include <cdi/audio.h>
4 #include <cdi/lists.h>
5 #include <cdi/pci.h>
7 extern struct cdi_driver *__start_cdi_drivers, *__stop_cdi_drivers;
9 uint8_t pci_in8(int bus, int device, int function, int offset);
10 uint16_t pci_in16(int bus, int device, int function, int offset);
11 uint32_t pci_in32(int bus, int device, int function, int offset);
13 void pci_out8(int bus, int device, int function, int offset, uint8_t value);
14 void pci_out16(int bus, int device, int function, int offset, uint16_t value);
15 void pci_out32(int bus, int device, int function, int offset, uint32_t value);
17 extern void register_cdi_audio_device(struct cdi_audio_device *dev);
19 void cdi_driver_init(struct cdi_driver *driver)
21 driver->devices = cdi_list_create();
24 void cdi_driver_destroy(struct cdi_driver *driver)
26 struct cdi_device *dev;
28 while ((dev = cdi_list_pop(driver->devices))) {
29 if (driver->remove_device) {
30 driver->remove_device(dev);
32 free(dev);
35 cdi_list_destroy(driver->devices);
38 void cdi_init(void)
42 static void add_pci_function(int bus, int device, int function)
44 struct cdi_pci_device dev = {
45 .bus_data.bus_type = CDI_PCI,
46 .bus = bus,
47 .dev = device,
48 .function = function,
49 .vendor_id = pci_in16(bus, device, function, 0x00),
50 .device_id = pci_in16(bus, device, function, 0x02),
51 .class_id = pci_in8(bus, device, function, 0x0b),
52 .subclass_id = pci_in8(bus, device, function, 0x0a),
53 .interface_id = pci_in8(bus, device, function, 0x09),
54 .rev_id = pci_in8(bus, device, function, 0x08),
55 .irq = pci_in8(bus, device, function, 0x3c),
56 .resources = cdi_list_create()
59 for (int i = 0; i < 6; i++) {
60 uint32_t bar = pci_in32(bus, device, function, 0x10 + i * 4);
61 if (!bar) {
62 continue;
65 struct cdi_pci_resource *res = malloc(sizeof(*res));
67 if (bar & 1) {
68 res->type = CDI_PCI_IOPORTS;
69 res->start = bar & ~0x3;
70 res->index = i;
71 res->address = NULL;
73 pci_out32(bus, device, function, 0x10 + i * 4, 0xfffffffc);
74 res->length = ~(pci_in32(bus, device, function, 0x10 + i * 4) & 0xfffffffc) + 0x1;
75 pci_out32(bus, device, function, 0x10 + i * 4, bar & ~0x2);
76 } else if (((bar >> 1) & 0x3) <= 0x1) {
77 res->type = CDI_PCI_MEMORY;
78 res->start = bar & ~0xf;
79 res->index = i;
80 res->address = NULL;
82 pci_out32(bus, device, function, 0x10 + i * 4, 0xfffffff0);
83 res->length = ~(pci_in32(bus, device, function, 0x10 + i * 4) & 0xfffffff0) + 0x1;
84 pci_out32(bus, device, function, 0x10 + i * 4, bar);
86 if (!res->length) {
87 free(res);
88 continue;
92 cdi_list_push(dev.resources, res);
95 struct cdi_driver **drvp = &__start_cdi_drivers;
96 while (drvp < &__stop_cdi_drivers) {
97 struct cdi_driver *drv = *drvp;
99 if (drv->bus == CDI_PCI && drv->init_device) {
100 struct cdi_device *cdi_dev = drv->init_device(&dev.bus_data);
101 if (cdi_dev) {
102 cdi_dev->driver = drv;
103 cdi_list_push(drv->devices, cdi_dev);
105 if (drv->type == CDI_AUDIO) {
106 register_cdi_audio_device((struct cdi_audio_device *)cdi_dev);
109 break;
113 drvp++;
117 static void enumerate_pci_bus(int bus)
119 for (int dev = 0; dev < 32; dev++) {
120 for (int fnc = 0; fnc < 8; fnc++) {
121 if (pci_in16(bus, dev, fnc, 0x00) == 0xffff) {
122 if (fnc) {
123 continue;
124 } else {
125 break;
129 switch (pci_in8(bus, dev, fnc, 0x0e) & 0x7f) {
130 case 0:
131 add_pci_function(bus, dev, fnc);
132 break;
134 case 1:
135 enumerate_pci_bus(pci_in8(bus, dev, fnc, 0x19));
138 if (!fnc && !(pci_in8(bus, dev, fnc, 0x0e) & 0x80)) {
139 break;
145 void load_cdi_drivers(void)
147 struct cdi_driver **drvp = &__start_cdi_drivers;
148 while (drvp < &__stop_cdi_drivers) {
149 struct cdi_driver *drv = *drvp;
151 if (drv->init != NULL) {
152 drv->init();
155 if (drv->type == CDI_AUDIO) {
156 for (size_t i = 0; i < cdi_list_size(drv->devices); i++) {
157 register_cdi_audio_device((struct cdi_audio_device *)cdi_list_get(drv->devices, i));
161 drvp++;
164 enumerate_pci_bus(0);