diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2001-06-23 03:30:39 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2001-06-23 03:30:39 +0000 |
commit | 53429270408e554c3738afc2b6008017e7819e7f (patch) | |
tree | b17749c46c0d58bc4b1347509cc759da31883c04 | |
parent | f13e0c71f1aae8d4d488fcfdd478d86e9ce198f1 (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.c | 12 | ||||
-rw-r--r-- | sys/arch/powerpc/conf/GENERIC | 4 | ||||
-rw-r--r-- | sys/arch/powerpc/powerpc/conf.c | 12 | ||||
-rw-r--r-- | sys/dev/pci/pci.c | 136 | ||||
-rw-r--r-- | sys/sys/conf.h | 9 | ||||
-rw-r--r-- | sys/sys/pciio.h | 115 |
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_ */ |