2 * The PCI Library -- Configuration Access via /proc/bus/pci
4 * Copyright (c) 1997--2023 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL v2+.
8 * SPDX-License-Identifier: GPL-2.0-or-later
19 #include <sys/types.h>
24 proc_config(struct pci_access
*a
)
26 pci_define_param(a
, "proc.path", PCI_PATH_PROC_BUS_PCI
, "Path to the procfs bus tree");
30 proc_detect(struct pci_access
*a
)
32 char *name
= pci_get_param(a
, "proc.path");
34 if (access(name
, R_OK
))
36 a
->warning("Cannot open %s", name
);
39 a
->debug("...using %s", name
);
44 proc_init(struct pci_access
*a
)
50 proc_cleanup(struct pci_access
*a
)
60 proc_scan(struct pci_access
*a
)
65 if (snprintf(buf
, sizeof(buf
), "%s/devices", pci_get_param(a
, "proc.path")) == sizeof(buf
))
66 a
->error("File name too long");
69 a
->error("Cannot open %s", buf
);
70 while (fgets(buf
, sizeof(buf
)-1, f
))
72 struct pci_dev
*d
= pci_alloc_dev(a
);
73 unsigned int dfn
, vend
, cnt
, known
;
77 #define F " " PCIADDR_T_FMT
78 cnt
= sscanf(buf
, "%x %x %x" F F F F F F F F F F F F F F
"%n",
98 if (cnt
!= 9 && cnt
!= 10 && cnt
!= 17)
99 a
->error("proc: parse error (read only %d items)", cnt
);
101 d
->dev
= PCI_SLOT(dfn
& 0xff);
102 d
->func
= PCI_FUNC(dfn
& 0xff);
103 d
->vendor_id
= vend
>> 16U;
104 d
->device_id
= vend
& 0xffff;
108 known
|= PCI_FILL_IDENT
| PCI_FILL_IRQ
| PCI_FILL_BASES
;
110 known
|= PCI_FILL_ROM_BASE
;
112 known
|= PCI_FILL_SIZES
;
116 while (buf
[offset
] && isspace(buf
[offset
]))
118 driver
= &buf
[offset
];
119 while (buf
[offset
] && !isspace(buf
[offset
]))
124 pci_set_property(d
, PCI_FILL_DRIVER
, driver
);
125 known
|= PCI_FILL_DRIVER
;
128 d
->known_fields
= known
;
135 proc_setup(struct pci_dev
*d
, int rw
)
137 struct pci_access
*a
= d
->access
;
139 if (a
->cached_dev
!= d
|| a
->fd_rw
< rw
)
145 e
= snprintf(buf
, sizeof(buf
), "%s/%02x/%02x.%d",
146 pci_get_param(a
, "proc.path"),
147 d
->bus
, d
->dev
, d
->func
);
148 if (e
< 0 || e
>= (int) sizeof(buf
))
149 a
->error("File name too long");
150 a
->fd_rw
= a
->writeable
|| rw
;
151 a
->fd
= open(buf
, a
->fd_rw
? O_RDWR
: O_RDONLY
);
154 e
= snprintf(buf
, sizeof(buf
), "%s/%04x:%02x/%02x.%d",
155 pci_get_param(a
, "proc.path"),
156 d
->domain
, d
->bus
, d
->dev
, d
->func
);
157 if (e
< 0 || e
>= (int) sizeof(buf
))
158 a
->error("File name too long");
159 a
->fd
= open(buf
, a
->fd_rw
? O_RDWR
: O_RDONLY
);
162 a
->warning("Cannot open %s", buf
);
169 proc_read(struct pci_dev
*d
, int pos
, byte
*buf
, int len
)
171 int fd
= proc_setup(d
, 0);
176 res
= pread(fd
, buf
, len
, pos
);
179 d
->access
->warning("proc_read: read failed: %s", strerror(errno
));
188 proc_write(struct pci_dev
*d
, int pos
, byte
*buf
, int len
)
190 int fd
= proc_setup(d
, 1);
195 res
= pwrite(fd
, buf
, len
, pos
);
198 d
->access
->warning("proc_write: write failed: %s", strerror(errno
));
203 d
->access
->warning("proc_write: tried to write %d bytes at %d, but only %d succeeded", len
, pos
, res
);
210 proc_cleanup_dev(struct pci_dev
*d
)
212 if (d
->access
->cached_dev
== d
)
213 d
->access
->cached_dev
= NULL
;
216 struct pci_methods pm_linux_proc
= {
217 .name
= "linux-proc",
218 .help
= "The proc file system on Linux",
219 .config
= proc_config
,
220 .detect
= proc_detect
,
222 .cleanup
= proc_cleanup
,
224 .fill_info
= pci_generic_fill_info
,
227 .cleanup_dev
= proc_cleanup_dev
,