]> mj.ucw.cz Git - pciutils.git/blob - lib/sylixos-device.c
4bc207427a69a1509dab88a3e1eb44b90201a99a
[pciutils.git] / lib / sylixos-device.c
1 /*
2  *  The PCI Library -- Direct Configuration access via SylixOS Ports
3  *
4  *  Copyright (c) 2018 YuJian.Gong <gongyujian@acoinfo.com>
5  *
6  *  Can be freely distributed and used under the terms of the GNU GPL.
7  */
8
9 #define _GNU_SOURCE
10 #define  __SYLIXOS_KERNEL
11 #define  __SYLIXOS_PCI_DRV
12 #include <SylixOS.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "internal.h"
17
18 #define PCI_VENDOR_ID_IS_INVALID(vendor) (((vendor) == 0xffff) || ((vendor) == 0x0000))
19
20 typedef struct {
21   struct pci_access *a;
22   byte *busmap;
23   int bus;
24 } pci_dev_scan;
25
26 static int
27 sylixos_pci_traversal (int (*function)(), void *arg, int min_bus, int max_bus)
28 {
29   int bus, dev, func;
30   u8 header;
31   u16 vendor;
32
33   if (!function || (min_bus < 0) || (max_bus < 0))
34     return PX_ERROR;
35
36   min_bus = (min_bus > (PCI_MAX_BUS - 1)) ? (PCI_MAX_BUS - 1) : min_bus;
37   max_bus = (max_bus > (PCI_MAX_BUS - 1)) ? (PCI_MAX_BUS - 1) : max_bus;
38
39   for (bus = min_bus; bus <= max_bus; bus++)
40     {
41       for (dev = 0; dev < PCI_MAX_SLOTS; dev++)
42         {
43           for (func = 0; func < PCI_MAX_FUNCTIONS; func++)
44             {
45               pciConfigInWord(bus, dev, func, PCI_VENDOR_ID, &vendor);
46               if (PCI_VENDOR_ID_IS_INVALID(vendor))
47                 {
48                   if (func == 0)
49                     break;
50                   continue;
51                 }
52
53               if (function(bus, dev, func, arg) != ERROR_NONE)
54                 goto  __out;
55
56               if (func == 0)
57                 {
58                   pciConfigInByte(bus, dev, func, PCI_HEADER_TYPE, &header);
59                   if ((header & PCI_HEADER_MULTI_FUNC) != PCI_HEADER_MULTI_FUNC)
60                     break;
61                 }
62             }
63         }
64     }
65
66 __out:
67   return ERROR_NONE;
68 }
69
70 static int
71 pci_dev_list_create (int  bus, int  dev, int  func, void *arg)
72 {
73   pci_dev_scan *f = (pci_dev_scan *)arg;
74   struct pci_dev *d;
75   u32 vd;
76
77   f->busmap[bus] = 1;
78   d = pci_alloc_dev(f->a);
79   d->bus = bus;
80   d->dev = dev;
81   d->func = func;
82
83   vd = pci_read_long(d, PCI_VENDOR_ID);
84   d->vendor_id = vd & 0xffff;
85   d->device_id = vd >> 16U;
86   d->known_fields = PCI_FILL_IDENT;
87   d->hdrtype = pci_read_byte(d, PCI_HEADER_TYPE) & 0x7f;
88   pci_link_dev(f->a, d);
89
90   return ERROR_NONE;
91 }
92
93 static void
94 pci_generic_scan_bus_tbl(struct pci_access *a, byte *busmap, int bus)
95 {
96   pci_dev_scan f;
97
98   f.a = a;
99   f.busmap = busmap;
100   f.bus = bus;
101
102   sylixos_pci_traversal(pci_dev_list_create, &f, bus, PCI_MAX_BUS);
103 }
104
105 static void
106 sylixos_scan(struct pci_access *a)
107 {
108   int se;
109   u8 busmap[256];
110   char *env;
111
112   memset(busmap, 0, sizeof(busmap));
113
114   env = getenv(PCI_SCAN_FUNC);
115   if (!env)
116     {
117       pci_generic_scan_bus(a, busmap, 0);
118       return;
119     }
120
121   se = atoi(env);
122   if (se)
123     pci_generic_scan_bus_tbl(a, busmap, 0);
124   else
125     pci_generic_scan_bus(a, busmap, 0);
126 }
127
128 static void
129 sylixos_config(struct pci_access *a)
130 {
131   pci_define_param(a, "sylixos.path", PCI_PATH_SYLIXOS_DEVICE, "Path to the SylixOS PCI device");
132 }
133
134 static int
135 sylixos_detect(struct pci_access *a)
136 {
137   char *name = pci_get_param(a, "sylixos.path");
138
139   if (access(name, R_OK))
140     {
141       a->warning("Cannot open %s", name);
142       return 0;
143     }
144
145   a->debug("...using %s", name);
146   return 1;
147 }
148
149 static void
150 sylixos_init(struct pci_access *a)
151 {
152   a->fd = -1;
153 }
154
155 static void
156 sylixos_cleanup(struct pci_access *a)
157 {
158     a->fd = -1;
159 }
160
161 static int
162 sylixos_read(struct pci_dev *d, int pos, byte *buf, int len)
163 {
164   int ret = -1;
165   u8  data_byte = -1;
166   u16 data_word = -1;
167   u32 data_dword = -1;
168
169   if (!(len == 1 || len == 2 || len == 4))
170     return pci_generic_block_read(d, pos, buf, len);
171
172   if (pos >= 256)
173     return 0;
174
175   switch (len)
176     {
177     case 1:
178       ret = pciConfigInByte(d->bus, d->dev, d->func, pos, &data_byte);
179       if (ret != ERROR_NONE)
180         return 0;
181       buf[0] = (u8)data_byte;
182       break;
183
184     case 2:
185       ret = pciConfigInWord(d->bus, d->dev, d->func, pos, &data_word);
186       if (ret != ERROR_NONE)
187         return 0;
188       ((u16 *) buf)[0] = cpu_to_le16(data_word);
189       break;
190
191     case 4:
192       ret = pciConfigInDword(d->bus, d->dev, d->func, pos, &data_dword);
193       if (ret != ERROR_NONE)
194         return 0;
195       ((u32 *) buf)[0] = cpu_to_le32(data_dword);
196       break;
197     }
198
199   return 1;
200 }
201
202 static int
203 sylixos_write(struct pci_dev *d, int pos, byte *buf, int len)
204 {
205   int ret = PX_ERROR;
206   u8 data_byte;
207   u16 data_word;
208   u32 data_dword;
209
210   if (!(len == 1 || len == 2 || len == 4))
211     return pci_generic_block_write(d, pos, buf, len);
212
213   if (pos >= 256)
214     return 0;
215
216   switch (len)
217     {
218     case 1:
219       data_byte = buf[0];
220       ret = pciConfigOutByte(d->bus, d->dev, d->func, pos, data_byte);
221       if (ret != ERROR_NONE)
222         return 0;
223       break;
224
225     case 2:
226       data_word = le16_to_cpu(((u16 *) buf)[0]);
227       ret = pciConfigOutWord(d->bus, d->dev, d->func, pos, data_word);
228       if (ret != ERROR_NONE)
229         return 0;
230       break;
231
232     case 4:
233       data_dword = le32_to_cpu(((u32 *) buf)[0]);
234       ret = pciConfigOutDword(d->bus, d->dev, d->func, pos, data_dword);
235       if (ret != ERROR_NONE)
236         return 0;
237       break;
238     }
239
240   return 1;
241 }
242
243 struct pci_methods pm_sylixos_device = {
244   "sylixos-device",
245   "SylixOS /proc/pci device",
246   sylixos_config,
247   sylixos_detect,
248   sylixos_init,
249   sylixos_cleanup,
250   sylixos_scan,
251   pci_generic_fill_info,
252   sylixos_read,
253   sylixos_write,
254   NULL,                 // no read_vpd
255   NULL,                 // no init_dev
256   NULL,                 // no cleanup_dev
257 };