]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4con/server/src/con_hw/pci.c
4823804ea783a99b95a0762520c7cbba4d58bc0f
[l4.git] / l4 / pkg / l4con / server / src / con_hw / pci.c
1 /*!
2  * \file        pci.c
3  * \brief       Handling of PCI devices
4  *
5  * \date        07/2002
6  * \author      Frank Mehnert <fm3@os.inf.tu-dresden.de> */
7 /*
8  * (c) 2002-2009 Technische Universität Dresden
9  * This file is part of TUD:OS and distributed under the terms of the
10  * GNU General Public License 2.
11  * Please see the COPYING-GPL-2 file for details.
12  */
13
14 #include <stdio.h>
15 #include <l4/re/c/namespace.h>
16 #include <l4/re/c/util/cap_alloc.h>
17 #include <l4/sys/err.h>
18
19 #include "pci.h"
20 #include "init.h"
21
22 #define MAX_DRIVERS 16
23
24 struct pci_driver
25 {
26   const struct pci_device_id *dev;
27   int (*probe)(unsigned int bus, unsigned int devfn,
28                const struct pci_device_id *dev, con_accel_t *accel);
29 };
30
31 static struct pci_driver pci_drv[MAX_DRIVERS];
32
33 void
34 pci_register(const struct pci_device_id *tbl, 
35              int(*probe)(unsigned int bus, unsigned int devfn,
36                          const struct pci_device_id *dev, con_accel_t *accel))
37 {
38   struct pci_driver *drv;
39
40   for (drv = pci_drv; drv->dev; drv++)
41     {
42       if (drv >= pci_drv + MAX_DRIVERS-1)
43         {
44           printf("Too many drivers registered, increase MAX_DRIVERS!!\n");
45           return;
46         }
47     }
48
49   drv->dev   = tbl;
50   drv->probe = probe;
51 }
52
53 l4_cap_idx_t vbus = L4_INVALID_CAP;
54 l4vbus_device_handle_t root_bridge = 0;
55
56 int
57 pci_probe(con_accel_t *accel)
58 {
59   long err;
60   int ret;
61
62   vbus = l4re_get_env_cap("vbus");
63   if (l4_is_invalid_cap(vbus))
64     {
65       printf("PCI: query vbus service failed, no PCI\n");
66       return -L4_ENODEV;
67     }
68
69   err = l4vbus_get_device_by_hid(vbus, 0, &root_bridge, "PNP0A03", L4VBUS_MAX_DEPTH, 0);
70
71   if (err < 0) {
72       printf("PCI: no root bridge found, no PCI\n");
73       return -L4_ENODEV;
74   }
75
76   unsigned bus = 0;
77   unsigned slot, fn = 0;
78   /* only scan possible devices and subdevices on the first bus */
79   for (slot = 0; slot < 32; slot++)
80     //for (fn = 0; fn < 8; fn ++)
81       {
82         unsigned devfn = (slot << 16) | fn;
83         struct pci_driver *drv;
84         const struct pci_device_id *dev;
85
86         /* only scan for graphics cards */
87         unsigned class_id = 0;
88         PCIBIOS_READ_CONFIG_WORD(bus, devfn, PCI_CLASS_DEVICE, &class_id);
89         if (class_id != PCI_CLASS_DISPLAY_VGA)
90           continue;
91         printf("Found VGA device\n");
92
93         for (drv = pci_drv; drv->dev; drv++)
94           {
95             for (dev = drv->dev; dev->vendor; dev++)
96               {
97                 unsigned vendor = 0, device = 0, sub_vendor = 0, sub_device = 0;
98                 PCIBIOS_READ_CONFIG_WORD(bus, devfn, PCI_VENDOR_ID, &vendor);
99                 PCIBIOS_READ_CONFIG_WORD(bus, devfn, PCI_DEVICE_ID, &device);
100                 PCIBIOS_READ_CONFIG_WORD(bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &sub_vendor);
101                 PCIBIOS_READ_CONFIG_WORD(bus, devfn, PCI_SUBSYSTEM_ID, &sub_device);
102                 if (dev->vendor != vendor)
103                   continue;
104                 if (dev->device != 0)
105                   if (dev->device != device)
106                     continue;
107                 if (dev->svid != 0)
108                   if ((dev->svid != sub_vendor) ||
109                       (dev->sid != sub_device))
110                     continue;
111
112                 /* found appropriate driver ... */
113                 if ((ret = drv->probe(bus, devfn, dev, accel)) != 0)
114                   /* ... YES */
115                   continue;
116
117                 return 0;
118               }
119           }
120       }
121
122   return -L4_ENODEV;
123 }
124
125 void
126 pci_resource(unsigned int bus, unsigned int devfn, 
127              int num, l4_addr_t *addr, l4_size_t *size)
128 {
129   unsigned l, sz, reg;
130
131   switch (num)
132     {
133     case 0:  reg = PCI_BASE_ADDRESS_0; break;
134     case 1:  reg = PCI_BASE_ADDRESS_1; break;
135     case 2:  reg = PCI_BASE_ADDRESS_2; break;
136     default: return;
137     }
138
139   PCIBIOS_READ_CONFIG_DWORD (bus, devfn, reg, &l);
140   PCIBIOS_WRITE_CONFIG_DWORD(bus, devfn, reg, ~0);
141   PCIBIOS_READ_CONFIG_DWORD (bus, devfn, reg, &sz);
142   PCIBIOS_WRITE_CONFIG_DWORD(bus, devfn, reg, l);
143   if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY)
144     {
145       *addr = l & PCI_BASE_ADDRESS_MEM_MASK;
146       sz   &= PCI_BASE_ADDRESS_MEM_MASK;
147       *size = sz & ~(sz - 1);
148     }
149   else
150     {
151       *addr = l & PCI_BASE_ADDRESS_IO_MASK;
152       sz   &= PCI_BASE_ADDRESS_IO_MASK & 0xffff;
153       *size = sz & ~(sz - 1);
154     }
155 }