diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 472e5a5b88ba..d1d696ddcd3d 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -1,6 +1,6 @@ /************************************************************************** ** -** $Id: pci.c,v 1.55 1996/09/10 23:30:59 bde Exp $ +** $Id: pci.c,v 1.56 1996/10/14 13:04:34 se Exp $ ** ** General subroutines for the PCI bus. ** pci_configure () @@ -52,6 +52,11 @@ #include #include #include /* declaration of wakeup(), used by vm.h */ +#include +#ifdef DEVFS +#include +#endif /* DEVFS */ +#include #include #include @@ -63,6 +68,7 @@ #include #include #include +#include #define PCI_MAX_IRQ (16) @@ -114,6 +120,8 @@ pci_bridge_config (void); static int pci_mfdev (int bus, int device); +static void pci_remember (int bus, int dev, int func); + /*======================================================== ** ** Variables @@ -377,7 +385,7 @@ static int pci_mfdev (int bus, int device) { pcici_t tag0,tag1; - int pci_id0, pci_id1; + unsigned pci_id0, pci_id1; /* ** Detect a multi-function device that complies to the PCI 2.0 spec @@ -424,7 +432,7 @@ pci_bus_config (void) u_long data; int unit; u_char pciint; - u_char irq; + int irq; struct pci_device *dvp; @@ -514,6 +522,8 @@ pci_bus_config (void) maxfunc = 7; } + pci_remember(bus_no, device, func); + if (dvp==NULL) { #ifndef PCI_QUIET if (pci_conf_count) @@ -1720,4 +1730,156 @@ void not_supported (pcici_t tag, u_long type) } } } + +/* + * This is the user interface to the PCI configuration space. + */ +static struct pci_conf *pci_dev_list; +static unsigned pci_dev_list_count; +static unsigned pci_dev_list_size; + +static void +pci_remember(int bus, int dev, int func) +{ + struct pci_conf *p; + pcici_t tag; + + if (++pci_dev_list_count > pci_dev_list_size) { + struct pci_conf *new; + + pci_dev_list_size += 8; + MALLOC(new, struct pci_conf *, pci_dev_list_size * sizeof *new, + M_DEVL, M_NOWAIT); + if (!new) { + pci_dev_list_size -= 8; + pci_dev_list_count--; + return; + } + + if (pci_dev_list) { + bcopy(pci_dev_list, new, ((pci_dev_list_size - 8) * + sizeof *new)); + FREE(pci_dev_list, M_DEVL); + } + pci_dev_list = new; + } + + p = &pci_dev_list[pci_dev_list_count - 1]; + p->pc_sel.pc_bus = bus; + p->pc_sel.pc_dev = dev; + p->pc_sel.pc_func = func; + tag = pcibus->pb_tag (bus, dev, func); + p->pc_devid = pci_conf_read(tag, PCI_ID_REG); + p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG); + p->pc_class = pci_conf_read(tag, PCI_CLASS_REG); +} + +static int +pci_open(dev_t dev, int oflags, int devtype, struct proc *p) +{ + if ((oflags & FWRITE) && securelevel > 0) { + return EPERM; + } + + return 0; +} + +static int +pci_close(dev_t dev, int flag, int devtype, struct proc *p) +{ + return 0; +} + +static int +pci_ioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) +{ + struct pci_conf_io *cio; + struct pci_io *io; + size_t iolen; + int error; + pcici_t tag; + + if (cmd != PCIOCGETCONF && !(flag & FWRITE)) + return EPERM; + + switch(cmd) { + case PCIOCGETCONF: + cio = (struct pci_conf_io *)data; + iolen = min(cio->pci_len, + pci_dev_list_count * sizeof(struct pci_conf)); + cio->pci_len = pci_dev_list_count * sizeof(struct pci_conf); + + error = copyout(pci_dev_list, cio->pci_buf, iolen); + break; + + case PCIOCREAD: + io = (struct pci_io *)data; + switch(io->pi_width) { + case 4: + tag = pcibus->pb_tag (io->pi_sel.pc_bus, + io->pi_sel.pc_dev, + io->pi_sel.pc_func); + io->pi_data = pci_conf_read(tag, io->pi_reg); + error = 0; + break; + case 2: + case 1: + default: + error = ENODEV; + break; + } + break; + + case PCIOCWRITE: + io = (struct pci_io *)data; + switch(io->pi_width) { + case 4: + tag = pcibus->pb_tag (io->pi_sel.pc_bus, + io->pi_sel.pc_dev, + io->pi_sel.pc_func); + pci_conf_write(tag, io->pi_reg, io->pi_data); + error = 0; + break; + case 2: + case 1: + default: + error = ENODEV; + break; + } + break; + + default: + error = ENOTTY; + break; + } + + return (error); +} + +#define PCI_CDEV 78 + +static struct cdevsw pcicdev = { + pci_open, pci_close, noread, nowrite, pci_ioctl, nostop, noreset, + nodevtotty, noselect, nommap, nostrategy, "pci", 0, PCI_CDEV +}; + +#ifdef DEVFS +static void *pci_devfs_token; +#endif + +static void +pci_cdevinit(void *dummy) +{ + dev_t dev; + + dev = makedev(PCI_CDEV, 0); + cdevsw_add(&dev, &pcicdev, NULL); +#ifdef DEVFS + pci_devfs_token = devfs_add_devswf(&pcicdev, 0, DV_CHR, + UID_ROOT, GID_WHEEL, 0644, "pci"); +#endif +} + +SYSINIT(pcidev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+PCI_CDEV, pci_cdevinit, NULL); + #endif /* NPCI */ diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index ac1003ce91d7..54b446b4235a 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -1,6 +1,6 @@ /************************************************************************** ** -** $Id: pcireg.h,v 1.6 1996/01/19 19:03:47 se Exp $ +** $Id: pcireg.h,v 1.7 1996/01/25 18:31:59 se Exp $ ** ** Names for PCI configuration space registers. ** @@ -160,6 +160,7 @@ #define PCI_PCI_BRIDGE_MEM_REG 0x20 #define PCI_PCI_BRIDGE_PMEM_REG 0x24 +#define PCI_SUBID_REG 0x2c #define PCI_SUBORDINATE_BUS_MASK 0x00ff0000 #define PCI_SECONDARY_BUS_MASK 0x0000ff00 diff --git a/sys/pci/pci.c b/sys/pci/pci.c index 472e5a5b88ba..d1d696ddcd3d 100644 --- a/sys/pci/pci.c +++ b/sys/pci/pci.c @@ -1,6 +1,6 @@ /************************************************************************** ** -** $Id: pci.c,v 1.55 1996/09/10 23:30:59 bde Exp $ +** $Id: pci.c,v 1.56 1996/10/14 13:04:34 se Exp $ ** ** General subroutines for the PCI bus. ** pci_configure () @@ -52,6 +52,11 @@ #include #include #include /* declaration of wakeup(), used by vm.h */ +#include +#ifdef DEVFS +#include +#endif /* DEVFS */ +#include #include #include @@ -63,6 +68,7 @@ #include #include #include +#include #define PCI_MAX_IRQ (16) @@ -114,6 +120,8 @@ pci_bridge_config (void); static int pci_mfdev (int bus, int device); +static void pci_remember (int bus, int dev, int func); + /*======================================================== ** ** Variables @@ -377,7 +385,7 @@ static int pci_mfdev (int bus, int device) { pcici_t tag0,tag1; - int pci_id0, pci_id1; + unsigned pci_id0, pci_id1; /* ** Detect a multi-function device that complies to the PCI 2.0 spec @@ -424,7 +432,7 @@ pci_bus_config (void) u_long data; int unit; u_char pciint; - u_char irq; + int irq; struct pci_device *dvp; @@ -514,6 +522,8 @@ pci_bus_config (void) maxfunc = 7; } + pci_remember(bus_no, device, func); + if (dvp==NULL) { #ifndef PCI_QUIET if (pci_conf_count) @@ -1720,4 +1730,156 @@ void not_supported (pcici_t tag, u_long type) } } } + +/* + * This is the user interface to the PCI configuration space. + */ +static struct pci_conf *pci_dev_list; +static unsigned pci_dev_list_count; +static unsigned pci_dev_list_size; + +static void +pci_remember(int bus, int dev, int func) +{ + struct pci_conf *p; + pcici_t tag; + + if (++pci_dev_list_count > pci_dev_list_size) { + struct pci_conf *new; + + pci_dev_list_size += 8; + MALLOC(new, struct pci_conf *, pci_dev_list_size * sizeof *new, + M_DEVL, M_NOWAIT); + if (!new) { + pci_dev_list_size -= 8; + pci_dev_list_count--; + return; + } + + if (pci_dev_list) { + bcopy(pci_dev_list, new, ((pci_dev_list_size - 8) * + sizeof *new)); + FREE(pci_dev_list, M_DEVL); + } + pci_dev_list = new; + } + + p = &pci_dev_list[pci_dev_list_count - 1]; + p->pc_sel.pc_bus = bus; + p->pc_sel.pc_dev = dev; + p->pc_sel.pc_func = func; + tag = pcibus->pb_tag (bus, dev, func); + p->pc_devid = pci_conf_read(tag, PCI_ID_REG); + p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG); + p->pc_class = pci_conf_read(tag, PCI_CLASS_REG); +} + +static int +pci_open(dev_t dev, int oflags, int devtype, struct proc *p) +{ + if ((oflags & FWRITE) && securelevel > 0) { + return EPERM; + } + + return 0; +} + +static int +pci_close(dev_t dev, int flag, int devtype, struct proc *p) +{ + return 0; +} + +static int +pci_ioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) +{ + struct pci_conf_io *cio; + struct pci_io *io; + size_t iolen; + int error; + pcici_t tag; + + if (cmd != PCIOCGETCONF && !(flag & FWRITE)) + return EPERM; + + switch(cmd) { + case PCIOCGETCONF: + cio = (struct pci_conf_io *)data; + iolen = min(cio->pci_len, + pci_dev_list_count * sizeof(struct pci_conf)); + cio->pci_len = pci_dev_list_count * sizeof(struct pci_conf); + + error = copyout(pci_dev_list, cio->pci_buf, iolen); + break; + + case PCIOCREAD: + io = (struct pci_io *)data; + switch(io->pi_width) { + case 4: + tag = pcibus->pb_tag (io->pi_sel.pc_bus, + io->pi_sel.pc_dev, + io->pi_sel.pc_func); + io->pi_data = pci_conf_read(tag, io->pi_reg); + error = 0; + break; + case 2: + case 1: + default: + error = ENODEV; + break; + } + break; + + case PCIOCWRITE: + io = (struct pci_io *)data; + switch(io->pi_width) { + case 4: + tag = pcibus->pb_tag (io->pi_sel.pc_bus, + io->pi_sel.pc_dev, + io->pi_sel.pc_func); + pci_conf_write(tag, io->pi_reg, io->pi_data); + error = 0; + break; + case 2: + case 1: + default: + error = ENODEV; + break; + } + break; + + default: + error = ENOTTY; + break; + } + + return (error); +} + +#define PCI_CDEV 78 + +static struct cdevsw pcicdev = { + pci_open, pci_close, noread, nowrite, pci_ioctl, nostop, noreset, + nodevtotty, noselect, nommap, nostrategy, "pci", 0, PCI_CDEV +}; + +#ifdef DEVFS +static void *pci_devfs_token; +#endif + +static void +pci_cdevinit(void *dummy) +{ + dev_t dev; + + dev = makedev(PCI_CDEV, 0); + cdevsw_add(&dev, &pcicdev, NULL); +#ifdef DEVFS + pci_devfs_token = devfs_add_devswf(&pcicdev, 0, DV_CHR, + UID_ROOT, GID_WHEEL, 0644, "pci"); +#endif +} + +SYSINIT(pcidev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+PCI_CDEV, pci_cdevinit, NULL); + #endif /* NPCI */ diff --git a/sys/pci/pcireg.h b/sys/pci/pcireg.h index ac1003ce91d7..54b446b4235a 100644 --- a/sys/pci/pcireg.h +++ b/sys/pci/pcireg.h @@ -1,6 +1,6 @@ /************************************************************************** ** -** $Id: pcireg.h,v 1.6 1996/01/19 19:03:47 se Exp $ +** $Id: pcireg.h,v 1.7 1996/01/25 18:31:59 se Exp $ ** ** Names for PCI configuration space registers. ** @@ -160,6 +160,7 @@ #define PCI_PCI_BRIDGE_MEM_REG 0x20 #define PCI_PCI_BRIDGE_PMEM_REG 0x24 +#define PCI_SUBID_REG 0x2c #define PCI_SUBORDINATE_BUS_MASK 0x00ff0000 #define PCI_SECONDARY_BUS_MASK 0x0000ff00