Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / unix / plugins / plugin_pci / plugin_pci.c
1 /* tag: openbios pci plugin
2  *
3  * Copyright (C) 2003 Stefan Reinauer
4  *
5  * See the file "COPYING" for further information about
6  * the copyright and warranty status of this work.
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include "unix/plugins.h"
12 #include "unix/plugin_pci.h"
13
14 #define DEBUG
15
16 u32 pci_conf_addr = 0;
17 pci_dev_t *pci_devices = NULL;
18
19 static pci_dev_t *find_device(u32 conf_addr)
20 {
21         pci_dev_t *devs = pci_devices;
22         unsigned bus = (conf_addr >> 16) & 0xff;
23         unsigned dev = (conf_addr >> 11) & 0x1f;
24         unsigned fn = (conf_addr >> 8) & 0x7;
25
26         // printf("Looking for device %x\n",conf_addr);
27
28         while (devs) {
29                 if (devs->bus == bus && devs->dev == dev && devs->fn == fn)
30                         return devs;
31                 devs = devs->next;
32         }
33         return NULL;
34 }
35
36 /*
37  * IO functions. These manage all the magic of providing a PCI
38  * compatible interface to OpenBIOS' unix version of the kernel.
39  */
40
41 static u8 pci_inb(u32 reg)
42 {
43         u32 basereg = (reg & 0xfffc);
44         u32 basepos = (reg & 0x03);
45         pci_dev_t *dev;
46
47         if (basereg == 0xcf8) {
48                 return (pci_conf_addr >> (basepos << 3));
49         }
50
51         /* still here? so we're 0xCFC */
52         dev = find_device(pci_conf_addr);
53         if (!dev || !dev->config)
54                 return 0xff;
55
56         return dev->config[(pci_conf_addr + basepos) & 0xff];
57 }
58
59 static u16 pci_inw(u32 reg)
60 {
61         u32 basereg = (reg & 0xfffc);
62         u32 basepos = (reg & 0x02);
63         pci_dev_t *dev;
64
65         if (basereg == 0xcf8) {
66                 return (pci_conf_addr >> (basepos << 3));
67         }
68
69         /* still here? so we're 0xCFC */
70         dev = find_device(pci_conf_addr);
71         if (!dev || !dev->config)
72                 return 0xffff;
73
74         return *(u16 *) (dev->config + ((pci_conf_addr + basepos) & 0xff));
75 }
76
77 static u32 pci_inl(u32 reg)
78 {
79         u32 basereg = (reg & 0xfffc);
80         pci_dev_t *dev;
81
82         if (basereg == 0xcf8) {
83                 return pci_conf_addr;
84         }
85
86         /* still here? so we're 0xCFC */
87         dev = find_device(pci_conf_addr);
88         if (!dev || !dev->config)
89                 return 0xffffffff;
90
91         return *(u32 *) (dev->config + (pci_conf_addr & 0xff));
92 }
93
94 static void pci_outb(u32 reg, u8 val)
95 {
96         u32 basereg = (reg & 0xfffc);
97         u32 basepos = (reg & 0x03);
98         pci_dev_t *dev;
99
100         if (basereg == 0xcf8) {
101                 pci_conf_addr &= (~(0xff << (basepos << 3)));
102                 pci_conf_addr |= (val << (basepos << 3));
103                 return;
104         }
105
106         /* still here? so we're 0xCFC */
107         dev = find_device(pci_conf_addr);
108         if (!dev || !dev->config)
109                 return;
110
111         dev->config[pci_conf_addr & 0xff] = val;
112 }
113
114 static void pci_outw(u32 reg, u16 val)
115 {
116         u32 basereg = (reg & 0xfffc);
117         u32 basepos = (reg & 0x02);
118         pci_dev_t *dev;
119
120         if (basereg == 0xcf8) {
121                 pci_conf_addr &= (~(0xffff << (basepos << 3)));
122                 pci_conf_addr |= (val << (basepos << 3));
123                 return;
124         }
125
126         /* still here? so we're 0xCFC */
127         dev = find_device(pci_conf_addr);
128         if (!dev || !dev->config)
129                 return;
130
131         *(u16 *) (dev->config + (pci_conf_addr & 0xff)) = val;
132 }
133
134 static void pci_outl(u32 reg, u32 val)
135 {
136         u32 basereg = (reg & 0xfffc);
137         pci_dev_t *dev;
138
139         if (basereg == 0xcf8) {
140                 pci_conf_addr = val;
141                 return;
142         }
143
144         /* still here? so we're 0xCFC */
145         dev = find_device(pci_conf_addr);
146         if (!dev || !dev->config)
147                 return;
148
149         *(u32 *) (dev->config + (pci_conf_addr & 0xff)) = val;
150 }
151
152 static io_ops_t pci_io_ops = {
153       inb:pci_inb,
154       inw:pci_inw,
155       inl:pci_inl,
156       outb:pci_outb,
157       outw:pci_outw,
158       outl:pci_outl
159 };
160
161 /*
162  * Functions visible to modules depending on this module.
163  */
164
165 int pci_register_device(unsigned bus, unsigned dev, unsigned fn,
166                         u8 * config)
167 {
168         pci_dev_t *newdev;
169         u32 caddr = (1 << 31) | (bus << 16) | (dev << 11) | (fn << 8);
170
171         if (find_device(caddr)) {
172                 printf("Error: pci device %02x:%02x.%01x already exists\n",
173                        bus, dev, fn);
174                 return -1;
175         }
176
177         newdev = malloc(sizeof(pci_dev_t));
178
179         if (!newdev) {
180                 printf("Out of memory\n");
181                 return -1;
182         }
183
184         newdev->bus = bus;
185         newdev->dev = dev;
186         newdev->fn = fn;
187         newdev->config = config;
188         newdev->next = pci_devices;
189
190         pci_devices = newdev;
191
192         return 0;
193 }
194
195 /*
196  * Initialization is really simple. We just grab the
197  * PCI conf1 io range for our emulation functions.
198  */
199 extern int plugin_pci_init( void );
200
201 int plugin_pci_init(void)
202 {
203 #ifdef DEBUG
204         printf("Plugin \"pci\" initializing... ");
205 #endif
206         register_iorange("pci", &pci_io_ops, 0xcf8, 0xcff);
207 #ifdef DEBUG
208         printf("done.\n");
209 #endif
210         return 0;
211 }
212
213 /* plugin meta information available for the plugin loader */
214 PLUGIN_AUTHOR       ("Stefan Reinauer <stepan@openbios.org>")
215 PLUGIN_DESCRIPTION  ("Generic PCI Device Emulation")
216 PLUGIN_LICENSE      ("GPL v2")
217
218 /* This plugin has no dependencies. Otherwise the following
219  * macro would be uncommented:
220  * PLUGIN_DEPENDENCIES ("this", "that")
221  */