pciconf.c revision 50479
1238405Sjkim/*
2238405Sjkim * Copyright 1996 Massachusetts Institute of Technology
3238405Sjkim *
4238405Sjkim * Permission to use, copy, modify, and distribute this software and
5238405Sjkim * its documentation for any purpose and without fee is hereby
6238405Sjkim * granted, provided that both the above copyright notice and this
7238405Sjkim * permission notice appear in all copies, that both the above
8238405Sjkim * copyright notice and this permission notice appear in all
9238405Sjkim * supporting documentation, and that the name of M.I.T. not be used
10238405Sjkim * in advertising or publicity pertaining to distribution of the
11238405Sjkim * software without specific, written prior permission.  M.I.T. makes
12238405Sjkim * no representations about the suitability of this software for any
13238405Sjkim * purpose.  It is provided "as is" without express or implied
14238405Sjkim * warranty.
15238405Sjkim *
16238405Sjkim * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17238405Sjkim * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18238405Sjkim * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19238405Sjkim * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20238405Sjkim * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21238405Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22238405Sjkim * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23238405Sjkim * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24238405Sjkim * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25238405Sjkim * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26238405Sjkim * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27238405Sjkim * SUCH DAMAGE.
28238405Sjkim */
29238405Sjkim
30238405Sjkim#ifndef lint
31238405Sjkimstatic const char rcsid[] =
32238405Sjkim  "$FreeBSD: head/usr.sbin/pciconf/pciconf.c 50479 1999-08-28 01:35:59Z peter $";
33238405Sjkim#endif /* not lint */
34238405Sjkim
35238405Sjkim#include <sys/types.h>
36238405Sjkim#include <sys/fcntl.h>
37238405Sjkim
38238405Sjkim#include <err.h>
39238405Sjkim#include <stdlib.h>
40238405Sjkim#include <stdio.h>
41238405Sjkim#include <string.h>
42238405Sjkim#include <unistd.h>
43238405Sjkim
44238405Sjkim#include <pci/pcivar.h>
45238405Sjkim#include <pci/pci_ioctl.h>
46238405Sjkim
47238405Sjkim#include "pathnames.h"
48238405Sjkim
49238405Sjkimstatic void list_devs(void);
50238405Sjkimstatic void readit(const char *, const char *, int);
51238405Sjkimstatic void writeit(const char *, const char *, const char *, int);
52238405Sjkimstatic void chkattached(const char *, int);
53238405Sjkim
54238405Sjkimstatic int exitstatus = 0;
55238405Sjkim
56238405Sjkimstatic void
57238405Sjkimusage()
58238405Sjkim{
59238405Sjkim	fprintf(stderr, "%s\n%s\n%s\n%s\n",
60238405Sjkim		"usage: pciconf -l",
61238405Sjkim		"       pciconf -a sel",
62238405Sjkim		"       pciconf -r [-b | -h] sel addr",
63238405Sjkim		"       pciconf -w [-b | -h] sel addr [value]");
64238405Sjkim	exit (1);
65238405Sjkim}
66238405Sjkim
67238405Sjkimint
68238405Sjkimmain(int argc, char **argv)
69238405Sjkim{
70238405Sjkim	int c;
71238405Sjkim	int listmode, readmode, writemode, attachedmode;
72238405Sjkim	int byte, isshort;
73238405Sjkim
74238405Sjkim	listmode = readmode = writemode = attachedmode = byte = isshort = 0;
75238405Sjkim
76238405Sjkim	while ((c = getopt(argc, argv, "alrwbh")) != -1) {
77238405Sjkim		switch(c) {
78238405Sjkim		case 'a':
79238405Sjkim			attachedmode = 1;
80238405Sjkim			break;
81238405Sjkim
82238405Sjkim		case 'l':
83238405Sjkim			listmode = 1;
84238405Sjkim			break;
85238405Sjkim
86238405Sjkim		case 'r':
87238405Sjkim			readmode = 1;
88238405Sjkim			break;
89238405Sjkim
90238405Sjkim		case 'w':
91238405Sjkim			writemode = 1;
92238405Sjkim			break;
93238405Sjkim
94238405Sjkim		case 'b':
95238405Sjkim			byte = 1;
96238405Sjkim			break;
97238405Sjkim
98238405Sjkim		case 'h':
99238405Sjkim			isshort = 1;
100238405Sjkim			break;
101238405Sjkim
102238405Sjkim		default:
103238405Sjkim			usage();
104238405Sjkim		}
105238405Sjkim	}
106238405Sjkim
107238405Sjkim	if ((listmode && optind != argc)
108238405Sjkim	    || (writemode && optind + 3 != argc)
109238405Sjkim	    || (readmode && optind + 2 != argc)
110238405Sjkim	    || (attachedmode && optind + 1 != argc))
111238405Sjkim		usage();
112238405Sjkim
113238405Sjkim	if (listmode) {
114238405Sjkim		list_devs();
115238405Sjkim	} else if(attachedmode) {
116238405Sjkim		chkattached(argv[optind],
117238405Sjkim		       byte ? 1 : isshort ? 2 : 4);
118238405Sjkim	} else if(readmode) {
119238405Sjkim		readit(argv[optind], argv[optind + 1],
120238405Sjkim		       byte ? 1 : isshort ? 2 : 4);
121238405Sjkim	} else if(writemode) {
122238405Sjkim		writeit(argv[optind], argv[optind + 1], argv[optind + 2],
123238405Sjkim		       byte ? 1 : isshort ? 2 : 4);
124238405Sjkim	} else {
125238405Sjkim 		usage();
126238405Sjkim	}
127238405Sjkim
128238405Sjkim	return exitstatus;
129238405Sjkim}
130238405Sjkim
131238405Sjkimstatic void
132238405Sjkimlist_devs(void)
133238405Sjkim{
134238405Sjkim	int fd;
135238405Sjkim	struct pci_conf_io pc;
136238405Sjkim	struct pci_conf conf[255], *p;
137238405Sjkim	int none_count = 0;
138238405Sjkim
139238405Sjkim	fd = open(_PATH_DEVPCI, O_RDWR, 0);
140238405Sjkim	if (fd < 0)
141238405Sjkim		err(1, "%s", _PATH_DEVPCI);
142238405Sjkim
143238405Sjkim	bzero(&pc, sizeof(struct pci_conf_io));
144238405Sjkim	pc.match_buf_len = sizeof(conf);
145238405Sjkim	pc.matches = conf;
146238405Sjkim
147238405Sjkim	do {
148238405Sjkim		if (ioctl(fd, PCIOCGETCONF, &pc) == -1)
149238405Sjkim			err(1, "ioctl(PCIOCGETCONF)");
150238405Sjkim
151238405Sjkim		/*
152238405Sjkim		 * 255 entries should be more than enough for most people,
153238405Sjkim		 * but if someone has more devices, and then changes things
154238405Sjkim		 * around between ioctls, we'll do the cheezy thing and
155238405Sjkim		 * just bail.  The alternative would be to go back to the
156238405Sjkim		 * beginning of the list, and print things twice, which may
157238405Sjkim		 * not be desireable.
158238405Sjkim		 */
159238405Sjkim		if (pc.status == PCI_GETCONF_LIST_CHANGED) {
160238405Sjkim			warnx("PCI device list changed, please try again");
161238405Sjkim			exitstatus = 1;
162238405Sjkim			close(fd);
163238405Sjkim			return;
164238405Sjkim		} else if (pc.status ==  PCI_GETCONF_ERROR) {
165238405Sjkim			warnx("Error returned from PCIOCGETCONF ioctl");
166238405Sjkim			exitstatus = 1;
167238405Sjkim			close(fd);
168238405Sjkim			return;
169238405Sjkim		}
170238405Sjkim		for (p = conf; p < &conf[pc.num_matches]; p++) {
171238405Sjkim
172238405Sjkim			printf("%s%d@pci%d:%d:%d:\tclass=0x%06x card=0x%08x "
173238405Sjkim			       "chip=0x%08x rev=0x%02x hdr=0x%02x\n",
174238405Sjkim			       (p->pd_name && *p->pd_name) ? p->pd_name :
175238405Sjkim			       "none",
176238405Sjkim			       (p->pd_name && *p->pd_name) ? (int)p->pd_unit :
177238405Sjkim			       none_count++,
178238405Sjkim			       p->pc_sel.pc_bus, p->pc_sel.pc_dev,
179238405Sjkim			       p->pc_sel.pc_func, (p->pc_class << 16) |
180238405Sjkim			       (p->pc_subclass << 8) | p->pc_progif,
181238405Sjkim			       (p->pc_subdevice << 16) | p->pc_subvendor,
182238405Sjkim			       (p->pc_device << 16) | p->pc_vendor,
183238405Sjkim			       p->pc_revid, p->pc_hdr);
184238405Sjkim		}
185238405Sjkim	} while (pc.status == PCI_GETCONF_MORE_DEVS);
186238405Sjkim
187238405Sjkim	close(fd);
188238405Sjkim}
189238405Sjkim
190238405Sjkimstatic struct pcisel
191238405Sjkimgetsel(const char *str)
192238405Sjkim{
193238405Sjkim	char *ep = (char*) str;
194238405Sjkim	struct pcisel sel;
195238405Sjkim
196238405Sjkim	if (strncmp(ep, "pci", 3) == 0) {
197238405Sjkim		ep += 3;
198238405Sjkim		sel.pc_bus = strtoul(ep, &ep, 0);
199238405Sjkim		if (!ep || *ep++ != ':')
200238405Sjkim			errx(1, "cannot parse selector %s", str);
201238405Sjkim		sel.pc_dev = strtoul(ep, &ep, 0);
202238405Sjkim		if (!ep || *ep != ':') {
203238405Sjkim			sel.pc_func = 0;
204238405Sjkim		} else {
205238405Sjkim			ep++;
206238405Sjkim			sel.pc_func = strtoul(ep, &ep, 0);
207238405Sjkim		}
208238405Sjkim	}
209238405Sjkim	if (*ep == ':')
210238405Sjkim		ep++;
211238405Sjkim	if (*ep || ep == str)
212238405Sjkim		errx(1, "cannot parse selector %s", str);
213238405Sjkim	return sel;
214238405Sjkim}
215238405Sjkim
216238405Sjkimstatic void
217238405Sjkimreadit(const char *name, const char *reg, int width)
218238405Sjkim{
219238405Sjkim	int fd;
220238405Sjkim	struct pci_io pi;
221238405Sjkim
222238405Sjkim	pi.pi_sel = getsel(name);
223238405Sjkim	pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */
224238405Sjkim	pi.pi_width = width;
225238405Sjkim
226238405Sjkim	fd = open(_PATH_DEVPCI, O_RDWR, 0);
227238405Sjkim	if (fd < 0)
228238405Sjkim		err(1, "%s", _PATH_DEVPCI);
229238405Sjkim
230238405Sjkim	if (ioctl(fd, PCIOCREAD, &pi) < 0)
231238405Sjkim		err(1, "ioctl(PCIOCREAD)");
232238405Sjkim
233238405Sjkim	printf("0x%08x\n", pi.pi_data);
234238405Sjkim}
235238405Sjkim
236238405Sjkimstatic void
237238405Sjkimwriteit(const char *name, const char *reg, const char *data, int width)
238238405Sjkim{
239238405Sjkim	int fd;
240238405Sjkim	struct pci_io pi;
241238405Sjkim
242238405Sjkim	pi.pi_sel = getsel(name);
243238405Sjkim	pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */
244238405Sjkim	pi.pi_width = width;
245238405Sjkim	pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */
246238405Sjkim
247238405Sjkim	fd = open(_PATH_DEVPCI, O_RDWR, 0);
248238405Sjkim	if (fd < 0)
249238405Sjkim		err(1, "%s", _PATH_DEVPCI);
250238405Sjkim
251238405Sjkim	if (ioctl(fd, PCIOCWRITE, &pi) < 0)
252238405Sjkim		err(1, "ioctl(PCIOCWRITE)");
253238405Sjkim}
254238405Sjkim
255238405Sjkimstatic void
256238405Sjkimchkattached (const char *name, int width)
257238405Sjkim{
258238405Sjkim	int fd;
259238405Sjkim	struct pci_io pi;
260238405Sjkim
261238405Sjkim	pi.pi_sel = getsel(name);
262238405Sjkim	pi.pi_reg = 0;
263238405Sjkim	pi.pi_width = width;
264238405Sjkim	pi.pi_data = 0;
265238405Sjkim
266238405Sjkim	fd = open(_PATH_DEVPCI, O_RDWR, 0);
267238405Sjkim	if (fd < 0)
268238405Sjkim		err(1, "%s", _PATH_DEVPCI);
269238405Sjkim
270238405Sjkim	if (ioctl(fd, PCIOCATTACHED, &pi) < 0)
271238405Sjkim		err(1, "ioctl(PCIOCATTACHED)");
272238405Sjkim
273238405Sjkim	exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */
274238405Sjkim	printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached");
275238405Sjkim}
276238405Sjkim