xref: /aosp_15_r20/external/pciutils/lib/sysfs.c (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker  *	The PCI Library -- Configuration Access via /sys/bus/pci
3*c2e0c6b5SAndroid Build Coastguard Worker  *
4*c2e0c6b5SAndroid Build Coastguard Worker  *	Copyright (c) 2003 Matthew Wilcox <[email protected]>
5*c2e0c6b5SAndroid Build Coastguard Worker  *	Copyright (c) 1997--2024 Martin Mares <[email protected]>
6*c2e0c6b5SAndroid Build Coastguard Worker  *
7*c2e0c6b5SAndroid Build Coastguard Worker  *	Can be freely distributed and used under the terms of the GNU GPL v2+.
8*c2e0c6b5SAndroid Build Coastguard Worker  *
9*c2e0c6b5SAndroid Build Coastguard Worker  *	SPDX-License-Identifier: GPL-2.0-or-later
10*c2e0c6b5SAndroid Build Coastguard Worker  */
11*c2e0c6b5SAndroid Build Coastguard Worker 
12*c2e0c6b5SAndroid Build Coastguard Worker #define _GNU_SOURCE
13*c2e0c6b5SAndroid Build Coastguard Worker 
14*c2e0c6b5SAndroid Build Coastguard Worker #include <stdio.h>
15*c2e0c6b5SAndroid Build Coastguard Worker #include <stdlib.h>
16*c2e0c6b5SAndroid Build Coastguard Worker #include <string.h>
17*c2e0c6b5SAndroid Build Coastguard Worker #include <stdarg.h>
18*c2e0c6b5SAndroid Build Coastguard Worker #include <unistd.h>
19*c2e0c6b5SAndroid Build Coastguard Worker #include <errno.h>
20*c2e0c6b5SAndroid Build Coastguard Worker #include <dirent.h>
21*c2e0c6b5SAndroid Build Coastguard Worker #include <fcntl.h>
22*c2e0c6b5SAndroid Build Coastguard Worker #include <libgen.h>
23*c2e0c6b5SAndroid Build Coastguard Worker #include <sys/types.h>
24*c2e0c6b5SAndroid Build Coastguard Worker 
25*c2e0c6b5SAndroid Build Coastguard Worker #include "internal.h"
26*c2e0c6b5SAndroid Build Coastguard Worker 
27*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_config(struct pci_access * a)28*c2e0c6b5SAndroid Build Coastguard Worker sysfs_config(struct pci_access *a)
29*c2e0c6b5SAndroid Build Coastguard Worker {
30*c2e0c6b5SAndroid Build Coastguard Worker   pci_define_param(a, "sysfs.path", PCI_PATH_SYS_BUS_PCI, "Path to the sysfs device tree");
31*c2e0c6b5SAndroid Build Coastguard Worker }
32*c2e0c6b5SAndroid Build Coastguard Worker 
33*c2e0c6b5SAndroid Build Coastguard Worker static inline char *
sysfs_name(struct pci_access * a)34*c2e0c6b5SAndroid Build Coastguard Worker sysfs_name(struct pci_access *a)
35*c2e0c6b5SAndroid Build Coastguard Worker {
36*c2e0c6b5SAndroid Build Coastguard Worker   return pci_get_param(a, "sysfs.path");
37*c2e0c6b5SAndroid Build Coastguard Worker }
38*c2e0c6b5SAndroid Build Coastguard Worker 
39*c2e0c6b5SAndroid Build Coastguard Worker static int
sysfs_detect(struct pci_access * a)40*c2e0c6b5SAndroid Build Coastguard Worker sysfs_detect(struct pci_access *a)
41*c2e0c6b5SAndroid Build Coastguard Worker {
42*c2e0c6b5SAndroid Build Coastguard Worker   if (access(sysfs_name(a), R_OK))
43*c2e0c6b5SAndroid Build Coastguard Worker     {
44*c2e0c6b5SAndroid Build Coastguard Worker       a->debug("...cannot open %s", sysfs_name(a));
45*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
46*c2e0c6b5SAndroid Build Coastguard Worker     }
47*c2e0c6b5SAndroid Build Coastguard Worker   a->debug("...using %s", sysfs_name(a));
48*c2e0c6b5SAndroid Build Coastguard Worker   return 1;
49*c2e0c6b5SAndroid Build Coastguard Worker }
50*c2e0c6b5SAndroid Build Coastguard Worker 
51*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_init(struct pci_access * a)52*c2e0c6b5SAndroid Build Coastguard Worker sysfs_init(struct pci_access *a)
53*c2e0c6b5SAndroid Build Coastguard Worker {
54*c2e0c6b5SAndroid Build Coastguard Worker   a->fd = -1;
55*c2e0c6b5SAndroid Build Coastguard Worker   a->fd_vpd = -1;
56*c2e0c6b5SAndroid Build Coastguard Worker }
57*c2e0c6b5SAndroid Build Coastguard Worker 
58*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_flush_cache(struct pci_access * a)59*c2e0c6b5SAndroid Build Coastguard Worker sysfs_flush_cache(struct pci_access *a)
60*c2e0c6b5SAndroid Build Coastguard Worker {
61*c2e0c6b5SAndroid Build Coastguard Worker   if (a->fd >= 0)
62*c2e0c6b5SAndroid Build Coastguard Worker     {
63*c2e0c6b5SAndroid Build Coastguard Worker       close(a->fd);
64*c2e0c6b5SAndroid Build Coastguard Worker       a->fd = -1;
65*c2e0c6b5SAndroid Build Coastguard Worker     }
66*c2e0c6b5SAndroid Build Coastguard Worker   if (a->fd_vpd >= 0)
67*c2e0c6b5SAndroid Build Coastguard Worker     {
68*c2e0c6b5SAndroid Build Coastguard Worker       close(a->fd_vpd);
69*c2e0c6b5SAndroid Build Coastguard Worker       a->fd_vpd = -1;
70*c2e0c6b5SAndroid Build Coastguard Worker     }
71*c2e0c6b5SAndroid Build Coastguard Worker   a->cached_dev = NULL;
72*c2e0c6b5SAndroid Build Coastguard Worker }
73*c2e0c6b5SAndroid Build Coastguard Worker 
74*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_cleanup(struct pci_access * a)75*c2e0c6b5SAndroid Build Coastguard Worker sysfs_cleanup(struct pci_access *a)
76*c2e0c6b5SAndroid Build Coastguard Worker {
77*c2e0c6b5SAndroid Build Coastguard Worker   sysfs_flush_cache(a);
78*c2e0c6b5SAndroid Build Coastguard Worker }
79*c2e0c6b5SAndroid Build Coastguard Worker 
80*c2e0c6b5SAndroid Build Coastguard Worker #define OBJNAMELEN 1024
81*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_obj_name(struct pci_dev * d,char * object,char * buf)82*c2e0c6b5SAndroid Build Coastguard Worker sysfs_obj_name(struct pci_dev *d, char *object, char *buf)
83*c2e0c6b5SAndroid Build Coastguard Worker {
84*c2e0c6b5SAndroid Build Coastguard Worker   int n = snprintf(buf, OBJNAMELEN, "%s/devices/%04x:%02x:%02x.%d/%s",
85*c2e0c6b5SAndroid Build Coastguard Worker 		   sysfs_name(d->access), d->domain, d->bus, d->dev, d->func, object);
86*c2e0c6b5SAndroid Build Coastguard Worker   if (n < 0 || n >= OBJNAMELEN)
87*c2e0c6b5SAndroid Build Coastguard Worker     d->access->error("File name too long");
88*c2e0c6b5SAndroid Build Coastguard Worker }
89*c2e0c6b5SAndroid Build Coastguard Worker 
90*c2e0c6b5SAndroid Build Coastguard Worker #define OBJBUFSIZE 1024
91*c2e0c6b5SAndroid Build Coastguard Worker 
92*c2e0c6b5SAndroid Build Coastguard Worker static int
sysfs_get_string(struct pci_dev * d,char * object,char * buf,int mandatory)93*c2e0c6b5SAndroid Build Coastguard Worker sysfs_get_string(struct pci_dev *d, char *object, char *buf, int mandatory)
94*c2e0c6b5SAndroid Build Coastguard Worker {
95*c2e0c6b5SAndroid Build Coastguard Worker   struct pci_access *a = d->access;
96*c2e0c6b5SAndroid Build Coastguard Worker   int fd, n;
97*c2e0c6b5SAndroid Build Coastguard Worker   char namebuf[OBJNAMELEN];
98*c2e0c6b5SAndroid Build Coastguard Worker   void (*warn)(char *msg, ...) = (mandatory ? a->error : a->warning);
99*c2e0c6b5SAndroid Build Coastguard Worker 
100*c2e0c6b5SAndroid Build Coastguard Worker   sysfs_obj_name(d, object, namebuf);
101*c2e0c6b5SAndroid Build Coastguard Worker   fd = open(namebuf, O_RDONLY);
102*c2e0c6b5SAndroid Build Coastguard Worker   if (fd < 0)
103*c2e0c6b5SAndroid Build Coastguard Worker     {
104*c2e0c6b5SAndroid Build Coastguard Worker       if (mandatory || errno != ENOENT)
105*c2e0c6b5SAndroid Build Coastguard Worker 	warn("Cannot open %s: %s", namebuf, strerror(errno));
106*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
107*c2e0c6b5SAndroid Build Coastguard Worker     }
108*c2e0c6b5SAndroid Build Coastguard Worker   n = read(fd, buf, OBJBUFSIZE);
109*c2e0c6b5SAndroid Build Coastguard Worker   int read_errno = errno;
110*c2e0c6b5SAndroid Build Coastguard Worker   close(fd);
111*c2e0c6b5SAndroid Build Coastguard Worker   if (n < 0)
112*c2e0c6b5SAndroid Build Coastguard Worker     {
113*c2e0c6b5SAndroid Build Coastguard Worker       warn("Error reading %s: %s", namebuf, strerror(read_errno));
114*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
115*c2e0c6b5SAndroid Build Coastguard Worker     }
116*c2e0c6b5SAndroid Build Coastguard Worker   if (n >= OBJBUFSIZE)
117*c2e0c6b5SAndroid Build Coastguard Worker     {
118*c2e0c6b5SAndroid Build Coastguard Worker       warn("Value in %s too long", namebuf);
119*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
120*c2e0c6b5SAndroid Build Coastguard Worker     }
121*c2e0c6b5SAndroid Build Coastguard Worker   buf[n] = 0;
122*c2e0c6b5SAndroid Build Coastguard Worker   return 1;
123*c2e0c6b5SAndroid Build Coastguard Worker }
124*c2e0c6b5SAndroid Build Coastguard Worker 
125*c2e0c6b5SAndroid Build Coastguard Worker static char *
sysfs_deref_link(struct pci_dev * d,char * link_name)126*c2e0c6b5SAndroid Build Coastguard Worker sysfs_deref_link(struct pci_dev *d, char *link_name)
127*c2e0c6b5SAndroid Build Coastguard Worker {
128*c2e0c6b5SAndroid Build Coastguard Worker   char path[2*OBJNAMELEN], rel_path[OBJNAMELEN];
129*c2e0c6b5SAndroid Build Coastguard Worker 
130*c2e0c6b5SAndroid Build Coastguard Worker   sysfs_obj_name(d, link_name, path);
131*c2e0c6b5SAndroid Build Coastguard Worker   memset(rel_path, 0, sizeof(rel_path));
132*c2e0c6b5SAndroid Build Coastguard Worker 
133*c2e0c6b5SAndroid Build Coastguard Worker   if (readlink(path, rel_path, sizeof(rel_path)) < 0)
134*c2e0c6b5SAndroid Build Coastguard Worker     return NULL;
135*c2e0c6b5SAndroid Build Coastguard Worker 
136*c2e0c6b5SAndroid Build Coastguard Worker   sysfs_obj_name(d, "", path);
137*c2e0c6b5SAndroid Build Coastguard Worker   strcat(path, rel_path);
138*c2e0c6b5SAndroid Build Coastguard Worker 
139*c2e0c6b5SAndroid Build Coastguard Worker   // Returns a pointer to malloc'ed memory
140*c2e0c6b5SAndroid Build Coastguard Worker   return realpath(path, NULL);
141*c2e0c6b5SAndroid Build Coastguard Worker }
142*c2e0c6b5SAndroid Build Coastguard Worker 
143*c2e0c6b5SAndroid Build Coastguard Worker static int
sysfs_get_value(struct pci_dev * d,char * object,int mandatory)144*c2e0c6b5SAndroid Build Coastguard Worker sysfs_get_value(struct pci_dev *d, char *object, int mandatory)
145*c2e0c6b5SAndroid Build Coastguard Worker {
146*c2e0c6b5SAndroid Build Coastguard Worker   char buf[OBJBUFSIZE];
147*c2e0c6b5SAndroid Build Coastguard Worker 
148*c2e0c6b5SAndroid Build Coastguard Worker   if (sysfs_get_string(d, object, buf, mandatory))
149*c2e0c6b5SAndroid Build Coastguard Worker     return strtol(buf, NULL, 0);
150*c2e0c6b5SAndroid Build Coastguard Worker   else
151*c2e0c6b5SAndroid Build Coastguard Worker     return -1;
152*c2e0c6b5SAndroid Build Coastguard Worker }
153*c2e0c6b5SAndroid Build Coastguard Worker 
154*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_get_resources(struct pci_dev * d)155*c2e0c6b5SAndroid Build Coastguard Worker sysfs_get_resources(struct pci_dev *d)
156*c2e0c6b5SAndroid Build Coastguard Worker {
157*c2e0c6b5SAndroid Build Coastguard Worker   struct pci_access *a = d->access;
158*c2e0c6b5SAndroid Build Coastguard Worker   char namebuf[OBJNAMELEN], buf[256];
159*c2e0c6b5SAndroid Build Coastguard Worker   struct { pciaddr_t flags, base_addr, size; } lines[10];
160*c2e0c6b5SAndroid Build Coastguard Worker   int have_bar_bases, have_rom_base, have_bridge_bases;
161*c2e0c6b5SAndroid Build Coastguard Worker   FILE *file;
162*c2e0c6b5SAndroid Build Coastguard Worker   int i;
163*c2e0c6b5SAndroid Build Coastguard Worker 
164*c2e0c6b5SAndroid Build Coastguard Worker   have_bar_bases = have_rom_base = have_bridge_bases = 0;
165*c2e0c6b5SAndroid Build Coastguard Worker   sysfs_obj_name(d, "resource", namebuf);
166*c2e0c6b5SAndroid Build Coastguard Worker   file = fopen(namebuf, "r");
167*c2e0c6b5SAndroid Build Coastguard Worker   if (!file)
168*c2e0c6b5SAndroid Build Coastguard Worker     a->error("Cannot open %s: %s", namebuf, strerror(errno));
169*c2e0c6b5SAndroid Build Coastguard Worker   for (i = 0; i < 7+6+4+1; i++)
170*c2e0c6b5SAndroid Build Coastguard Worker     {
171*c2e0c6b5SAndroid Build Coastguard Worker       unsigned long long start, end, size, flags;
172*c2e0c6b5SAndroid Build Coastguard Worker       if (!fgets(buf, sizeof(buf), file))
173*c2e0c6b5SAndroid Build Coastguard Worker 	break;
174*c2e0c6b5SAndroid Build Coastguard Worker       if (sscanf(buf, "%llx %llx %llx", &start, &end, &flags) != 3)
175*c2e0c6b5SAndroid Build Coastguard Worker 	a->error("Syntax error in %s", namebuf);
176*c2e0c6b5SAndroid Build Coastguard Worker       if (end > start)
177*c2e0c6b5SAndroid Build Coastguard Worker 	size = end - start + 1;
178*c2e0c6b5SAndroid Build Coastguard Worker       else
179*c2e0c6b5SAndroid Build Coastguard Worker 	size = 0;
180*c2e0c6b5SAndroid Build Coastguard Worker       if (i < 6)
181*c2e0c6b5SAndroid Build Coastguard Worker 	{
182*c2e0c6b5SAndroid Build Coastguard Worker 	  d->flags[i] = flags;
183*c2e0c6b5SAndroid Build Coastguard Worker 	  flags &= PCI_ADDR_FLAG_MASK;
184*c2e0c6b5SAndroid Build Coastguard Worker 	  d->base_addr[i] = start | flags;
185*c2e0c6b5SAndroid Build Coastguard Worker 	  d->size[i] = size;
186*c2e0c6b5SAndroid Build Coastguard Worker 	  have_bar_bases = 1;
187*c2e0c6b5SAndroid Build Coastguard Worker 	}
188*c2e0c6b5SAndroid Build Coastguard Worker       else if (i == 6)
189*c2e0c6b5SAndroid Build Coastguard Worker 	{
190*c2e0c6b5SAndroid Build Coastguard Worker 	  d->rom_flags = flags;
191*c2e0c6b5SAndroid Build Coastguard Worker 	  flags &= PCI_ADDR_FLAG_MASK;
192*c2e0c6b5SAndroid Build Coastguard Worker 	  d->rom_base_addr = start | flags;
193*c2e0c6b5SAndroid Build Coastguard Worker 	  d->rom_size = size;
194*c2e0c6b5SAndroid Build Coastguard Worker 	  have_rom_base = 1;
195*c2e0c6b5SAndroid Build Coastguard Worker 	}
196*c2e0c6b5SAndroid Build Coastguard Worker       else if (i < 7+6+4)
197*c2e0c6b5SAndroid Build Coastguard Worker         {
198*c2e0c6b5SAndroid Build Coastguard Worker           /*
199*c2e0c6b5SAndroid Build Coastguard Worker            * If kernel was compiled without CONFIG_PCI_IOV option then after
200*c2e0c6b5SAndroid Build Coastguard Worker            * the ROM line for configured bridge device (that which had set
201*c2e0c6b5SAndroid Build Coastguard Worker            * subordinary bus number to non-zero value) are four additional lines
202*c2e0c6b5SAndroid Build Coastguard Worker            * which describe resources behind bridge. For PCI-to-PCI bridges they
203*c2e0c6b5SAndroid Build Coastguard Worker            * are: IO, MEM, PREFMEM and empty. For CardBus bridges they are: IO0,
204*c2e0c6b5SAndroid Build Coastguard Worker            * IO1, MEM0 and MEM1. For unconfigured bridges and other devices
205*c2e0c6b5SAndroid Build Coastguard Worker            * there is no additional line after the ROM line. If kernel was
206*c2e0c6b5SAndroid Build Coastguard Worker            * compiled with CONFIG_PCI_IOV option then after the ROM line and
207*c2e0c6b5SAndroid Build Coastguard Worker            * before the first bridge resource line are six additional lines
208*c2e0c6b5SAndroid Build Coastguard Worker            * which describe IOV resources. Read all remaining lines in resource
209*c2e0c6b5SAndroid Build Coastguard Worker            * file and based on the number of remaining lines (0, 4, 6, 10) parse
210*c2e0c6b5SAndroid Build Coastguard Worker            * resources behind bridge.
211*c2e0c6b5SAndroid Build Coastguard Worker            */
212*c2e0c6b5SAndroid Build Coastguard Worker           lines[i-7].flags = flags;
213*c2e0c6b5SAndroid Build Coastguard Worker           lines[i-7].base_addr = start;
214*c2e0c6b5SAndroid Build Coastguard Worker           lines[i-7].size = size;
215*c2e0c6b5SAndroid Build Coastguard Worker         }
216*c2e0c6b5SAndroid Build Coastguard Worker     }
217*c2e0c6b5SAndroid Build Coastguard Worker   if (i == 7+4 || i == 7+6+4)
218*c2e0c6b5SAndroid Build Coastguard Worker     {
219*c2e0c6b5SAndroid Build Coastguard Worker       int offset = (i == 7+6+4) ? 6 : 0;
220*c2e0c6b5SAndroid Build Coastguard Worker       for (i = 0; i < 4; i++)
221*c2e0c6b5SAndroid Build Coastguard Worker         {
222*c2e0c6b5SAndroid Build Coastguard Worker           d->bridge_flags[i] = lines[offset+i].flags;
223*c2e0c6b5SAndroid Build Coastguard Worker           d->bridge_base_addr[i] = lines[offset+i].base_addr;
224*c2e0c6b5SAndroid Build Coastguard Worker           d->bridge_size[i] = lines[offset+i].size;
225*c2e0c6b5SAndroid Build Coastguard Worker         }
226*c2e0c6b5SAndroid Build Coastguard Worker       have_bridge_bases = 1;
227*c2e0c6b5SAndroid Build Coastguard Worker     }
228*c2e0c6b5SAndroid Build Coastguard Worker   fclose(file);
229*c2e0c6b5SAndroid Build Coastguard Worker   if (!have_bar_bases)
230*c2e0c6b5SAndroid Build Coastguard Worker     clear_fill(d, PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS);
231*c2e0c6b5SAndroid Build Coastguard Worker   if (!have_rom_base)
232*c2e0c6b5SAndroid Build Coastguard Worker     clear_fill(d, PCI_FILL_ROM_BASE);
233*c2e0c6b5SAndroid Build Coastguard Worker   if (!have_bridge_bases)
234*c2e0c6b5SAndroid Build Coastguard Worker     clear_fill(d, PCI_FILL_BRIDGE_BASES);
235*c2e0c6b5SAndroid Build Coastguard Worker }
236*c2e0c6b5SAndroid Build Coastguard Worker 
sysfs_scan(struct pci_access * a)237*c2e0c6b5SAndroid Build Coastguard Worker static void sysfs_scan(struct pci_access *a)
238*c2e0c6b5SAndroid Build Coastguard Worker {
239*c2e0c6b5SAndroid Build Coastguard Worker   char dirname[1024];
240*c2e0c6b5SAndroid Build Coastguard Worker   DIR *dir;
241*c2e0c6b5SAndroid Build Coastguard Worker   struct dirent *entry;
242*c2e0c6b5SAndroid Build Coastguard Worker   int n;
243*c2e0c6b5SAndroid Build Coastguard Worker 
244*c2e0c6b5SAndroid Build Coastguard Worker   n = snprintf(dirname, sizeof(dirname), "%s/devices", sysfs_name(a));
245*c2e0c6b5SAndroid Build Coastguard Worker   if (n < 0 || n >= (int) sizeof(dirname))
246*c2e0c6b5SAndroid Build Coastguard Worker     a->error("Directory name too long");
247*c2e0c6b5SAndroid Build Coastguard Worker   dir = opendir(dirname);
248*c2e0c6b5SAndroid Build Coastguard Worker   if (!dir)
249*c2e0c6b5SAndroid Build Coastguard Worker     a->error("Cannot open %s", dirname);
250*c2e0c6b5SAndroid Build Coastguard Worker   while ((entry = readdir(dir)))
251*c2e0c6b5SAndroid Build Coastguard Worker     {
252*c2e0c6b5SAndroid Build Coastguard Worker       struct pci_dev *d;
253*c2e0c6b5SAndroid Build Coastguard Worker       unsigned int dom, bus, dev, func;
254*c2e0c6b5SAndroid Build Coastguard Worker 
255*c2e0c6b5SAndroid Build Coastguard Worker       /* ".", ".." or a special non-device perhaps */
256*c2e0c6b5SAndroid Build Coastguard Worker       if (entry->d_name[0] == '.')
257*c2e0c6b5SAndroid Build Coastguard Worker 	continue;
258*c2e0c6b5SAndroid Build Coastguard Worker 
259*c2e0c6b5SAndroid Build Coastguard Worker       d = pci_alloc_dev(a);
260*c2e0c6b5SAndroid Build Coastguard Worker       if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4)
261*c2e0c6b5SAndroid Build Coastguard Worker 	a->error("sysfs_scan: Couldn't parse entry name %s", entry->d_name);
262*c2e0c6b5SAndroid Build Coastguard Worker 
263*c2e0c6b5SAndroid Build Coastguard Worker       /* Ensure kernel provided domain that fits in a signed integer */
264*c2e0c6b5SAndroid Build Coastguard Worker       if (dom > 0x7fffffff)
265*c2e0c6b5SAndroid Build Coastguard Worker 	a->error("sysfs_scan: Invalid domain %x", dom);
266*c2e0c6b5SAndroid Build Coastguard Worker 
267*c2e0c6b5SAndroid Build Coastguard Worker       d->domain = dom;
268*c2e0c6b5SAndroid Build Coastguard Worker       d->bus = bus;
269*c2e0c6b5SAndroid Build Coastguard Worker       d->dev = dev;
270*c2e0c6b5SAndroid Build Coastguard Worker       d->func = func;
271*c2e0c6b5SAndroid Build Coastguard Worker       pci_link_dev(a, d);
272*c2e0c6b5SAndroid Build Coastguard Worker     }
273*c2e0c6b5SAndroid Build Coastguard Worker   closedir(dir);
274*c2e0c6b5SAndroid Build Coastguard Worker }
275*c2e0c6b5SAndroid Build Coastguard Worker 
276*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_fill_slots(struct pci_access * a)277*c2e0c6b5SAndroid Build Coastguard Worker sysfs_fill_slots(struct pci_access *a)
278*c2e0c6b5SAndroid Build Coastguard Worker {
279*c2e0c6b5SAndroid Build Coastguard Worker   char dirname[1024];
280*c2e0c6b5SAndroid Build Coastguard Worker   DIR *dir;
281*c2e0c6b5SAndroid Build Coastguard Worker   struct dirent *entry;
282*c2e0c6b5SAndroid Build Coastguard Worker   int n;
283*c2e0c6b5SAndroid Build Coastguard Worker 
284*c2e0c6b5SAndroid Build Coastguard Worker   n = snprintf(dirname, sizeof(dirname), "%s/slots", sysfs_name(a));
285*c2e0c6b5SAndroid Build Coastguard Worker   if (n < 0 || n >= (int) sizeof(dirname))
286*c2e0c6b5SAndroid Build Coastguard Worker     a->error("Directory name too long");
287*c2e0c6b5SAndroid Build Coastguard Worker   dir = opendir(dirname);
288*c2e0c6b5SAndroid Build Coastguard Worker   if (!dir)
289*c2e0c6b5SAndroid Build Coastguard Worker     return;
290*c2e0c6b5SAndroid Build Coastguard Worker 
291*c2e0c6b5SAndroid Build Coastguard Worker   while (entry = readdir(dir))
292*c2e0c6b5SAndroid Build Coastguard Worker     {
293*c2e0c6b5SAndroid Build Coastguard Worker       char namebuf[OBJNAMELEN], buf[16];
294*c2e0c6b5SAndroid Build Coastguard Worker       FILE *file;
295*c2e0c6b5SAndroid Build Coastguard Worker       unsigned int dom, bus, dev;
296*c2e0c6b5SAndroid Build Coastguard Worker       int res = 0;
297*c2e0c6b5SAndroid Build Coastguard Worker       struct pci_dev *d;
298*c2e0c6b5SAndroid Build Coastguard Worker 
299*c2e0c6b5SAndroid Build Coastguard Worker       /* ".", ".." or a special non-device perhaps */
300*c2e0c6b5SAndroid Build Coastguard Worker       if (entry->d_name[0] == '.')
301*c2e0c6b5SAndroid Build Coastguard Worker 	continue;
302*c2e0c6b5SAndroid Build Coastguard Worker 
303*c2e0c6b5SAndroid Build Coastguard Worker       n = snprintf(namebuf, OBJNAMELEN, "%s/%s/%s", dirname, entry->d_name, "address");
304*c2e0c6b5SAndroid Build Coastguard Worker       if (n < 0 || n >= OBJNAMELEN)
305*c2e0c6b5SAndroid Build Coastguard Worker 	a->error("File name too long");
306*c2e0c6b5SAndroid Build Coastguard Worker       file = fopen(namebuf, "r");
307*c2e0c6b5SAndroid Build Coastguard Worker       /*
308*c2e0c6b5SAndroid Build Coastguard Worker        * Old versions of Linux had a fakephp which didn't have an 'address'
309*c2e0c6b5SAndroid Build Coastguard Worker        * file.  There's no useful information to be gleaned from these
310*c2e0c6b5SAndroid Build Coastguard Worker        * devices, pretend they're not there.
311*c2e0c6b5SAndroid Build Coastguard Worker        */
312*c2e0c6b5SAndroid Build Coastguard Worker       if (!file)
313*c2e0c6b5SAndroid Build Coastguard Worker 	continue;
314*c2e0c6b5SAndroid Build Coastguard Worker 
315*c2e0c6b5SAndroid Build Coastguard Worker       if (!fgets(buf, sizeof(buf), file) || (res = sscanf(buf, "%x:%x:%x", &dom, &bus, &dev)) < 3)
316*c2e0c6b5SAndroid Build Coastguard Worker 	{
317*c2e0c6b5SAndroid Build Coastguard Worker 	  /*
318*c2e0c6b5SAndroid Build Coastguard Worker 	   * In some cases, the slot is not tied to a specific device before
319*c2e0c6b5SAndroid Build Coastguard Worker 	   * a card gets inserted. This happens for example on IBM pSeries
320*c2e0c6b5SAndroid Build Coastguard Worker 	   * and we need not warn about it.
321*c2e0c6b5SAndroid Build Coastguard Worker 	   */
322*c2e0c6b5SAndroid Build Coastguard Worker 	  if (res != 2)
323*c2e0c6b5SAndroid Build Coastguard Worker 	    a->warning("sysfs_fill_slots: Couldn't parse entry address %s", buf);
324*c2e0c6b5SAndroid Build Coastguard Worker 	}
325*c2e0c6b5SAndroid Build Coastguard Worker       else
326*c2e0c6b5SAndroid Build Coastguard Worker 	{
327*c2e0c6b5SAndroid Build Coastguard Worker 	  for (d = a->devices; d; d = d->next)
328*c2e0c6b5SAndroid Build Coastguard Worker 	    if (dom == (unsigned)d->domain && bus == d->bus && dev == d->dev && !d->phy_slot)
329*c2e0c6b5SAndroid Build Coastguard Worker 	      d->phy_slot = pci_set_property(d, PCI_FILL_PHYS_SLOT, entry->d_name);
330*c2e0c6b5SAndroid Build Coastguard Worker 	}
331*c2e0c6b5SAndroid Build Coastguard Worker       fclose(file);
332*c2e0c6b5SAndroid Build Coastguard Worker     }
333*c2e0c6b5SAndroid Build Coastguard Worker   closedir(dir);
334*c2e0c6b5SAndroid Build Coastguard Worker }
335*c2e0c6b5SAndroid Build Coastguard Worker 
336*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_fill_info(struct pci_dev * d,unsigned int flags)337*c2e0c6b5SAndroid Build Coastguard Worker sysfs_fill_info(struct pci_dev *d, unsigned int flags)
338*c2e0c6b5SAndroid Build Coastguard Worker {
339*c2e0c6b5SAndroid Build Coastguard Worker   int value, want_class, want_class_ext;
340*c2e0c6b5SAndroid Build Coastguard Worker 
341*c2e0c6b5SAndroid Build Coastguard Worker   if (!d->access->buscentric)
342*c2e0c6b5SAndroid Build Coastguard Worker     {
343*c2e0c6b5SAndroid Build Coastguard Worker       /*
344*c2e0c6b5SAndroid Build Coastguard Worker        *  These fields can be read from the config registers, but we want to show
345*c2e0c6b5SAndroid Build Coastguard Worker        *  the kernel's view, which has regions and IRQs remapped and other fields
346*c2e0c6b5SAndroid Build Coastguard Worker        *  (most importantly classes) possibly fixed if the device is known broken.
347*c2e0c6b5SAndroid Build Coastguard Worker        */
348*c2e0c6b5SAndroid Build Coastguard Worker       if (want_fill(d, flags, PCI_FILL_IDENT))
349*c2e0c6b5SAndroid Build Coastguard Worker 	{
350*c2e0c6b5SAndroid Build Coastguard Worker 	  d->vendor_id = sysfs_get_value(d, "vendor", 1);
351*c2e0c6b5SAndroid Build Coastguard Worker 	  d->device_id = sysfs_get_value(d, "device", 1);
352*c2e0c6b5SAndroid Build Coastguard Worker 	}
353*c2e0c6b5SAndroid Build Coastguard Worker       want_class = want_fill(d, flags, PCI_FILL_CLASS);
354*c2e0c6b5SAndroid Build Coastguard Worker       want_class_ext = want_fill(d, flags, PCI_FILL_CLASS_EXT);
355*c2e0c6b5SAndroid Build Coastguard Worker       if (want_class || want_class_ext)
356*c2e0c6b5SAndroid Build Coastguard Worker         {
357*c2e0c6b5SAndroid Build Coastguard Worker 	  value = sysfs_get_value(d, "class", 1);
358*c2e0c6b5SAndroid Build Coastguard Worker 	  if (want_class)
359*c2e0c6b5SAndroid Build Coastguard Worker 	    d->device_class = value >> 8;
360*c2e0c6b5SAndroid Build Coastguard Worker 	  if (want_class_ext)
361*c2e0c6b5SAndroid Build Coastguard Worker 	    {
362*c2e0c6b5SAndroid Build Coastguard Worker 	      d->prog_if = value & 0xff;
363*c2e0c6b5SAndroid Build Coastguard Worker 	      value = sysfs_get_value(d, "revision", 0);
364*c2e0c6b5SAndroid Build Coastguard Worker 	      if (value < 0)
365*c2e0c6b5SAndroid Build Coastguard Worker 	        value = pci_read_byte(d, PCI_REVISION_ID);
366*c2e0c6b5SAndroid Build Coastguard Worker 	      if (value >= 0)
367*c2e0c6b5SAndroid Build Coastguard Worker 	        d->rev_id = value;
368*c2e0c6b5SAndroid Build Coastguard Worker 	    }
369*c2e0c6b5SAndroid Build Coastguard Worker 	}
370*c2e0c6b5SAndroid Build Coastguard Worker       if (want_fill(d, flags, PCI_FILL_SUBSYS))
371*c2e0c6b5SAndroid Build Coastguard Worker 	{
372*c2e0c6b5SAndroid Build Coastguard Worker 	  value = sysfs_get_value(d, "subsystem_vendor", 0);
373*c2e0c6b5SAndroid Build Coastguard Worker 	  if (value >= 0)
374*c2e0c6b5SAndroid Build Coastguard Worker 	    {
375*c2e0c6b5SAndroid Build Coastguard Worker 	      d->subsys_vendor_id = value;
376*c2e0c6b5SAndroid Build Coastguard Worker 	      value = sysfs_get_value(d, "subsystem_device", 0);
377*c2e0c6b5SAndroid Build Coastguard Worker 	      if (value >= 0)
378*c2e0c6b5SAndroid Build Coastguard Worker 	        d->subsys_id = value;
379*c2e0c6b5SAndroid Build Coastguard Worker 	    }
380*c2e0c6b5SAndroid Build Coastguard Worker 	  else
381*c2e0c6b5SAndroid Build Coastguard Worker 	    clear_fill(d, PCI_FILL_SUBSYS);
382*c2e0c6b5SAndroid Build Coastguard Worker 	}
383*c2e0c6b5SAndroid Build Coastguard Worker       if (want_fill(d, flags, PCI_FILL_IRQ))
384*c2e0c6b5SAndroid Build Coastguard Worker 	  d->irq = sysfs_get_value(d, "irq", 1);
385*c2e0c6b5SAndroid Build Coastguard Worker       if (want_fill(d, flags, PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS | PCI_FILL_BRIDGE_BASES))
386*c2e0c6b5SAndroid Build Coastguard Worker 	  sysfs_get_resources(d);
387*c2e0c6b5SAndroid Build Coastguard Worker       if (want_fill(d, flags, PCI_FILL_PARENT))
388*c2e0c6b5SAndroid Build Coastguard Worker 	{
389*c2e0c6b5SAndroid Build Coastguard Worker 	  unsigned int domain, bus, dev, func;
390*c2e0c6b5SAndroid Build Coastguard Worker 	  char *path_abs, *path_canon, *name;
391*c2e0c6b5SAndroid Build Coastguard Worker 	  char path_rel[OBJNAMELEN];
392*c2e0c6b5SAndroid Build Coastguard Worker 	  struct pci_dev *parent;
393*c2e0c6b5SAndroid Build Coastguard Worker 
394*c2e0c6b5SAndroid Build Coastguard Worker 	  /* Construct sysfs path for parent device */
395*c2e0c6b5SAndroid Build Coastguard Worker 	  sysfs_obj_name(d, "..", path_rel);
396*c2e0c6b5SAndroid Build Coastguard Worker 	  path_abs = realpath(path_rel, NULL);
397*c2e0c6b5SAndroid Build Coastguard Worker 	  name = path_abs ? strrchr(path_abs, '/') : NULL;
398*c2e0c6b5SAndroid Build Coastguard Worker 	  name = name ? name+1 : name;
399*c2e0c6b5SAndroid Build Coastguard Worker 	  parent = NULL;
400*c2e0c6b5SAndroid Build Coastguard Worker 
401*c2e0c6b5SAndroid Build Coastguard Worker 	  if (name && sscanf(name, "%x:%x:%x.%d", &domain, &bus, &dev, &func) == 4 && domain <= 0x7fffffff)
402*c2e0c6b5SAndroid Build Coastguard Worker 	    for (parent = d->access->devices; parent; parent = parent->next)
403*c2e0c6b5SAndroid Build Coastguard Worker 	      if (parent->domain == (int)domain && parent->bus == bus && parent->dev == dev && parent->func == func)
404*c2e0c6b5SAndroid Build Coastguard Worker 	        break;
405*c2e0c6b5SAndroid Build Coastguard Worker 
406*c2e0c6b5SAndroid Build Coastguard Worker 	  if (parent)
407*c2e0c6b5SAndroid Build Coastguard Worker 	    {
408*c2e0c6b5SAndroid Build Coastguard Worker 	      /* Check if parsed BDF address from parent sysfs device is really expected PCI device */
409*c2e0c6b5SAndroid Build Coastguard Worker 	      sysfs_obj_name(parent, ".", path_rel);
410*c2e0c6b5SAndroid Build Coastguard Worker 	      path_canon = realpath(path_rel, NULL);
411*c2e0c6b5SAndroid Build Coastguard Worker 	      if (!path_canon || strcmp(path_canon, path_abs) != 0)
412*c2e0c6b5SAndroid Build Coastguard Worker 	        parent = NULL;
413*c2e0c6b5SAndroid Build Coastguard Worker 
414*c2e0c6b5SAndroid Build Coastguard Worker 	      if (path_canon)
415*c2e0c6b5SAndroid Build Coastguard Worker 		free(path_canon);
416*c2e0c6b5SAndroid Build Coastguard Worker 	    }
417*c2e0c6b5SAndroid Build Coastguard Worker 
418*c2e0c6b5SAndroid Build Coastguard Worker 	  if (parent)
419*c2e0c6b5SAndroid Build Coastguard Worker 	    d->parent = parent;
420*c2e0c6b5SAndroid Build Coastguard Worker 	  else
421*c2e0c6b5SAndroid Build Coastguard Worker 	    clear_fill(d, PCI_FILL_PARENT);
422*c2e0c6b5SAndroid Build Coastguard Worker 
423*c2e0c6b5SAndroid Build Coastguard Worker 	  if (path_abs)
424*c2e0c6b5SAndroid Build Coastguard Worker 	    free(path_abs);
425*c2e0c6b5SAndroid Build Coastguard Worker 	}
426*c2e0c6b5SAndroid Build Coastguard Worker     }
427*c2e0c6b5SAndroid Build Coastguard Worker 
428*c2e0c6b5SAndroid Build Coastguard Worker   if (want_fill(d, flags, PCI_FILL_PHYS_SLOT))
429*c2e0c6b5SAndroid Build Coastguard Worker     {
430*c2e0c6b5SAndroid Build Coastguard Worker       struct pci_dev *pd;
431*c2e0c6b5SAndroid Build Coastguard Worker       sysfs_fill_slots(d->access);
432*c2e0c6b5SAndroid Build Coastguard Worker       for (pd = d->access->devices; pd; pd = pd->next)
433*c2e0c6b5SAndroid Build Coastguard Worker 	pd->known_fields |= PCI_FILL_PHYS_SLOT;
434*c2e0c6b5SAndroid Build Coastguard Worker     }
435*c2e0c6b5SAndroid Build Coastguard Worker 
436*c2e0c6b5SAndroid Build Coastguard Worker   if (want_fill(d, flags, PCI_FILL_MODULE_ALIAS))
437*c2e0c6b5SAndroid Build Coastguard Worker     {
438*c2e0c6b5SAndroid Build Coastguard Worker       char buf[OBJBUFSIZE];
439*c2e0c6b5SAndroid Build Coastguard Worker       if (sysfs_get_string(d, "modalias", buf, 0))
440*c2e0c6b5SAndroid Build Coastguard Worker 	d->module_alias = pci_set_property(d, PCI_FILL_MODULE_ALIAS, buf);
441*c2e0c6b5SAndroid Build Coastguard Worker     }
442*c2e0c6b5SAndroid Build Coastguard Worker 
443*c2e0c6b5SAndroid Build Coastguard Worker   if (want_fill(d, flags, PCI_FILL_LABEL))
444*c2e0c6b5SAndroid Build Coastguard Worker     {
445*c2e0c6b5SAndroid Build Coastguard Worker       char buf[OBJBUFSIZE];
446*c2e0c6b5SAndroid Build Coastguard Worker       if (sysfs_get_string(d, "label", buf, 0))
447*c2e0c6b5SAndroid Build Coastguard Worker 	d->label = pci_set_property(d, PCI_FILL_LABEL, buf);
448*c2e0c6b5SAndroid Build Coastguard Worker     }
449*c2e0c6b5SAndroid Build Coastguard Worker 
450*c2e0c6b5SAndroid Build Coastguard Worker   if (want_fill(d, flags, PCI_FILL_NUMA_NODE))
451*c2e0c6b5SAndroid Build Coastguard Worker     d->numa_node = sysfs_get_value(d, "numa_node", 0);
452*c2e0c6b5SAndroid Build Coastguard Worker 
453*c2e0c6b5SAndroid Build Coastguard Worker   if (want_fill(d, flags, PCI_FILL_IOMMU_GROUP))
454*c2e0c6b5SAndroid Build Coastguard Worker     {
455*c2e0c6b5SAndroid Build Coastguard Worker       char *group_link = sysfs_deref_link(d, "iommu_group");
456*c2e0c6b5SAndroid Build Coastguard Worker       if (group_link)
457*c2e0c6b5SAndroid Build Coastguard Worker         {
458*c2e0c6b5SAndroid Build Coastguard Worker           pci_set_property(d, PCI_FILL_IOMMU_GROUP, basename(group_link));
459*c2e0c6b5SAndroid Build Coastguard Worker           free(group_link);
460*c2e0c6b5SAndroid Build Coastguard Worker         }
461*c2e0c6b5SAndroid Build Coastguard Worker     }
462*c2e0c6b5SAndroid Build Coastguard Worker 
463*c2e0c6b5SAndroid Build Coastguard Worker   if (want_fill(d, flags, PCI_FILL_DT_NODE))
464*c2e0c6b5SAndroid Build Coastguard Worker     {
465*c2e0c6b5SAndroid Build Coastguard Worker       char *node = sysfs_deref_link(d, "of_node");
466*c2e0c6b5SAndroid Build Coastguard Worker       if (node)
467*c2e0c6b5SAndroid Build Coastguard Worker 	{
468*c2e0c6b5SAndroid Build Coastguard Worker 	  pci_set_property(d, PCI_FILL_DT_NODE, node);
469*c2e0c6b5SAndroid Build Coastguard Worker 	  free(node);
470*c2e0c6b5SAndroid Build Coastguard Worker 	}
471*c2e0c6b5SAndroid Build Coastguard Worker     }
472*c2e0c6b5SAndroid Build Coastguard Worker 
473*c2e0c6b5SAndroid Build Coastguard Worker   if (want_fill(d, flags, PCI_FILL_DRIVER))
474*c2e0c6b5SAndroid Build Coastguard Worker     {
475*c2e0c6b5SAndroid Build Coastguard Worker       char *driver_path = sysfs_deref_link(d, "driver");
476*c2e0c6b5SAndroid Build Coastguard Worker       if (driver_path)
477*c2e0c6b5SAndroid Build Coastguard Worker         {
478*c2e0c6b5SAndroid Build Coastguard Worker           char *driver = strrchr(driver_path, '/');
479*c2e0c6b5SAndroid Build Coastguard Worker           driver = driver ? driver+1 : driver_path;
480*c2e0c6b5SAndroid Build Coastguard Worker           pci_set_property(d, PCI_FILL_DRIVER, driver);
481*c2e0c6b5SAndroid Build Coastguard Worker           free(driver_path);
482*c2e0c6b5SAndroid Build Coastguard Worker         }
483*c2e0c6b5SAndroid Build Coastguard Worker       else
484*c2e0c6b5SAndroid Build Coastguard Worker         clear_fill(d, PCI_FILL_DRIVER);
485*c2e0c6b5SAndroid Build Coastguard Worker     }
486*c2e0c6b5SAndroid Build Coastguard Worker 
487*c2e0c6b5SAndroid Build Coastguard Worker   if (want_fill(d, flags, PCI_FILL_RCD_LNK))
488*c2e0c6b5SAndroid Build Coastguard Worker     {
489*c2e0c6b5SAndroid Build Coastguard Worker       char buf[OBJBUFSIZE];
490*c2e0c6b5SAndroid Build Coastguard Worker       if (sysfs_get_string(d, "rcd_link_cap", buf, 0))
491*c2e0c6b5SAndroid Build Coastguard Worker         d->rcd_link_cap = strtoul(buf, NULL, 16);
492*c2e0c6b5SAndroid Build Coastguard Worker       if (sysfs_get_string(d, "rcd_link_ctrl", buf, 0))
493*c2e0c6b5SAndroid Build Coastguard Worker         d->rcd_link_ctrl = strtoul(buf, NULL, 16);
494*c2e0c6b5SAndroid Build Coastguard Worker       if (sysfs_get_string(d, "rcd_link_status", buf, 0))
495*c2e0c6b5SAndroid Build Coastguard Worker         d->rcd_link_status = strtoul(buf, NULL, 16);
496*c2e0c6b5SAndroid Build Coastguard Worker     }
497*c2e0c6b5SAndroid Build Coastguard Worker 
498*c2e0c6b5SAndroid Build Coastguard Worker   pci_generic_fill_info(d, flags);
499*c2e0c6b5SAndroid Build Coastguard Worker }
500*c2e0c6b5SAndroid Build Coastguard Worker 
501*c2e0c6b5SAndroid Build Coastguard Worker /* Intent of the sysfs_setup() caller */
502*c2e0c6b5SAndroid Build Coastguard Worker enum
503*c2e0c6b5SAndroid Build Coastguard Worker   {
504*c2e0c6b5SAndroid Build Coastguard Worker     SETUP_READ_CONFIG = 0,
505*c2e0c6b5SAndroid Build Coastguard Worker     SETUP_WRITE_CONFIG = 1,
506*c2e0c6b5SAndroid Build Coastguard Worker     SETUP_READ_VPD = 2
507*c2e0c6b5SAndroid Build Coastguard Worker   };
508*c2e0c6b5SAndroid Build Coastguard Worker 
509*c2e0c6b5SAndroid Build Coastguard Worker static int
sysfs_setup(struct pci_dev * d,int intent)510*c2e0c6b5SAndroid Build Coastguard Worker sysfs_setup(struct pci_dev *d, int intent)
511*c2e0c6b5SAndroid Build Coastguard Worker {
512*c2e0c6b5SAndroid Build Coastguard Worker   struct pci_access *a = d->access;
513*c2e0c6b5SAndroid Build Coastguard Worker   char namebuf[OBJNAMELEN];
514*c2e0c6b5SAndroid Build Coastguard Worker 
515*c2e0c6b5SAndroid Build Coastguard Worker   if (a->cached_dev != d || (intent == SETUP_WRITE_CONFIG && !a->fd_rw))
516*c2e0c6b5SAndroid Build Coastguard Worker     {
517*c2e0c6b5SAndroid Build Coastguard Worker       sysfs_flush_cache(a);
518*c2e0c6b5SAndroid Build Coastguard Worker       a->cached_dev = d;
519*c2e0c6b5SAndroid Build Coastguard Worker     }
520*c2e0c6b5SAndroid Build Coastguard Worker 
521*c2e0c6b5SAndroid Build Coastguard Worker   if (intent == SETUP_READ_VPD)
522*c2e0c6b5SAndroid Build Coastguard Worker     {
523*c2e0c6b5SAndroid Build Coastguard Worker       if (a->fd_vpd < 0)
524*c2e0c6b5SAndroid Build Coastguard Worker 	{
525*c2e0c6b5SAndroid Build Coastguard Worker 	  sysfs_obj_name(d, "vpd", namebuf);
526*c2e0c6b5SAndroid Build Coastguard Worker 	  a->fd_vpd = open(namebuf, O_RDONLY);
527*c2e0c6b5SAndroid Build Coastguard Worker 	  /* No warning on error; vpd may be absent or accessible only to root */
528*c2e0c6b5SAndroid Build Coastguard Worker 	}
529*c2e0c6b5SAndroid Build Coastguard Worker       return a->fd_vpd;
530*c2e0c6b5SAndroid Build Coastguard Worker     }
531*c2e0c6b5SAndroid Build Coastguard Worker 
532*c2e0c6b5SAndroid Build Coastguard Worker   if (a->fd < 0)
533*c2e0c6b5SAndroid Build Coastguard Worker     {
534*c2e0c6b5SAndroid Build Coastguard Worker       sysfs_obj_name(d, "config", namebuf);
535*c2e0c6b5SAndroid Build Coastguard Worker       a->fd_rw = a->writeable || intent == SETUP_WRITE_CONFIG;
536*c2e0c6b5SAndroid Build Coastguard Worker       a->fd = open(namebuf, a->fd_rw ? O_RDWR : O_RDONLY);
537*c2e0c6b5SAndroid Build Coastguard Worker       if (a->fd < 0)
538*c2e0c6b5SAndroid Build Coastguard Worker 	a->warning("Cannot open %s", namebuf);
539*c2e0c6b5SAndroid Build Coastguard Worker     }
540*c2e0c6b5SAndroid Build Coastguard Worker   return a->fd;
541*c2e0c6b5SAndroid Build Coastguard Worker }
542*c2e0c6b5SAndroid Build Coastguard Worker 
sysfs_read(struct pci_dev * d,int pos,byte * buf,int len)543*c2e0c6b5SAndroid Build Coastguard Worker static int sysfs_read(struct pci_dev *d, int pos, byte *buf, int len)
544*c2e0c6b5SAndroid Build Coastguard Worker {
545*c2e0c6b5SAndroid Build Coastguard Worker   int fd = sysfs_setup(d, SETUP_READ_CONFIG);
546*c2e0c6b5SAndroid Build Coastguard Worker   int res;
547*c2e0c6b5SAndroid Build Coastguard Worker 
548*c2e0c6b5SAndroid Build Coastguard Worker   if (fd < 0)
549*c2e0c6b5SAndroid Build Coastguard Worker     return 0;
550*c2e0c6b5SAndroid Build Coastguard Worker   res = pread(fd, buf, len, pos);
551*c2e0c6b5SAndroid Build Coastguard Worker   if (res < 0)
552*c2e0c6b5SAndroid Build Coastguard Worker     {
553*c2e0c6b5SAndroid Build Coastguard Worker       d->access->warning("sysfs_read: read failed: %s", strerror(errno));
554*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
555*c2e0c6b5SAndroid Build Coastguard Worker     }
556*c2e0c6b5SAndroid Build Coastguard Worker   else if (res != len)
557*c2e0c6b5SAndroid Build Coastguard Worker     return 0;
558*c2e0c6b5SAndroid Build Coastguard Worker   return 1;
559*c2e0c6b5SAndroid Build Coastguard Worker }
560*c2e0c6b5SAndroid Build Coastguard Worker 
sysfs_write(struct pci_dev * d,int pos,byte * buf,int len)561*c2e0c6b5SAndroid Build Coastguard Worker static int sysfs_write(struct pci_dev *d, int pos, byte *buf, int len)
562*c2e0c6b5SAndroid Build Coastguard Worker {
563*c2e0c6b5SAndroid Build Coastguard Worker   int fd = sysfs_setup(d, SETUP_WRITE_CONFIG);
564*c2e0c6b5SAndroid Build Coastguard Worker   int res;
565*c2e0c6b5SAndroid Build Coastguard Worker 
566*c2e0c6b5SAndroid Build Coastguard Worker   if (fd < 0)
567*c2e0c6b5SAndroid Build Coastguard Worker     return 0;
568*c2e0c6b5SAndroid Build Coastguard Worker   res = pwrite(fd, buf, len, pos);
569*c2e0c6b5SAndroid Build Coastguard Worker   if (res < 0)
570*c2e0c6b5SAndroid Build Coastguard Worker     {
571*c2e0c6b5SAndroid Build Coastguard Worker       d->access->warning("sysfs_write: write failed: %s", strerror(errno));
572*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
573*c2e0c6b5SAndroid Build Coastguard Worker     }
574*c2e0c6b5SAndroid Build Coastguard Worker   else if (res != len)
575*c2e0c6b5SAndroid Build Coastguard Worker     {
576*c2e0c6b5SAndroid Build Coastguard Worker       d->access->warning("sysfs_write: tried to write %d bytes at %d, but only %d succeeded", len, pos, res);
577*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
578*c2e0c6b5SAndroid Build Coastguard Worker     }
579*c2e0c6b5SAndroid Build Coastguard Worker   return 1;
580*c2e0c6b5SAndroid Build Coastguard Worker }
581*c2e0c6b5SAndroid Build Coastguard Worker 
sysfs_read_vpd(struct pci_dev * d,int pos,byte * buf,int len)582*c2e0c6b5SAndroid Build Coastguard Worker static int sysfs_read_vpd(struct pci_dev *d, int pos, byte *buf, int len)
583*c2e0c6b5SAndroid Build Coastguard Worker {
584*c2e0c6b5SAndroid Build Coastguard Worker   int fd = sysfs_setup(d, SETUP_READ_VPD);
585*c2e0c6b5SAndroid Build Coastguard Worker   int res;
586*c2e0c6b5SAndroid Build Coastguard Worker 
587*c2e0c6b5SAndroid Build Coastguard Worker   if (fd < 0)
588*c2e0c6b5SAndroid Build Coastguard Worker     return 0;
589*c2e0c6b5SAndroid Build Coastguard Worker   res = pread(fd, buf, len, pos);
590*c2e0c6b5SAndroid Build Coastguard Worker   if (res < 0)
591*c2e0c6b5SAndroid Build Coastguard Worker     {
592*c2e0c6b5SAndroid Build Coastguard Worker       d->access->warning("sysfs_read_vpd: read failed: %s", strerror(errno));
593*c2e0c6b5SAndroid Build Coastguard Worker       return 0;
594*c2e0c6b5SAndroid Build Coastguard Worker     }
595*c2e0c6b5SAndroid Build Coastguard Worker   else if (res != len)
596*c2e0c6b5SAndroid Build Coastguard Worker     return 0;
597*c2e0c6b5SAndroid Build Coastguard Worker   return 1;
598*c2e0c6b5SAndroid Build Coastguard Worker }
599*c2e0c6b5SAndroid Build Coastguard Worker 
sysfs_cleanup_dev(struct pci_dev * d)600*c2e0c6b5SAndroid Build Coastguard Worker static void sysfs_cleanup_dev(struct pci_dev *d)
601*c2e0c6b5SAndroid Build Coastguard Worker {
602*c2e0c6b5SAndroid Build Coastguard Worker   struct pci_access *a = d->access;
603*c2e0c6b5SAndroid Build Coastguard Worker 
604*c2e0c6b5SAndroid Build Coastguard Worker   if (a->cached_dev == d)
605*c2e0c6b5SAndroid Build Coastguard Worker     sysfs_flush_cache(a);
606*c2e0c6b5SAndroid Build Coastguard Worker }
607*c2e0c6b5SAndroid Build Coastguard Worker 
608*c2e0c6b5SAndroid Build Coastguard Worker struct pci_methods pm_linux_sysfs = {
609*c2e0c6b5SAndroid Build Coastguard Worker   .name = "linux-sysfs",
610*c2e0c6b5SAndroid Build Coastguard Worker   .help = "The sys filesystem on Linux",
611*c2e0c6b5SAndroid Build Coastguard Worker   .config = sysfs_config,
612*c2e0c6b5SAndroid Build Coastguard Worker   .detect = sysfs_detect,
613*c2e0c6b5SAndroid Build Coastguard Worker   .init = sysfs_init,
614*c2e0c6b5SAndroid Build Coastguard Worker   .cleanup = sysfs_cleanup,
615*c2e0c6b5SAndroid Build Coastguard Worker   .scan = sysfs_scan,
616*c2e0c6b5SAndroid Build Coastguard Worker   .fill_info = sysfs_fill_info,
617*c2e0c6b5SAndroid Build Coastguard Worker   .read = sysfs_read,
618*c2e0c6b5SAndroid Build Coastguard Worker   .write = sysfs_write,
619*c2e0c6b5SAndroid Build Coastguard Worker   .read_vpd = sysfs_read_vpd,
620*c2e0c6b5SAndroid Build Coastguard Worker   .cleanup_dev = sysfs_cleanup_dev,
621*c2e0c6b5SAndroid Build Coastguard Worker };
622