summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2001-06-23 03:30:39 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2001-06-23 03:30:39 +0000
commit53429270408e554c3738afc2b6008017e7819e7f (patch)
treeb17749c46c0d58bc4b1347509cc759da31883c04
parentf13e0c71f1aae8d4d488fcfdd478d86e9ce198f1 (diff)
PCI bus configuration userland access from FreeBSD.
Will be used by XFree86 on powerpc (works on i386 too, but its not currently used).
-rw-r--r--sys/arch/i386/i386/conf.c12
-rw-r--r--sys/arch/powerpc/conf/GENERIC4
-rw-r--r--sys/arch/powerpc/powerpc/conf.c12
-rw-r--r--sys/dev/pci/pci.c136
-rw-r--r--sys/sys/conf.h9
-rw-r--r--sys/sys/pciio.h115
6 files changed, 283 insertions, 5 deletions
diff --git a/sys/arch/i386/i386/conf.c b/sys/arch/i386/i386/conf.c
index fefd4b582ab..b8cd08d4dbd 100644
--- a/sys/arch/i386/i386/conf.c
+++ b/sys/arch/i386/i386/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.70 2001/06/21 13:21:46 nate Exp $ */
+/* $OpenBSD: conf.c,v 1.71 2001/06/23 03:30:37 matthieu Exp $ */
/* $NetBSD: conf.c,v 1.75 1996/05/03 19:40:20 christos Exp $ */
/*
@@ -230,6 +230,11 @@ cdev_decl(cztty);
#include "wsmux.h"
cdev_decl(wsmux);
+#ifdef USER_PCICONF
+#include "pci.h"
+cdev_decl(pci);
+#endif
+
struct cdevsw cdevsw[] =
{
cdev_cn_init(1,cn), /* 0: virtual console */
@@ -328,6 +333,11 @@ struct cdevsw cdevsw[] =
cdev_mouse_init(NWSMUX, wsmux), /* 69: ws multiplexor */
cdev_crypto_init(NCRYPTO,crypto), /* 70: /dev/crypto */
cdev_tty_init(NCZ,cztty), /* 71: Cyclades-Z serial port */
+#ifdef USER_PCICONF
+ cdev_pci_init(NPCI,pci), /* 71: PCI user */
+#else
+ cdev_notdef(),
+#endif
};
int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]);
diff --git a/sys/arch/powerpc/conf/GENERIC b/sys/arch/powerpc/conf/GENERIC
index 417a7dbd4c7..c4a4f11460e 100644
--- a/sys/arch/powerpc/conf/GENERIC
+++ b/sys/arch/powerpc/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.35 2001/06/17 03:44:03 drahn Exp $
+# $OpenBSD: GENERIC,v 1.36 2001/06/23 03:30:38 matthieu Exp $
#
# PPC GENERIC config file
#
@@ -18,6 +18,8 @@ option PCIVERBOSE
option USBVERBOSE
option WSEMUL_NO_DUMB
+option USER_PCICONF # user-space PCI configuration
+
include "../../../conf/GENERIC"
config bsd swap generic
diff --git a/sys/arch/powerpc/powerpc/conf.c b/sys/arch/powerpc/powerpc/conf.c
index eadfd8bad8d..bf20a219bf3 100644
--- a/sys/arch/powerpc/powerpc/conf.c
+++ b/sys/arch/powerpc/powerpc/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.20 2001/03/29 19:56:33 drahn Exp $ */
+/* $OpenBSD: conf.c,v 1.21 2001/06/23 03:30:38 matthieu Exp $ */
/*
* Copyright (c) 1997 Per Fogelstrom
@@ -183,6 +183,11 @@ cdev_decl(ucom);
#include "wsmux.h"
cdev_decl(wsmux);
+#ifdef USER_PCICONF
+#include "pci.h"
+cdev_decl(pci);
+#endif
+
#include "audio.h"
cdev_decl(audio);
@@ -267,6 +272,11 @@ struct cdevsw cdevsw[] = {
cdev_mouse_init(NWSMOUSE, /* 69: mice */
wsmouse),
cdev_mouse_init(NWSMUX, wsmux), /* 70: ws multiplexor */
+#ifdef USER_PCICONF
+ cdev_pci_init(NPCI,pci), /* 71: PCI user */
+#else
+ cdev_notdef(),
+#endif
};
int nchrdev = sizeof cdevsw / sizeof cdevsw[0];
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 14e41423517..e29c0f7f528 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci.c,v 1.16 2001/01/27 05:02:39 mickey Exp $ */
+/* $OpenBSD: pci.c,v 1.17 2001/06/23 03:30:37 matthieu Exp $ */
/* $NetBSD: pci.c,v 1.31 1997/06/06 23:48:04 thorpej Exp $ */
/*
@@ -46,8 +46,19 @@
int pcimatch __P((struct device *, void *, void *));
void pciattach __P((struct device *, struct device *, void *));
+#ifdef USER_PCICONF
+struct pci_softc {
+ struct device sc_dev;
+ pci_chipset_tag_t sc_pc;
+};
+#endif
+
struct cfattach pci_ca = {
+#ifndef USER_PCICONF
sizeof(struct device), pcimatch, pciattach
+#else
+ sizeof(struct pci_softc), pcimatch, pciattach
+#endif
};
struct cfdriver pci_cd = {
@@ -117,6 +128,9 @@ pciattach(parent, self, aux)
bus_space_tag_t iot, memt;
pci_chipset_tag_t pc;
int bus, device, maxndevs, function, nfunctions;
+#ifdef USER_PCICONF
+ struct pci_softc *sc = (struct pci_softc *)self;
+#endif
pci_attach_hook(parent, self, pba);
printf("\n");
@@ -127,6 +141,10 @@ pciattach(parent, self, aux)
bus = pba->pba_bus;
maxndevs = pci_bus_maxdevs(pc, bus);
+#ifdef USER_PCICONF
+ sc->sc_pc = pba->pba_pc;
+#endif
+
if (bus == 0)
pci_isa_bridge_callback = NULL;
@@ -321,3 +339,119 @@ pci_get_capability(pc, tag, capid, offset, value)
return (0);
}
+
+#ifdef USER_PCICONF
+/*
+ * This is the user interface to PCI configuration space.
+ */
+
+#include <sys/pciio.h>
+#include <sys/fcntl.h>
+
+#ifdef DEBUG
+#define PCIDEBUG(x) printf x
+#else
+#define PCIDEBUG(x)
+#endif
+
+
+int pciopen __P((dev_t dev, int oflags, int devtype, struct proc *p));
+int pciclose __P((dev_t dev, int flag, int devtype, struct proc *p));
+int pciioctl __P((dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p));
+
+int
+pciopen(dev_t dev, int oflags, int devtype, struct proc *p)
+{
+ PCIDEBUG(("pciopen ndevs: %d\n" , pci_cd.cd_ndevs));
+
+ if ((oflags & FWRITE) && securelevel > 0) {
+ return EPERM;
+ }
+ return 0;
+}
+
+int
+pciclose(dev_t dev, int flag, int devtype, struct proc *p)
+{
+ PCIDEBUG(("pciclose\n"));
+ return 0;
+}
+
+int
+pciioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct pci_io *io;
+ int error;
+ pcitag_t tag;
+ struct pci_softc *pci;
+ pci_chipset_tag_t pc;
+
+ io = (struct pci_io *)data;
+
+ PCIDEBUG(("pciioctl cmd %s", cmd == PCIOCREAD ? "pciocread"
+ : cmd == PCIOCWRITE ? "pciocwrite" : "unknown"));
+ PCIDEBUG((" bus %d dev %d func %d reg %x\n", io->pi_sel.pc_bus,
+ io->pi_sel.pc_dev, io->pi_sel.pc_func, io->pi_reg));
+
+ if (io->pi_sel.pc_bus >= pci_cd.cd_ndevs) {
+ error = ENXIO;
+ goto done;
+ }
+ pci = pci_cd.cd_devs[io->pi_sel.pc_bus];
+ if (pci != NULL) {
+ pc = pci->sc_pc;
+ } else {
+ error = ENXIO;
+ goto done;
+ }
+
+ if (!(flag & FWRITE))
+ return EPERM;
+
+
+ tag = pci_make_tag(pc, io->pi_sel.pc_bus, io->pi_sel.pc_dev,
+ io->pi_sel.pc_func);
+
+ switch(cmd) {
+ case PCIOCGETCONF:
+ error = ENODEV;
+ break;
+
+ case PCIOCREAD:
+ switch(io->pi_width) {
+ case 4:
+ /* Make sure the register is properly aligned */
+ if (io->pi_reg & 0x3)
+ return EINVAL;
+ io->pi_data = pci_conf_read(pc, tag, io->pi_reg);
+ error = 0;
+ break;
+ default:
+ error = ENODEV;
+ break;
+ }
+ break;
+
+ case PCIOCWRITE:
+ switch(io->pi_width) {
+ case 4:
+ /* Make sure the register is properly aligned */
+ if (io->pi_reg & 0x3)
+ return EINVAL;
+ pci_conf_write(pc, tag, io->pi_reg, io->pi_data);
+ break;
+ default:
+ error = ENODEV;
+ break;
+ }
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+ done:
+ return (error);
+}
+
+#endif
diff --git a/sys/sys/conf.h b/sys/sys/conf.h
index 3c8dadbd607..4c283822151 100644
--- a/sys/sys/conf.h
+++ b/sys/sys/conf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.h,v 1.40 2001/05/13 15:39:26 deraadt Exp $ */
+/* $OpenBSD: conf.h,v 1.41 2001/06/23 03:30:37 matthieu Exp $ */
/* $NetBSD: conf.h,v 1.33 1996/05/03 20:03:32 christos Exp $ */
/*-
@@ -410,6 +410,13 @@ void randomattach __P((void));
#define cdev_usbdev_init(c,n) cdev_random_init(c,n)
#define cdev_ugen_init(c,n) cdev_random_init(c,n)
+/* open, close, ioctl */
+#define cdev_pci_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+ (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) enodev, 0, (dev_type_select((*))) enodev, \
+ (dev_type_mmap((*))) enodev }
+
/* symbolic sleep message strings */
extern char devopn[], devio[], devwait[], devin[], devout[];
extern char devioc[], devcls[];
diff --git a/sys/sys/pciio.h b/sys/sys/pciio.h
new file mode 100644
index 00000000000..8e31e3e3408
--- /dev/null
+++ b/sys/sys/pciio.h
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 1997, Stefan Esser <se@FreeBSD.ORG>
+ * Copyright (c) 1997, 1998, 1999, Kenneth D. Merry <ken@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sys/pciio.h,v 1.5 1999/12/08 17:44:04 ken Exp $
+ *
+ */
+
+#ifndef _SYS_PCIIO_H_
+#define _SYS_PCIIO_H_
+
+#include <sys/ioccom.h>
+
+#define PCI_MAXNAMELEN 16
+
+typedef enum {
+ PCI_GETCONF_LAST_DEVICE,
+ PCI_GETCONF_LIST_CHANGED,
+ PCI_GETCONF_MORE_DEVS,
+ PCI_GETCONF_ERROR
+} pci_getconf_status;
+
+typedef enum {
+ PCI_GETCONF_NO_MATCH = 0x00,
+ PCI_GETCONF_MATCH_BUS = 0x01,
+ PCI_GETCONF_MATCH_DEV = 0x02,
+ PCI_GETCONF_MATCH_FUNC = 0x04,
+ PCI_GETCONF_MATCH_NAME = 0x08,
+ PCI_GETCONF_MATCH_UNIT = 0x10,
+ PCI_GETCONF_MATCH_VENDOR = 0x20,
+ PCI_GETCONF_MATCH_DEVICE = 0x40,
+ PCI_GETCONF_MATCH_CLASS = 0x80
+} pci_getconf_flags;
+
+struct pcisel {
+ u_int8_t pc_bus; /* bus number */
+ u_int8_t pc_dev; /* device on this bus */
+ u_int8_t pc_func; /* function on this device */
+};
+
+struct pci_conf {
+ struct pcisel pc_sel; /* bus+slot+function */
+ u_int8_t pc_hdr; /* PCI header type */
+ u_int16_t pc_subvendor; /* card vendor ID */
+ u_int16_t pc_subdevice; /* card device ID, assigned by
+ card vendor */
+ u_int16_t pc_vendor; /* chip vendor ID */
+ u_int16_t pc_device; /* chip device ID, assigned by
+ chip vendor */
+ u_int8_t pc_class; /* chip PCI class */
+ u_int8_t pc_subclass; /* chip PCI subclass */
+ u_int8_t pc_progif; /* chip PCI programming interface */
+ u_int8_t pc_revid; /* chip revision ID */
+ char pd_name[PCI_MAXNAMELEN + 1]; /* device name */
+ u_long pd_unit; /* device unit number */
+};
+
+struct pci_match_conf {
+ struct pcisel pc_sel; /* bus+slot+function */
+ char pd_name[PCI_MAXNAMELEN + 1]; /* device name */
+ u_long pd_unit; /* Unit number */
+ u_int16_t pc_vendor; /* PCI Vendor ID */
+ u_int16_t pc_device; /* PCI Device ID */
+ u_int8_t pc_class; /* PCI class */
+ pci_getconf_flags flags; /* Matching expression */
+};
+
+struct pci_conf_io {
+ u_int32_t pat_buf_len; /* pattern buffer length */
+ u_int32_t num_patterns; /* number of patterns */
+ struct pci_match_conf *patterns; /* pattern buffer */
+ u_int32_t match_buf_len; /* match buffer length */
+ u_int32_t num_matches; /* number of matches returned */
+ struct pci_conf *matches; /* match buffer */
+ u_int32_t offset; /* offset into device list */
+ u_int32_t generation; /* device list generation */
+ pci_getconf_status status; /* request status */
+};
+
+struct pci_io {
+ struct pcisel pi_sel; /* device to operate on */
+ int pi_reg; /* configuration register to examine */
+ int pi_width; /* width (in bytes) of read or write */
+ u_int32_t pi_data; /* data to write or result of read */
+};
+
+
+#define PCIOCGETCONF _IOWR('p', 1, struct pci_conf_io)
+#define PCIOCREAD _IOWR('p', 2, struct pci_io)
+#define PCIOCWRITE _IOWR('p', 3, struct pci_io)
+#define PCIOCATTACHED _IOWR('p', 4, struct pci_io)
+
+#endif /* !_SYS_PCIIO_H_ */