Rename pci_find_class() to pci_find_classprog(), and add new functions.
[seabios.git] / src / pcibios.c
1 // PCI BIOS (int 1a/b1) calls
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU GPLv3 license.
7
8 #include "types.h" // u32
9 #include "util.h" // handle_1ab1
10 #include "pci.h" // pci_config_readl
11 #include "bregs.h" // struct bregs
12 #include "biosvar.h" // GET_EBDA
13
14 #define RET_FUNC_NOT_SUPPORTED 0x81
15 #define RET_BAD_VENDOR_ID      0x83
16 #define RET_DEVICE_NOT_FOUND   0x86
17 #define RET_BUFFER_TOO_SMALL   0x89
18
19 // installation check
20 static void
21 handle_1ab101(struct bregs *regs)
22 {
23     regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
24     regs->bx = 0x0210; // PCI version 2.10
25     regs->cl = CONFIG_PCI_BUS_COUNT - 1;
26     regs->edx = 0x20494350; // "PCI "
27     // XXX - bochs bios code sets edi to point to 32bit code - but no
28     // reference to this in spec.
29     set_code_success(regs);
30 }
31
32 // find pci device
33 static void
34 handle_1ab102(struct bregs *regs)
35 {
36     PCIDevice d;
37     int ret = pci_find_device(regs->dx, regs->cx, regs->si, &d);
38     if (ret) {
39         set_code_fail(regs, RET_DEVICE_NOT_FOUND);
40         return;
41     }
42     regs->bh = d.bus;
43     regs->bl = d.devfn;
44     set_code_success(regs);
45 }
46
47 // find class code
48 static void
49 handle_1ab103(struct bregs *regs)
50 {
51     PCIDevice d;
52     int ret = pci_find_classprog(regs->ecx, regs->si, &d);
53     if (ret) {
54         set_code_fail(regs, RET_DEVICE_NOT_FOUND);
55         return;
56     }
57     regs->bh = d.bus;
58     regs->bl = d.devfn;
59     set_code_success(regs);
60 }
61
62 // read configuration byte
63 static void
64 handle_1ab108(struct bregs *regs)
65 {
66     regs->cl = pci_config_readb(pci_bd(regs->bh, regs->bl), regs->di);
67     set_code_success(regs);
68 }
69
70 // read configuration word
71 static void
72 handle_1ab109(struct bregs *regs)
73 {
74     regs->cx = pci_config_readw(pci_bd(regs->bh, regs->bl), regs->di);
75     set_code_success(regs);
76 }
77
78 // read configuration dword
79 static void
80 handle_1ab10a(struct bregs *regs)
81 {
82     regs->ecx = pci_config_readl(pci_bd(regs->bh, regs->bl), regs->di);
83     set_code_success(regs);
84 }
85
86 // write configuration byte
87 static void
88 handle_1ab10b(struct bregs *regs)
89 {
90     pci_config_writeb(pci_bd(regs->bh, regs->bl), regs->di, regs->cl);
91     set_code_success(regs);
92 }
93
94 // write configuration word
95 static void
96 handle_1ab10c(struct bregs *regs)
97 {
98     pci_config_writew(pci_bd(regs->bh, regs->bl), regs->di, regs->cx);
99     set_code_success(regs);
100 }
101
102 // write configuration dword
103 static void
104 handle_1ab10d(struct bregs *regs)
105 {
106     pci_config_writel(pci_bd(regs->bh, regs->bl), regs->di, regs->ecx);
107     set_code_success(regs);
108 }
109
110 // get irq routing options
111 static void
112 handle_1ab10e(struct bregs *regs)
113 {
114     struct pir_header *pirtable_far = (struct pir_header*)GET_EBDA(pir_loc);
115     if (! pirtable_far) {
116         set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
117         return;
118     }
119
120     // Validate and update size.
121     u16 size = GET_FARVAR(regs->es, *(u16*)(regs->di+0));
122     u16 pirsize = (GET_FARPTR(pirtable_far->size)
123                    - sizeof(struct pir_header));
124     SET_FARVAR(regs->es, *(u16*)(regs->di+0), pirsize);
125     if (size < pirsize) {
126         set_code_fail(regs, RET_BUFFER_TOO_SMALL);
127         return;
128     }
129
130     // Get dest buffer.
131     u16 d = (GET_FARVAR(regs->es, *(u16*)(regs->di+2)) + 0);
132     u16 destseg = GET_FARVAR(regs->es, *(u16*)(regs->di+4));
133
134     // Memcpy pir table slots to dest buffer.
135     memcpy_far(MAKE_FARPTR(destseg, d), pirtable_far, pirsize);
136
137     // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
138     regs->bx = GET_FARPTR(pirtable_far->exclusive_irqs);
139     set_code_success(regs);
140 }
141
142 static void
143 handle_1ab1XX(struct bregs *regs)
144 {
145     set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
146 }
147
148 void
149 handle_1ab1(struct bregs *regs)
150 {
151     //debug_stub(regs);
152
153     if (! CONFIG_PCIBIOS) {
154         set_fail(regs);
155         return;
156     }
157
158     switch (regs->al) {
159     case 0x01: handle_1ab101(regs); break;
160     case 0x02: handle_1ab102(regs); break;
161     case 0x03: handle_1ab103(regs); break;
162     case 0x08: handle_1ab108(regs); break;
163     case 0x09: handle_1ab109(regs); break;
164     case 0x0a: handle_1ab10a(regs); break;
165     case 0x0b: handle_1ab10b(regs); break;
166     case 0x0c: handle_1ab10c(regs); break;
167     case 0x0d: handle_1ab10d(regs); break;
168     case 0x0e: handle_1ab10e(regs); break;
169     default:   handle_1ab1XX(regs); break;
170     }
171 }