pciconf.c revision 41103
119102Sse/*
219102Sse * Copyright 1996 Massachusetts Institute of Technology
319102Sse *
419102Sse * Permission to use, copy, modify, and distribute this software and
519102Sse * its documentation for any purpose and without fee is hereby
619102Sse * granted, provided that both the above copyright notice and this
719102Sse * permission notice appear in all copies, that both the above
819102Sse * copyright notice and this permission notice appear in all
919102Sse * supporting documentation, and that the name of M.I.T. not be used
1019102Sse * in advertising or publicity pertaining to distribution of the
1119102Sse * software without specific, written prior permission.  M.I.T. makes
1219102Sse * no representations about the suitability of this software for any
1319102Sse * purpose.  It is provided "as is" without express or implied
1419102Sse * warranty.
1519102Sse *
1619102Sse * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
1719102Sse * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
1819102Sse * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1919102Sse * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
2019102Sse * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2119102Sse * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2219102Sse * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2319102Sse * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2419102Sse * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2519102Sse * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
2619102Sse * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2719102Sse * SUCH DAMAGE.
2819102Sse */
2919102Sse
3030172Scharnier#ifndef lint
3130172Scharnierstatic const char rcsid[] =
3241103Sken	"$Id: pciconf.c,v 1.6 1998/09/15 08:21:13 gibbs Exp $";
3330172Scharnier#endif /* not lint */
3430172Scharnier
3519102Sse#include <sys/types.h>
3619102Sse#include <sys/fcntl.h>
3719102Sse
3819102Sse#include <err.h>
3919102Sse#include <stdlib.h>
4019102Sse#include <stdio.h>
4119102Sse#include <string.h>
4219102Sse#include <unistd.h>
4319102Sse
4419102Sse#include <pci/pcivar.h>
4519102Sse#include <pci/pci_ioctl.h>
4619102Sse
4719102Sse#include "pathnames.h"
4819102Sse
4919102Ssestatic void list_devs(void);
5019102Ssestatic void readit(const char *, const char *, int);
5119102Ssestatic void writeit(const char *, const char *, const char *, int);
5221935Ssestatic void chkattached(const char *, int);
5319102Sse
5421935Ssestatic exitstatus = 0;
5519102Sse
5619102Ssestatic void
5730172Scharnierusage()
5830172Scharnier{
5930172Scharnier	fprintf(stderr, "%s\n%s\n%s\n%s\n",
6030172Scharnier		"usage: pciconf -l",
6130172Scharnier		"       pciconf -a sel",
6230172Scharnier		"       pciconf -r [-b | -h] sel addr",
6330172Scharnier		"       pciconf -w [-b | -h] sel addr [value]");
6419817Sse	exit (1);
6519102Sse}
6619102Sse
6719102Sseint
6819102Ssemain(int argc, char **argv)
6919102Sse{
7019102Sse	int c;
7121935Sse	int listmode, readmode, writemode, attachedmode;
7219102Sse	int byte, isshort;
7319102Sse
7421935Sse	listmode = readmode = writemode = attachedmode = byte = isshort = 0;
7519102Sse
7624428Simp	while ((c = getopt(argc, argv, "alrwbh")) != -1) {
7719102Sse		switch(c) {
7821935Sse		case 'a':
7921935Sse			attachedmode = 1;
8021935Sse			break;
8121935Sse
8219102Sse		case 'l':
8319102Sse			listmode = 1;
8419102Sse			break;
8519102Sse
8619102Sse		case 'r':
8719102Sse			readmode = 1;
8819102Sse			break;
8919102Sse
9019102Sse		case 'w':
9119102Sse			writemode = 1;
9219102Sse			break;
9319102Sse
9419102Sse		case 'b':
9519102Sse			byte = 1;
9619102Sse			break;
9719102Sse
9819102Sse		case 'h':
9919102Sse			isshort = 1;
10019102Sse			break;
10119102Sse
10219102Sse		default:
10330172Scharnier			usage();
10419102Sse		}
10519102Sse	}
10619102Sse
10719102Sse	if ((listmode && optind != argc)
10819102Sse	    || (writemode && optind + 3 != argc)
10921935Sse	    || (readmode && optind + 2 != argc)
11021935Sse	    || (attachedmode && optind + 1 != argc))
11130172Scharnier		usage();
11219102Sse
11319102Sse	if (listmode) {
11419102Sse		list_devs();
11521935Sse	} else if(attachedmode) {
11621935Sse		chkattached(argv[optind],
11721935Sse		       byte ? 1 : isshort ? 2 : 4);
11819102Sse	} else if(readmode) {
11919102Sse		readit(argv[optind], argv[optind + 1],
12019102Sse		       byte ? 1 : isshort ? 2 : 4);
12119102Sse	} else if(writemode) {
12219102Sse		writeit(argv[optind], argv[optind + 1], argv[optind + 2],
12319102Sse		       byte ? 1 : isshort ? 2 : 4);
12419102Sse	} else {
12530172Scharnier 		usage();
12619102Sse	}
12719102Sse
12821935Sse	return exitstatus;
12919102Sse}
13019102Sse
13119102Ssestatic void
13219102Sselist_devs(void)
13319102Sse{
13419102Sse	int fd;
13519102Sse	struct pci_conf_io pc;
13619102Sse	struct pci_conf conf[255], *p;
13741103Sken	int none_count = 0;
13819102Sse
13939231Sgibbs	fd = open(_PATH_DEVPCI, O_RDWR, 0);
14019102Sse	if (fd < 0)
14119102Sse		err(1, "%s", _PATH_DEVPCI);
14219102Sse
14339231Sgibbs	bzero(&pc, sizeof(struct pci_conf_io));
14439231Sgibbs	pc.match_buf_len = sizeof(conf);
14539231Sgibbs	pc.matches = conf;
14619102Sse
14739231Sgibbs	do {
14839231Sgibbs		if (ioctl(fd, PCIOCGETCONF, &pc) == -1)
14939231Sgibbs			err(1, "ioctl(PCIOCGETCONF)");
15019102Sse
15139231Sgibbs		/*
15239231Sgibbs		 * 255 entries should be more than enough for most people,
15339231Sgibbs		 * but if someone has more devices, and then changes things
15439231Sgibbs		 * around between ioctls, we'll do the cheezy thing and
15539231Sgibbs		 * just bail.  The alternative would be to go back to the
15639231Sgibbs		 * beginning of the list, and print things twice, which may
15739231Sgibbs		 * not be desireable.
15839231Sgibbs		 */
15939231Sgibbs		if (pc.status == PCI_GETCONF_LIST_CHANGED) {
16039231Sgibbs			warnx("PCI device list changed, please try again");
16139231Sgibbs			exitstatus = 1;
16239231Sgibbs			close(fd);
16339231Sgibbs			return;
16439231Sgibbs		} else if (pc.status ==  PCI_GETCONF_ERROR) {
16539231Sgibbs			warnx("Error returned from PCIOCGETCONF ioctl");
16639231Sgibbs			exitstatus = 1;
16739231Sgibbs			close(fd);
16839231Sgibbs			return;
16939231Sgibbs		}
17039231Sgibbs		for (p = conf; p < &conf[pc.num_matches]; p++) {
17139231Sgibbs
17239231Sgibbs			printf("%s%d@pci%d:%d:%d:\tclass=0x%06x card=0x%08lx "
17339231Sgibbs			       "chip=0x%08lx rev=0x%02x hdr=0x%02x\n",
17441103Sken			       (p->pd_name && *p->pd_name) ? p->pd_name :
17541103Sken			       "none",
17641103Sken			       (p->pd_name && *p->pd_name) ? p->pd_unit :
17741103Sken			       none_count++,
17839231Sgibbs			       p->pc_sel.pc_bus, p->pc_sel.pc_dev,
17939231Sgibbs			       p->pc_sel.pc_func, (p->pc_class << 16) |
18039231Sgibbs			       (p->pc_subclass << 8) | p->pc_progif,
18139231Sgibbs			       (p->pc_subdevice << 16) | p->pc_subvendor,
18239231Sgibbs			       (p->pc_device << 16) | p->pc_vendor,
18339231Sgibbs			       p->pc_revid, p->pc_hdr);
18439231Sgibbs		}
18539231Sgibbs	} while (pc.status == PCI_GETCONF_MORE_DEVS);
18639231Sgibbs
18719102Sse	close(fd);
18819102Sse}
18919102Sse
19019102Ssestatic struct pcisel
19119102Ssegetsel(const char *str)
19219102Sse{
19319102Sse	char *ep = (char*) str;
19419102Sse	struct pcisel sel;
19519102Sse
19619102Sse	if (strncmp(ep, "pci", 3) == 0) {
19719102Sse		ep += 3;
19819102Sse		sel.pc_bus = strtoul(ep, &ep, 0);
19919102Sse		if (!ep || *ep++ != ':')
20019102Sse			errx(1, "cannot parse selector %s", str);
20119102Sse		sel.pc_dev = strtoul(ep, &ep, 0);
20219102Sse		if (!ep || *ep != ':') {
20319102Sse			sel.pc_func = 0;
20419102Sse		} else {
20519102Sse			ep++;
20619102Sse			sel.pc_func = strtoul(ep, &ep, 0);
20719102Sse		}
20819102Sse	}
20919102Sse	if (*ep == ':')
21019102Sse		ep++;
21119102Sse	if (*ep || ep == str)
21219102Sse		errx(1, "cannot parse selector %s", str);
21319102Sse	return sel;
21419102Sse}
21519102Sse
21619102Ssestatic void
21719102Ssereadit(const char *name, const char *reg, int width)
21819102Sse{
21919102Sse	int fd;
22019102Sse	struct pci_io pi;
22119102Sse
22219102Sse	pi.pi_sel = getsel(name);
22319102Sse	pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */
22419102Sse	pi.pi_width = width;
22519102Sse
22619102Sse	fd = open(_PATH_DEVPCI, O_RDWR, 0);
22719102Sse	if (fd < 0)
22819102Sse		err(1, "%s", _PATH_DEVPCI);
22919102Sse
23019102Sse	if (ioctl(fd, PCIOCREAD, &pi) < 0)
23119102Sse		err(1, "ioctl(PCIOCREAD)");
23219102Sse
23319102Sse	printf("0x%08x\n", pi.pi_data);
23419102Sse}
23519102Sse
23619102Ssestatic void
23719102Ssewriteit(const char *name, const char *reg, const char *data, int width)
23819102Sse{
23919102Sse	int fd;
24019102Sse	struct pci_io pi;
24119102Sse
24219102Sse	pi.pi_sel = getsel(name);
24319102Sse	pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */
24419102Sse	pi.pi_width = width;
24519102Sse	pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */
24619102Sse
24719102Sse	fd = open(_PATH_DEVPCI, O_RDWR, 0);
24819102Sse	if (fd < 0)
24919102Sse		err(1, "%s", _PATH_DEVPCI);
25019102Sse
25119102Sse	if (ioctl(fd, PCIOCWRITE, &pi) < 0)
25219102Sse		err(1, "ioctl(PCIOCWRITE)");
25319102Sse}
25421935Sse
25521935Ssestatic void
25621935Ssechkattached (const char *name, int width)
25721935Sse{
25821935Sse	int fd;
25921935Sse	struct pci_io pi;
26021935Sse
26121935Sse	pi.pi_sel = getsel(name);
26221935Sse	pi.pi_reg = 0;
26321935Sse	pi.pi_width = width;
26421935Sse	pi.pi_data = 0;
26521935Sse
26621935Sse	fd = open(_PATH_DEVPCI, O_RDWR, 0);
26721935Sse	if (fd < 0)
26821935Sse		err(1, "%s", _PATH_DEVPCI);
26921935Sse
27021935Sse	if (ioctl(fd, PCIOCATTACHED, &pi) < 0)
27121935Sse		err(1, "ioctl(PCIOCATTACHED)");
27221935Sse
27321935Sse	exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */
27421935Sse	printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached");
27521935Sse}
276