Fixed ZDE build - missing header file
[ZeXOS.git] / kernel / drivers / bus / pci / pci.c
blobebd1a44e4497baa0785dddf242f494b875197795
1 /*
2 * ZeX/OS
3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <config.h>
23 #include <build.h>
25 #ifndef ARCH_i386
26 #undef CONFIG_DRV_PCI
27 #endif
29 #ifdef CONFIG_DRV_PCI
31 #include <system.h>
32 #include <arch/io.h>
33 #include <pci.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include "../drivers/bus/pci/devlist.h"
38 pcidev_t pcidev_list;
40 #define inportb(P) inb(P)
41 #define inportw(P) inw(P)
42 #define outportb(P,V) outb(P,V)
43 #define outportw(P,V) outw_p(P,V)
44 #define inportl(P) inl(P)
45 #define outportl(P,V) outl(P,V)
48 /* else [in|out]portl() defined below */
49 #define PCI_READ_CONFIG_BYTE 0xB108
50 #define PCI_READ_CONFIG_WORD 0xB109
51 #define PCI_READ_CONFIG_DWORD 0xB10A
52 #define PCI_WRITE_CONFIG_BYTE 0xB10B
53 #define PCI_WRITE_CONFIG_WORD 0xB10C
54 #define PCI_WRITE_CONFIG_DWORD 0xB10D
56 #define PCI_ADR_REG 0xCF8
57 #define PCI_DATA_REG 0xCFC
59 /*****************************************************************************
60 If you have PnP code available, device PNP0A03 also
61 indicates the presence of a PCI controller in the system.
62 *****************************************************************************/
63 static int pci_detect ()
65 kprintf ("PCI controller: ");
67 /* poke 32-bit I/O register at 0xCF8 to see if
68 there's a PCI controller there */
69 outportl (PCI_ADR_REG, 0x80000000L); /* bus 0, dev 0, fn 0, reg 0 */
71 unsigned long ret = inportl (PCI_ADR_REG);
73 if(ret != 0x80000000L) {
74 kprintf ("not found / %x\n", ret);
75 return -1;
78 kprintf ("found\n");
80 return 0;
82 /*****************************************************************************
83 *****************************************************************************/
84 int pci_read_config_byte (pcidev_t *pci, unsigned reg, unsigned char *val)
86 outportl(PCI_ADR_REG,
87 0x80000000L | /* "enable configuration space mapping" */
88 ((unsigned long)pci->bus << 16) | /* b23-b16=bus */
89 ((unsigned)pci->dev << 11) | /* b15-b11=dev */
90 ((unsigned)pci->fn << 8) | /* b10-b8 =fn */
91 (reg & ~3)); /* b7 -b2 =reg */
93 *val = inportb(PCI_DATA_REG + (reg & 3)); // xxx - is this legit?
95 return 0;
97 /*****************************************************************************
98 *****************************************************************************/
99 int pci_read_config_word (pcidev_t *pci, unsigned reg, unsigned short *val)
101 outportl (PCI_ADR_REG, 0x80000000L |
102 ((unsigned long) pci->bus << 16) |
103 ((unsigned) pci->dev << 11) |
104 ((unsigned) pci->fn << 8) | (reg & ~3));
106 *val = inportw (PCI_DATA_REG + (reg & 2));
108 return 0;
110 /*****************************************************************************
111 *****************************************************************************/
112 int pci_read_config_dword (pcidev_t *pci, unsigned reg, unsigned long *val)
114 outportl (PCI_ADR_REG, 0x80000000L |
115 ((unsigned long) pci->bus << 16) |
116 ((unsigned) pci->dev << 11) |
117 ((unsigned) pci->fn << 8) | (reg & ~3));
119 *val = inportl (PCI_DATA_REG + 0);
121 return 0;
123 /*****************************************************************************
124 *****************************************************************************/
125 int pci_write_config_byte (pcidev_t *pci, unsigned reg,
126 unsigned val)
128 outportl (PCI_ADR_REG, 0x80000000L |
129 ((unsigned long)pci->bus << 16) |
130 ((unsigned)pci->dev << 11) |
131 ((unsigned)pci->fn << 8) | (reg & ~3));
133 outportb (PCI_DATA_REG + (reg & 3), val);
135 return 0;
137 /*****************************************************************************
138 *****************************************************************************/
139 int pci_write_config_word(pcidev_t *pci, unsigned reg,
140 unsigned val)
142 outportl (PCI_ADR_REG, 0x80000000L |
143 ((unsigned long)pci->bus << 16) |
144 ((unsigned)pci->dev << 11) |
145 ((unsigned)pci->fn << 8) | (reg & ~3));
147 outportw (PCI_DATA_REG + (reg & 2), val);
149 return 0;
151 /*****************************************************************************
152 *****************************************************************************/
153 int pci_write_config_dword(pcidev_t *pci, unsigned reg,
154 unsigned long val)
156 outportl(PCI_ADR_REG, 0x80000000L |
157 ((unsigned long)pci->bus << 16) |
158 ((unsigned)pci->dev << 11) |
159 ((unsigned)pci->fn << 8) | (reg & ~3));
161 outportl (PCI_DATA_REG + 0, val);
163 return 0;
165 /*****************************************************************************
166 *****************************************************************************/
167 static int pci_iterate (pcidev_t *pci)
169 unsigned char hdr_type = 0x80;
171 /* if first function of this device, check if multi-function device
172 (otherwise fn==0 is the _only_ function of this device) */
173 if(pci->fn == 0) {
174 if(pci_read_config_byte(pci, 0x0E, &hdr_type))
175 return -1; /* error */
178 /* increment iterators
179 fn (function) is the least significant, bus is the most significant */
180 pci->fn ++;
182 if(pci->fn >= 8 || (hdr_type & 0x80) == 0) {
183 pci->fn = 0;
184 pci->dev++;
185 if(pci->dev >= 32) {
186 pci->dev = 0;
187 pci->bus++;
188 // if(pci->bus > g_last_pci_bus)
189 if(pci->bus > 7)
190 return 1; /* done */
194 return 0;
196 /*****************************************************************************
197 *****************************************************************************/
199 * Set device to be a busmaster in case BIOS neglected to do so.
200 * Also adjust PCI latency timer to a reasonable value, 32.
203 void pci_device_adjust (pcidev_t *pci)
205 unsigned short new_command, pci_command;
206 unsigned char pci_latency;
208 pci_read_config_word (pci, PCI_command, &pci_command);
210 new_command = pci_command | PCI_command_master | PCI_command_io;
212 if (pci_command != new_command) {
213 kprintf("The PCI BIOS has not enabled this device!\nUpdating PCI command %X->%X\n",
214 pci_command, new_command);
216 pci_write_config_word (pci, PCI_command, new_command);
219 pci_read_config_byte (pci, PCI_latency, &pci_latency);
221 if (pci_latency < 32) {
222 kprintf("PCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency);
223 pci_write_config_byte(pci, PCI_latency, 32);
226 /*****************************************************************************
227 *****************************************************************************/
228 int pci_device_enable (pcidev_t *pci)
230 unsigned char r;
231 pci_read_config_byte (pci, PCI_pm_status, &r);
233 if (r & PCI_pm_state_d0)
234 pci_write_config_byte (pci, PCI_pm_status, PCI_pm_state_d0);
236 return 1;
238 /*****************************************************************************
239 *****************************************************************************/
240 void pcidev_display ()
242 pcidev_t *pcidev;
243 for (pcidev = pcidev_list.next; pcidev != &pcidev_list; pcidev = pcidev->next) {
244 if (!pcidev)
245 continue;
247 unsigned i = 0;
248 for (i = 0; i < PCI_DEVTABLE_LEN; i ++)
249 if (PciDevTable[i].VenId == (unsigned short) (pcidev->id & 0xFFFF)) {
250 if (PciDevTable[i].DevId == (unsigned short) (pcidev->id >> 16))
251 break;
255 printf ("%02u:%02u:%u %04lX:%04lX %s: %s\n",
256 pcidev->bus, pcidev->dev, pcidev->fn,
257 pcidev->id & 0xFFFF, pcidev->id >> 16,
258 //pcidev->u.h0.base_registers[0], pcidev->u.h0.base_register_sizes[0], pcidev->u.h0.base_registers[3],
259 i == PCI_DEVTABLE_LEN ? "Unknown" : PciDevTable[i].Chip,
260 i == PCI_DEVTABLE_LEN ? "Unknown" : PciDevTable[i].ChipDesc);
264 /*****************************************************************************
265 *****************************************************************************/
266 pcidev_t *pcidev_register (unsigned char bus, unsigned char dev, unsigned char fn, unsigned long id)
268 pcidev_t *pcidev;
270 /* alloc and init context */
271 pcidev = (pcidev_t *) kmalloc (sizeof (pcidev_t));
273 pcidev->bus = bus;
274 pcidev->dev = dev;
275 pcidev->fn = fn;
276 pcidev->id = id;
278 /* add into list */
279 pcidev->next = &pcidev_list;
280 pcidev->prev = pcidev_list.prev;
281 pcidev->prev->next = pcidev;
282 pcidev->next->prev = pcidev;
284 return pcidev;
287 pcidev_t *pcidev_find (unsigned short vendor, unsigned short device)
289 pcidev_t *pcidev;
290 for (pcidev = pcidev_list.next; pcidev != &pcidev_list; pcidev = pcidev->next) {
291 if (!pcidev)
292 continue;
294 if (vendor == (unsigned short) (pcidev->id & 0xFFFF))
295 if (device == (unsigned short) (pcidev->id >> 16))
296 return pcidev;
299 return 0;
302 bool bus_pci_acthandler (unsigned act, char *block, unsigned block_len)
304 switch (act) {
305 case DEV_ACT_INIT:
307 pcidev_list.next = &pcidev_list;
308 pcidev_list.prev = &pcidev_list;
310 pcidev_t pci;
311 int err;
313 /* check for PCI BIOS */
314 if(pci_detect ())
315 return 1;
317 /* display numeric ID of all PCI devices detected */
318 memset (&pci, 0, sizeof(pci));
322 /* 00=PCI_VENDOR_ID */
323 err = pci_read_config_dword (&pci, 0x00, &pci.id);
325 if(err) {
326 ERR: kprintf ("PCI: error 0x%02X reading PCI config\n", err);
327 return 1;
330 pcidev_t *pcidev = 0;
331 /* anything there? */
332 if(pci.id != 0xFFFFFFFFL) {
333 pcidev = pcidev_register (pci.bus, pci.dev, pci.fn, pci.id);
334 if (pcidev) {
335 /* base info */
336 pci_read_config_byte (pcidev, PCI_revision, &pcidev->revision);
337 pci_read_config_byte (pcidev, PCI_class_api, &pcidev->class_api);
338 pci_read_config_byte (pcidev, PCI_class_sub, &pcidev->class_sub);
339 pci_read_config_byte (pcidev, PCI_class_base, &pcidev->class_base);
341 pci_read_config_byte (pcidev, PCI_header_type, &pcidev->header_type);
342 pcidev->header_type &= PCI_header_type_mask;
344 pci_read_config_byte (pcidev, PCI_latency, &pcidev->latency);
345 pci_read_config_byte (pcidev, PCI_bist, &pcidev->bist);
346 pci_read_config_byte (pcidev, PCI_line_size, &pcidev->line_size);
348 unsigned i = 0;
349 unsigned temp, temp2;
351 if(pcidev->header_type == 0) {
352 for (i = 0; i < 6; i++) {
353 pci_read_config_dword (pcidev, PCI_base_registers + i*4, (unsigned long *) &temp);
354 if(temp) {
355 pci_write_config_dword (pcidev, PCI_base_registers + i*4, 0xffffffff);
356 pci_read_config_dword (pcidev, PCI_base_registers + i*4, (unsigned long *) &temp2);
357 temp2 &= 0xfffffff0;
359 pci_write_config_dword (pcidev, PCI_base_registers + i*4, temp);
361 temp2 = 1 + ~temp2;
362 if(temp & 1) {
363 pcidev->u.h0.base_registers[i] = temp & 0xfff0;
364 pcidev->u.h0.base_register_sizes[i] = temp2 & 0xffff;
365 } else {
366 pcidev->u.h0.base_registers[i] = temp & 0xfffffff0;
367 pcidev->u.h0.base_register_sizes[i] = temp2;
369 } else {
370 pcidev->u.h0.base_registers[i] = 0;
371 pcidev->u.h0.base_register_sizes[i] = 0;
374 pci_read_config_byte (pcidev, PCI_interrupt_line, &pcidev->u.h0.interrupt_line);
375 pci_read_config_byte (pcidev, PCI_interrupt_pin, &pcidev->u.h0.interrupt_pin);
376 pcidev->u.h1.interrupt_pin &= PCI_pin_mask;
377 // dprintf("basereg %d:%d:%d 0x%x\n", bus, dev, func, pcii->u.h0.base_registers[i]);
378 // dprintf("size %d:%d:%d 0x%x\n", bus, dev, func, pcii->u.h0.base_register_sizes[i]);
385 } while (!pci_iterate (&pci));
388 /* find a USB controller */
389 memset (&pci, 0, sizeof (pci));
393 unsigned char major, minor;
394 unsigned long id;
397 /* 00=vendor */
398 err = pci_read_config_dword (&pci, 0x00, &id);
400 if(err)
401 goto ERR;
403 /* 0B=class */
404 err = pci_read_config_byte (&pci, 0x0B, &major);
406 if(err)
407 goto ERR;
409 /* 0A=sub-class */
410 err = pci_read_config_byte (&pci, 0x0A, &minor);
412 if(err)
413 goto ERR;
415 /* anything there? */
416 if (major != 0xFF || minor != 0xFF) {
417 //printf("detected device of class %u.%u\n", major, minor);
418 if(major == 12 && minor == 3) {
419 //printf("USB controller detected: 0x%x, 0x%x\n", id & 0xFFFF, id >> 16);
420 pcidev_t *pcidev = pcidev_find (id & 0xFFFF, id >> 16);
422 if (!pcidev)
423 continue;
425 usb_controller_register (pcidev);
427 break;
431 } while (!pci_iterate (&pci));
433 return 1;
435 break;
436 case DEV_ACT_READ:
439 return 1;
441 break;
442 case DEV_ACT_WRITE:
445 return 1;
447 break;
450 return 0;
452 #endif