Index: stable/10/sys/dev/puc/puc.c =================================================================== --- stable/10/sys/dev/puc/puc.c (revision 287925) +++ stable/10/sys/dev/puc/puc.c (revision 287926) @@ -1,766 +1,768 @@ /*- * Copyright (c) 2006 Marcel Moolenaar * 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, 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #define PUC_ISRCCNT 5 struct puc_port { struct puc_bar *p_bar; struct resource *p_rres; struct resource *p_ires; device_t p_dev; int p_nr; int p_type; int p_rclk; int p_hasintr:1; serdev_intr_t *p_ihsrc[PUC_ISRCCNT]; void *p_iharg; int p_ipend; }; devclass_t puc_devclass; const char puc_driver_name[] = "puc"; static MALLOC_DEFINE(M_PUC, "PUC", "PUC driver"); +SYSCTL_NODE(_hw, OID_AUTO, puc, CTLFLAG_RD, 0, "puc(9) driver configuration"); + struct puc_bar * puc_get_bar(struct puc_softc *sc, int rid) { struct puc_bar *bar; struct rman *rm; u_long end, start; int error, i; /* Find the BAR entry with the given RID. */ i = 0; while (i < PUC_PCI_BARS && sc->sc_bar[i].b_rid != rid) i++; if (i < PUC_PCI_BARS) return (&sc->sc_bar[i]); /* Not found. If we're looking for an unused entry, return NULL. */ if (rid == -1) return (NULL); /* Get an unused entry for us to fill. */ bar = puc_get_bar(sc, -1); if (bar == NULL) return (NULL); bar->b_rid = rid; bar->b_type = SYS_RES_IOPORT; bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type, &bar->b_rid, RF_ACTIVE); if (bar->b_res == NULL) { bar->b_rid = rid; bar->b_type = SYS_RES_MEMORY; bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type, &bar->b_rid, RF_ACTIVE); if (bar->b_res == NULL) { bar->b_rid = -1; return (NULL); } } /* Update our managed space. */ rm = (bar->b_type == SYS_RES_IOPORT) ? &sc->sc_ioport : &sc->sc_iomem; start = rman_get_start(bar->b_res); end = rman_get_end(bar->b_res); error = rman_manage_region(rm, start, end); if (error) { bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid, bar->b_res); bar->b_res = NULL; bar->b_rid = -1; bar = NULL; } return (bar); } static int puc_intr(void *arg) { struct puc_port *port; struct puc_softc *sc = arg; u_long ds, dev, devs; int i, idx, ipend, isrc, nints; uint8_t ilr; nints = 0; while (1) { /* * Obtain the set of devices with pending interrupts. */ devs = sc->sc_serdevs; if (sc->sc_ilr == PUC_ILR_DIGI) { idx = 0; while (devs & (0xfful << idx)) { ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7); devs &= ~0ul ^ ((u_long)ilr << idx); idx += 8; } } else if (sc->sc_ilr == PUC_ILR_QUATECH) { /* * Don't trust the value if it's the same as the option * register. It may mean that the ILR is not active and * we're reading the option register instead. This may * lead to false positives on 8-port boards. */ ilr = bus_read_1(sc->sc_port[0].p_rres, 7); if (ilr != (sc->sc_cfg_data & 0xff)) devs &= (u_long)ilr; } if (devs == 0UL) break; /* * Obtain the set of interrupt sources from those devices * that have pending interrupts. */ ipend = 0; idx = 0, dev = 1UL; ds = devs; while (ds != 0UL) { while ((ds & dev) == 0UL) idx++, dev <<= 1; ds &= ~dev; port = &sc->sc_port[idx]; port->p_ipend = SERDEV_IPEND(port->p_dev); ipend |= port->p_ipend; } if (ipend == 0) break; i = 0, isrc = SER_INT_OVERRUN; while (ipend) { while (i < PUC_ISRCCNT && !(ipend & isrc)) i++, isrc <<= 1; KASSERT(i < PUC_ISRCCNT, ("%s", __func__)); ipend &= ~isrc; idx = 0, dev = 1UL; ds = devs; while (ds != 0UL) { while ((ds & dev) == 0UL) idx++, dev <<= 1; ds &= ~dev; port = &sc->sc_port[idx]; if (!(port->p_ipend & isrc)) continue; if (port->p_ihsrc[i] != NULL) (*port->p_ihsrc[i])(port->p_iharg); nints++; } } } return ((nints > 0) ? FILTER_HANDLED : FILTER_STRAY); } int puc_bfe_attach(device_t dev) { char buffer[64]; struct puc_bar *bar; struct puc_port *port; struct puc_softc *sc; struct rman *rm; intptr_t res; bus_addr_t ofs, start; bus_size_t size; bus_space_handle_t bsh; bus_space_tag_t bst; int error, idx; sc = device_get_softc(dev); for (idx = 0; idx < PUC_PCI_BARS; idx++) sc->sc_bar[idx].b_rid = -1; do { sc->sc_ioport.rm_type = RMAN_ARRAY; error = rman_init(&sc->sc_ioport); if (!error) { sc->sc_iomem.rm_type = RMAN_ARRAY; error = rman_init(&sc->sc_iomem); if (!error) { sc->sc_irq.rm_type = RMAN_ARRAY; error = rman_init(&sc->sc_irq); if (!error) break; rman_fini(&sc->sc_iomem); } rman_fini(&sc->sc_ioport); } return (error); } while (0); snprintf(buffer, sizeof(buffer), "%s I/O port mapping", device_get_nameunit(dev)); sc->sc_ioport.rm_descr = strdup(buffer, M_PUC); snprintf(buffer, sizeof(buffer), "%s I/O memory mapping", device_get_nameunit(dev)); sc->sc_iomem.rm_descr = strdup(buffer, M_PUC); snprintf(buffer, sizeof(buffer), "%s port numbers", device_get_nameunit(dev)); sc->sc_irq.rm_descr = strdup(buffer, M_PUC); error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res); KASSERT(error == 0, ("%s %d", __func__, __LINE__)); sc->sc_nports = (int)res; sc->sc_port = malloc(sc->sc_nports * sizeof(struct puc_port), M_PUC, M_WAITOK|M_ZERO); error = rman_manage_region(&sc->sc_irq, 1, sc->sc_nports); if (error) goto fail; error = puc_config(sc, PUC_CFG_SETUP, 0, &res); if (error) goto fail; for (idx = 0; idx < sc->sc_nports; idx++) { port = &sc->sc_port[idx]; port->p_nr = idx + 1; error = puc_config(sc, PUC_CFG_GET_TYPE, idx, &res); if (error) goto fail; port->p_type = res; error = puc_config(sc, PUC_CFG_GET_RID, idx, &res); if (error) goto fail; bar = puc_get_bar(sc, res); if (bar == NULL) { error = ENXIO; goto fail; } port->p_bar = bar; start = rman_get_start(bar->b_res); error = puc_config(sc, PUC_CFG_GET_OFS, idx, &res); if (error) goto fail; ofs = res; error = puc_config(sc, PUC_CFG_GET_LEN, idx, &res); if (error) goto fail; size = res; rm = (bar->b_type == SYS_RES_IOPORT) ? &sc->sc_ioport: &sc->sc_iomem; port->p_rres = rman_reserve_resource(rm, start + ofs, start + ofs + size - 1, size, 0, NULL); if (port->p_rres != NULL) { bsh = rman_get_bushandle(bar->b_res); bst = rman_get_bustag(bar->b_res); bus_space_subregion(bst, bsh, ofs, size, &bsh); rman_set_bushandle(port->p_rres, bsh); rman_set_bustag(port->p_rres, bst); } port->p_ires = rman_reserve_resource(&sc->sc_irq, port->p_nr, port->p_nr, 1, 0, NULL); if (port->p_ires == NULL) { error = ENXIO; goto fail; } error = puc_config(sc, PUC_CFG_GET_CLOCK, idx, &res); if (error) goto fail; port->p_rclk = res; port->p_dev = device_add_child(dev, NULL, -1); if (port->p_dev != NULL) device_set_ivars(port->p_dev, (void *)port); } error = puc_config(sc, PUC_CFG_GET_ILR, 0, &res); if (error) goto fail; sc->sc_ilr = res; if (bootverbose && sc->sc_ilr != 0) device_printf(dev, "using interrupt latch register\n"); - sc->sc_irid = 0; sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid, RF_ACTIVE|RF_SHAREABLE); if (sc->sc_ires != NULL) { error = bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_TTY, puc_intr, NULL, sc, &sc->sc_icookie); if (error) error = bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_TTY | INTR_MPSAFE, NULL, (driver_intr_t *)puc_intr, sc, &sc->sc_icookie); else sc->sc_fastintr = 1; if (error) { device_printf(dev, "could not activate interrupt\n"); bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires); sc->sc_ires = NULL; } } if (sc->sc_ires == NULL) { /* XXX no interrupt resource. Force polled mode. */ sc->sc_polled = 1; } /* Probe and attach our children. */ for (idx = 0; idx < sc->sc_nports; idx++) { port = &sc->sc_port[idx]; if (port->p_dev == NULL) continue; error = device_probe_and_attach(port->p_dev); if (error) { device_delete_child(dev, port->p_dev); port->p_dev = NULL; } } /* * If there are no serdev devices, then our interrupt handler * will do nothing. Tear it down. */ if (sc->sc_serdevs == 0UL) bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie); return (0); fail: for (idx = 0; idx < sc->sc_nports; idx++) { port = &sc->sc_port[idx]; if (port->p_dev != NULL) device_delete_child(dev, port->p_dev); if (port->p_rres != NULL) rman_release_resource(port->p_rres); if (port->p_ires != NULL) rman_release_resource(port->p_ires); } for (idx = 0; idx < PUC_PCI_BARS; idx++) { bar = &sc->sc_bar[idx]; if (bar->b_res != NULL) bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid, bar->b_res); } rman_fini(&sc->sc_irq); free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC); rman_fini(&sc->sc_iomem); free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC); rman_fini(&sc->sc_ioport); free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC); free(sc->sc_port, M_PUC); return (error); } int puc_bfe_detach(device_t dev) { struct puc_bar *bar; struct puc_port *port; struct puc_softc *sc; int error, idx; sc = device_get_softc(dev); /* Detach our children. */ error = 0; for (idx = 0; idx < sc->sc_nports; idx++) { port = &sc->sc_port[idx]; if (port->p_dev == NULL) continue; if (device_detach(port->p_dev) == 0) { device_delete_child(dev, port->p_dev); if (port->p_rres != NULL) rman_release_resource(port->p_rres); if (port->p_ires != NULL) rman_release_resource(port->p_ires); } else error = ENXIO; } if (error) return (error); if (sc->sc_serdevs != 0UL) bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie); bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires); for (idx = 0; idx < PUC_PCI_BARS; idx++) { bar = &sc->sc_bar[idx]; if (bar->b_res != NULL) bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid, bar->b_res); } rman_fini(&sc->sc_irq); free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC); rman_fini(&sc->sc_iomem); free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC); rman_fini(&sc->sc_ioport); free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC); free(sc->sc_port, M_PUC); return (0); } int puc_bfe_probe(device_t dev, const struct puc_cfg *cfg) { struct puc_softc *sc; intptr_t res; int error; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_cfg = cfg; /* We don't attach to single-port serial cards. */ if (cfg->ports == PUC_PORT_1S || cfg->ports == PUC_PORT_1P) return (EDOOFUS); error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res); if (error) return (error); error = puc_config(sc, PUC_CFG_GET_DESC, 0, &res); if (error) return (error); if (res != 0) device_set_desc(dev, (const char *)res); return (BUS_PROBE_DEFAULT); } struct resource * puc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct puc_port *port; struct resource *res; device_t assigned, originator; int error; /* Get our immediate child. */ originator = child; while (child != NULL && device_get_parent(child) != dev) child = device_get_parent(child); if (child == NULL) return (NULL); port = device_get_ivars(child); KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); if (rid == NULL || *rid != 0) return (NULL); /* We only support default allocations. */ if (start != 0UL || end != ~0UL) return (NULL); if (type == port->p_bar->b_type) res = port->p_rres; else if (type == SYS_RES_IRQ) res = port->p_ires; else return (NULL); if (res == NULL) return (NULL); assigned = rman_get_device(res); if (assigned == NULL) /* Not allocated */ rman_set_device(res, originator); else if (assigned != originator) return (NULL); if (flags & RF_ACTIVE) { error = rman_activate_resource(res); if (error) { if (assigned == NULL) rman_set_device(res, NULL); return (NULL); } } return (res); } int puc_bus_release_resource(device_t dev, device_t child, int type, int rid, struct resource *res) { struct puc_port *port; device_t originator; /* Get our immediate child. */ originator = child; while (child != NULL && device_get_parent(child) != dev) child = device_get_parent(child); if (child == NULL) return (EINVAL); port = device_get_ivars(child); KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); if (rid != 0 || res == NULL) return (EINVAL); if (type == port->p_bar->b_type) { if (res != port->p_rres) return (EINVAL); } else if (type == SYS_RES_IRQ) { if (res != port->p_ires) return (EINVAL); if (port->p_hasintr) return (EBUSY); } else return (EINVAL); if (rman_get_device(res) != originator) return (ENXIO); if (rman_get_flags(res) & RF_ACTIVE) rman_deactivate_resource(res); rman_set_device(res, NULL); return (0); } int puc_bus_get_resource(device_t dev, device_t child, int type, int rid, u_long *startp, u_long *countp) { struct puc_port *port; struct resource *res; u_long start; /* Get our immediate child. */ while (child != NULL && device_get_parent(child) != dev) child = device_get_parent(child); if (child == NULL) return (EINVAL); port = device_get_ivars(child); KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); if (type == port->p_bar->b_type) res = port->p_rres; else if (type == SYS_RES_IRQ) res = port->p_ires; else return (ENXIO); if (rid != 0 || res == NULL) return (ENXIO); start = rman_get_start(res); if (startp != NULL) *startp = start; if (countp != NULL) *countp = rman_get_end(res) - start + 1; return (0); } int puc_bus_setup_intr(device_t dev, device_t child, struct resource *res, int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep) { struct puc_port *port; struct puc_softc *sc; device_t originator; int i, isrc, serdev; sc = device_get_softc(dev); /* Get our immediate child. */ originator = child; while (child != NULL && device_get_parent(child) != dev) child = device_get_parent(child); if (child == NULL) return (EINVAL); port = device_get_ivars(child); KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); if (cookiep == NULL || res != port->p_ires) return (EINVAL); /* We demand that serdev devices use filter_only interrupts. */ if (port->p_type == PUC_TYPE_SERIAL && ihand != NULL) return (ENXIO); if (rman_get_device(port->p_ires) != originator) return (ENXIO); /* * Have non-serdev ports handled by the bus implementation. It * supports multiple handlers for a single interrupt as it is, * so we wouldn't add value if we did it ourselves. */ serdev = 0; if (port->p_type == PUC_TYPE_SERIAL) { i = 0, isrc = SER_INT_OVERRUN; while (i < PUC_ISRCCNT) { port->p_ihsrc[i] = SERDEV_IHAND(originator, isrc); if (port->p_ihsrc[i] != NULL) serdev = 1; i++, isrc <<= 1; } } if (!serdev) return (BUS_SETUP_INTR(device_get_parent(dev), originator, sc->sc_ires, flags, filt, ihand, arg, cookiep)); sc->sc_serdevs |= 1UL << (port->p_nr - 1); port->p_hasintr = 1; port->p_iharg = arg; *cookiep = port; return (0); } int puc_bus_teardown_intr(device_t dev, device_t child, struct resource *res, void *cookie) { struct puc_port *port; struct puc_softc *sc; device_t originator; int i; sc = device_get_softc(dev); /* Get our immediate child. */ originator = child; while (child != NULL && device_get_parent(child) != dev) child = device_get_parent(child); if (child == NULL) return (EINVAL); port = device_get_ivars(child); KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); if (res != port->p_ires) return (EINVAL); if (rman_get_device(port->p_ires) != originator) return (ENXIO); if (!port->p_hasintr) return (BUS_TEARDOWN_INTR(device_get_parent(dev), originator, sc->sc_ires, cookie)); if (cookie != port) return (EINVAL); port->p_hasintr = 0; port->p_iharg = NULL; for (i = 0; i < PUC_ISRCCNT; i++) port->p_ihsrc[i] = NULL; return (0); } int puc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) { struct puc_port *port; /* Get our immediate child. */ while (child != NULL && device_get_parent(child) != dev) child = device_get_parent(child); if (child == NULL) return (EINVAL); port = device_get_ivars(child); KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); if (result == NULL) return (EINVAL); switch(index) { case PUC_IVAR_CLOCK: *result = port->p_rclk; break; case PUC_IVAR_TYPE: *result = port->p_type; break; default: return (ENOENT); } return (0); } int puc_bus_print_child(device_t dev, device_t child) { struct puc_port *port; int retval; port = device_get_ivars(child); retval = 0; retval += bus_print_child_header(dev, child); retval += printf(" at port %d", port->p_nr); retval += bus_print_child_footer(dev, child); return (retval); } int puc_bus_child_location_str(device_t dev, device_t child, char *buf, size_t buflen) { struct puc_port *port; port = device_get_ivars(child); snprintf(buf, buflen, "port=%d", port->p_nr); return (0); } int puc_bus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen) { struct puc_port *port; port = device_get_ivars(child); snprintf(buf, buflen, "type=%d", port->p_type); return (0); } Index: stable/10/sys/dev/puc/puc_bfe.h =================================================================== --- stable/10/sys/dev/puc/puc_bfe.h (revision 287925) +++ stable/10/sys/dev/puc/puc_bfe.h (revision 287926) @@ -1,97 +1,100 @@ /*- * Copyright (c) 2006 Marcel Moolenaar * 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, 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$ */ #ifndef _DEV_PUC_BFE_H_ #define _DEV_PUC_BFE_H_ #define PUC_PCI_BARS 6 struct puc_cfg; struct puc_port; extern const struct puc_cfg puc_pci_devices[]; extern devclass_t puc_devclass; extern const char puc_driver_name[]; struct puc_bar { struct resource *b_res; int b_rid; int b_type; }; struct puc_softc { device_t sc_dev; const struct puc_cfg *sc_cfg; intptr_t sc_cfg_data; struct puc_bar sc_bar[PUC_PCI_BARS]; struct rman sc_ioport; struct rman sc_iomem; struct rman sc_irq; struct resource *sc_ires; void *sc_icookie; int sc_irid; int sc_nports; struct puc_port *sc_port; int sc_fastintr:1; int sc_leaving:1; int sc_polled:1; + int sc_msi:1; int sc_ilr; /* * Bitmask of ports that use the serdev I/F. This allows for * 32 ports on ILP32 machines and 64 ports on LP64 machines. */ u_long sc_serdevs; }; struct puc_bar *puc_get_bar(struct puc_softc *sc, int rid); int puc_bfe_attach(device_t); int puc_bfe_detach(device_t); int puc_bfe_probe(device_t, const struct puc_cfg *); int puc_bus_child_location_str(device_t, device_t, char *, size_t); int puc_bus_child_pnpinfo_str(device_t, device_t, char *, size_t); struct resource *puc_bus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); int puc_bus_get_resource(device_t, device_t, int, int, u_long *, u_long *); int puc_bus_print_child(device_t, device_t); int puc_bus_read_ivar(device_t, device_t, int, uintptr_t *); int puc_bus_release_resource(device_t, device_t, int, int, struct resource *); int puc_bus_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); int puc_bus_teardown_intr(device_t, device_t, struct resource *, void *); + +SYSCTL_DECL(_hw_puc); #endif /* _DEV_PUC_BFE_H_ */ Index: stable/10/sys/dev/puc/puc_cfg.c =================================================================== --- stable/10/sys/dev/puc/puc_cfg.c (revision 287925) +++ stable/10/sys/dev/puc/puc_cfg.c (revision 287926) @@ -1,175 +1,176 @@ /*- * Copyright (c) 2006 Marcel Moolenaar * 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, 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include +#include #include #include #include int puc_config(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *r) { const struct puc_cfg *cfg = sc->sc_cfg; int error; if (cfg->config_function != NULL) { error = cfg->config_function(sc, cmd, port, r); if (!error) return (0); } else error = EDOOFUS; switch (cmd) { case PUC_CFG_GET_CLOCK: if (cfg->clock < 0) return (error); *r = cfg->clock; return (0); case PUC_CFG_GET_DESC: if (cfg->desc == NULL) return (error); *r = (intptr_t)cfg->desc; return (0); case PUC_CFG_GET_ILR: *r = PUC_ILR_NONE; return (0); case PUC_CFG_GET_LEN: /* The length of bus space needed by the port. */ *r = 8; return (0); case PUC_CFG_GET_NPORTS: /* The number of ports on this card. */ switch (cfg->ports) { case PUC_PORT_NONSTANDARD: return (error); case PUC_PORT_1P: case PUC_PORT_1S: *r = 1; return (0); case PUC_PORT_1S1P: case PUC_PORT_2P: case PUC_PORT_2S: *r = 2; return (0); case PUC_PORT_1S2P: case PUC_PORT_2S1P: case PUC_PORT_3S: *r = 3; return (0); case PUC_PORT_4S: *r = 4; return (0); case PUC_PORT_4S1P: *r = 5; return (0); case PUC_PORT_6S: *r = 6; return (0); case PUC_PORT_8S: *r = 8; return (0); case PUC_PORT_12S: *r = 12; return (0); case PUC_PORT_16S: *r = 16; return (0); } break; case PUC_CFG_GET_OFS: /* The offset relative to the RID. */ if (cfg->d_ofs < 0) return (error); *r = port * cfg->d_ofs; return (0); case PUC_CFG_GET_RID: /* The RID for this port. */ if (port == 0) { if (cfg->rid < 0) return (error); *r = cfg->rid; return (0); } if (cfg->d_rid < 0) return (error); if (cfg->rid < 0) { error = puc_config(sc, PUC_CFG_GET_RID, 0, r); if (error) return (error); } else *r = cfg->rid; *r += port * cfg->d_rid; return (0); case PUC_CFG_GET_TYPE: /* The type of this port. */ if (cfg->ports == PUC_PORT_NONSTANDARD) return (error); switch (port) { case 0: if (cfg->ports == PUC_PORT_1P || cfg->ports == PUC_PORT_2P) *r = PUC_TYPE_PARALLEL; else *r = PUC_TYPE_SERIAL; return (0); case 1: if (cfg->ports == PUC_PORT_1S1P || cfg->ports == PUC_PORT_1S2P || cfg->ports == PUC_PORT_2P) *r = PUC_TYPE_PARALLEL; else *r = PUC_TYPE_SERIAL; return (0); case 2: if (cfg->ports == PUC_PORT_1S2P || cfg->ports == PUC_PORT_2S1P) *r = PUC_TYPE_PARALLEL; else *r = PUC_TYPE_SERIAL; return (0); case 4: if (cfg->ports == PUC_PORT_4S1P) *r = PUC_TYPE_PARALLEL; else *r = PUC_TYPE_SERIAL; return (0); } *r = PUC_TYPE_SERIAL; return (0); case PUC_CFG_SETUP: *r = ENXIO; return (0); } return (ENXIO); } Index: stable/10/sys/dev/puc/puc_pccard.c =================================================================== --- stable/10/sys/dev/puc/puc_pccard.c (revision 287925) +++ stable/10/sys/dev/puc/puc_pccard.c (revision 287926) @@ -1,98 +1,99 @@ /*- * Copyright (c) 2002 Poul-Henning Kamp. 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. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include +#include #include #include #include #include #include #include /* http://www.argosy.com.tw/product/sp320.htm */ const struct puc_cfg puc_pccard_rscom = { 0, 0, 0, 0, "ARGOSY SP320 Dual port serial PCMCIA", DEFAULT_RCLK, PUC_PORT_2S, 0, 1, 0, }; static int puc_pccard_probe(device_t dev) { const char *vendor, *product; int error; error = pccard_get_vendor_str(dev, &vendor); if (error) return(error); error = pccard_get_product_str(dev, &product); if (error) return(error); if (!strcmp(vendor, "PCMCIA") && !strcmp(product, "RS-COM 2P")) return (puc_bfe_probe(dev, &puc_pccard_rscom)); return (ENXIO); } static device_method_t puc_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, puc_pccard_probe), DEVMETHOD(device_attach, puc_bfe_attach), DEVMETHOD(device_detach, puc_bfe_detach), DEVMETHOD(bus_alloc_resource, puc_bus_alloc_resource), DEVMETHOD(bus_release_resource, puc_bus_release_resource), DEVMETHOD(bus_get_resource, puc_bus_get_resource), DEVMETHOD(bus_read_ivar, puc_bus_read_ivar), DEVMETHOD(bus_setup_intr, puc_bus_setup_intr), DEVMETHOD(bus_teardown_intr, puc_bus_teardown_intr), DEVMETHOD(bus_print_child, puc_bus_print_child), DEVMETHOD(bus_child_pnpinfo_str, puc_bus_child_pnpinfo_str), DEVMETHOD(bus_child_location_str, puc_bus_child_location_str), DEVMETHOD_END }; static driver_t puc_pccard_driver = { puc_driver_name, puc_pccard_methods, sizeof(struct puc_softc), }; DRIVER_MODULE(puc, pccard, puc_pccard_driver, puc_devclass, 0, 0); Index: stable/10/sys/dev/puc/puc_pci.c =================================================================== --- stable/10/sys/dev/puc/puc_pci.c (revision 287925) +++ stable/10/sys/dev/puc/puc_pci.c (revision 287926) @@ -1,148 +1,199 @@ /* $NetBSD: puc.c,v 1.7 2000/07/29 17:43:38 jlam Exp $ */ /*- * Copyright (c) 2002 JF Hay. All rights reserved. * Copyright (c) 2000 M. Warner Losh. 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. */ /*- * Copyright (c) 1996, 1998, 1999 * Christopher G. Demetriou. 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, 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Christopher G. Demetriou * for the NetBSD Project. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include +static int puc_msi_disable; +TUNABLE_INT("hw.puc.msi_disable", &puc_msi_disable); +SYSCTL_INT(_hw_puc, OID_AUTO, msi_disable, CTLFLAG_RD | CTLFLAG_TUN, + &puc_msi_disable, 0, "Disable use of MSI interrupts by puc(9)"); + static const struct puc_cfg * puc_pci_match(device_t dev, const struct puc_cfg *desc) { uint16_t vendor, device; uint16_t subvendor, subdevice; vendor = pci_get_vendor(dev); device = pci_get_device(dev); subvendor = pci_get_subvendor(dev); subdevice = pci_get_subdevice(dev); while (desc->vendor != 0xffff) { if (desc->vendor == vendor && desc->device == device) { /* exact match */ if (desc->subvendor == subvendor && desc->subdevice == subdevice) return (desc); /* wildcard match */ if (desc->subvendor == 0xffff) return (desc); } desc++; } /* no match */ return (NULL); } static int puc_pci_probe(device_t dev) { const struct puc_cfg *desc; if ((pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) != 0) return (ENXIO); desc = puc_pci_match(dev, puc_pci_devices); if (desc == NULL) return (ENXIO); return (puc_bfe_probe(dev, desc)); } +static int +puc_pci_attach(device_t dev) +{ + struct puc_softc *sc; + int error, count; + + sc = device_get_softc(dev); + + if (!puc_msi_disable) { + count = 1; + + if (pci_alloc_msi(dev, &count) == 0) { + sc->sc_msi = 1; + sc->sc_irid = 1; + } + } + + error = puc_bfe_attach(dev); + + if (error != 0 && sc->sc_msi) + pci_release_msi(dev); + + return (error); +} + +static int +puc_pci_detach(device_t dev) +{ + struct puc_softc *sc; + int error; + + sc = device_get_softc(dev); + + error = puc_bfe_detach(dev); + + if (error != 0) + return (error); + + if (sc->sc_msi) + error = pci_release_msi(dev); + + return (error); +} + + static device_method_t puc_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, puc_pci_probe), - DEVMETHOD(device_attach, puc_bfe_attach), - DEVMETHOD(device_detach, puc_bfe_detach), + DEVMETHOD(device_attach, puc_pci_attach), + DEVMETHOD(device_detach, puc_pci_detach), DEVMETHOD(bus_alloc_resource, puc_bus_alloc_resource), DEVMETHOD(bus_release_resource, puc_bus_release_resource), DEVMETHOD(bus_get_resource, puc_bus_get_resource), DEVMETHOD(bus_read_ivar, puc_bus_read_ivar), DEVMETHOD(bus_setup_intr, puc_bus_setup_intr), DEVMETHOD(bus_teardown_intr, puc_bus_teardown_intr), DEVMETHOD(bus_print_child, puc_bus_print_child), DEVMETHOD(bus_child_pnpinfo_str, puc_bus_child_pnpinfo_str), DEVMETHOD(bus_child_location_str, puc_bus_child_location_str), DEVMETHOD_END }; static driver_t puc_pci_driver = { puc_driver_name, puc_pci_methods, sizeof(struct puc_softc), }; DRIVER_MODULE(puc, pci, puc_pci_driver, puc_devclass, 0, 0); Index: stable/10/sys/dev/puc/pucdata.c =================================================================== --- stable/10/sys/dev/puc/pucdata.c (revision 287925) +++ stable/10/sys/dev/puc/pucdata.c (revision 287926) @@ -1,1703 +1,1704 @@ /*- * Copyright (c) 2006 Marcel Moolenaar * 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, 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. */ #include __FBSDID("$FreeBSD$"); /* * PCI "universal" communications card driver configuration data (used to * match/attach the cards). */ #include #include #include #include +#include #include #include #include #include #include #include #include static puc_config_f puc_config_amc; static puc_config_f puc_config_diva; static puc_config_f puc_config_exar; static puc_config_f puc_config_exar_pcie; static puc_config_f puc_config_icbook; static puc_config_f puc_config_moxa; static puc_config_f puc_config_oxford_pci954; static puc_config_f puc_config_oxford_pcie; static puc_config_f puc_config_quatech; static puc_config_f puc_config_syba; static puc_config_f puc_config_siig; static puc_config_f puc_config_sunix; static puc_config_f puc_config_timedia; static puc_config_f puc_config_titan; const struct puc_cfg puc_pci_devices[] = { { 0x0009, 0x7168, 0xffff, 0, "Sunix SUN1889", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x10, 0, 8, }, { 0x103c, 0x1048, 0x103c, 0x1049, "HP Diva Serial [GSP] Multiport UART - Tosca Console", DEFAULT_RCLK, PUC_PORT_3S, 0x10, 0, -1, .config_function = puc_config_diva }, { 0x103c, 0x1048, 0x103c, 0x104a, "HP Diva Serial [GSP] Multiport UART - Tosca Secondary", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 0, -1, .config_function = puc_config_diva }, { 0x103c, 0x1048, 0x103c, 0x104b, "HP Diva Serial [GSP] Multiport UART - Maestro SP2", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 0, -1, .config_function = puc_config_diva }, { 0x103c, 0x1048, 0x103c, 0x1223, "HP Diva Serial [GSP] Multiport UART - Superdome Console", DEFAULT_RCLK, PUC_PORT_3S, 0x10, 0, -1, .config_function = puc_config_diva }, { 0x103c, 0x1048, 0x103c, 0x1226, "HP Diva Serial [GSP] Multiport UART - Keystone SP2", DEFAULT_RCLK, PUC_PORT_3S, 0x10, 0, -1, .config_function = puc_config_diva }, { 0x103c, 0x1048, 0x103c, 0x1282, "HP Diva Serial [GSP] Multiport UART - Everest SP2", DEFAULT_RCLK, PUC_PORT_3S, 0x10, 0, -1, .config_function = puc_config_diva }, { 0x10b5, 0x1076, 0x10b5, 0x1076, "VScom PCI-800", DEFAULT_RCLK * 8, PUC_PORT_8S, 0x18, 0, 8, }, { 0x10b5, 0x1077, 0x10b5, 0x1077, "VScom PCI-400", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x18, 0, 8, }, { 0x10b5, 0x1103, 0x10b5, 0x1103, "VScom PCI-200", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x18, 4, 0, }, /* * Boca Research Turbo Serial 658 (8 serial port) card. * Appears to be the same as Chase Research PLC PCI-FAST8 * and Perle PCI-FAST8 Multi-Port serial cards. */ { 0x10b5, 0x9050, 0x12e0, 0x0021, "Boca Research Turbo Serial 658", DEFAULT_RCLK * 4, PUC_PORT_8S, 0x18, 0, 8, }, { 0x10b5, 0x9050, 0x12e0, 0x0031, "Boca Research Turbo Serial 654", DEFAULT_RCLK * 4, PUC_PORT_4S, 0x18, 0, 8, }, /* * Dolphin Peripherals 4035 (dual serial port) card. PLX 9050, with * a seemingly-lame EEPROM setup that puts the Dolphin IDs * into the subsystem fields, and claims that it's a * network/misc (0x02/0x80) device. */ { 0x10b5, 0x9050, 0xd84d, 0x6808, "Dolphin Peripherals 4035", DEFAULT_RCLK, PUC_PORT_2S, 0x18, 4, 0, }, /* * Dolphin Peripherals 4014 (dual parallel port) card. PLX 9050, with * a seemingly-lame EEPROM setup that puts the Dolphin IDs * into the subsystem fields, and claims that it's a * network/misc (0x02/0x80) device. */ { 0x10b5, 0x9050, 0xd84d, 0x6810, "Dolphin Peripherals 4014", 0, PUC_PORT_2P, 0x20, 4, 0, }, { 0x10e8, 0x818e, 0xffff, 0, "Applied Micro Circuits 8 Port UART", DEFAULT_RCLK, PUC_PORT_8S, 0x14, -1, -1, .config_function = puc_config_amc }, { 0x11fe, 0x8010, 0xffff, 0, "Comtrol RocketPort 550/8 RJ11 part A", DEFAULT_RCLK * 4, PUC_PORT_4S, 0x10, 0, 8, }, { 0x11fe, 0x8011, 0xffff, 0, "Comtrol RocketPort 550/8 RJ11 part B", DEFAULT_RCLK * 4, PUC_PORT_4S, 0x10, 0, 8, }, { 0x11fe, 0x8012, 0xffff, 0, "Comtrol RocketPort 550/8 Octa part A", DEFAULT_RCLK * 4, PUC_PORT_4S, 0x10, 0, 8, }, { 0x11fe, 0x8013, 0xffff, 0, "Comtrol RocketPort 550/8 Octa part B", DEFAULT_RCLK * 4, PUC_PORT_4S, 0x10, 0, 8, }, { 0x11fe, 0x8014, 0xffff, 0, "Comtrol RocketPort 550/4 RJ45", DEFAULT_RCLK * 4, PUC_PORT_4S, 0x10, 0, 8, }, { 0x11fe, 0x8015, 0xffff, 0, "Comtrol RocketPort 550/Quad", DEFAULT_RCLK * 4, PUC_PORT_4S, 0x10, 0, 8, }, { 0x11fe, 0x8016, 0xffff, 0, "Comtrol RocketPort 550/16 part A", DEFAULT_RCLK * 4, PUC_PORT_4S, 0x10, 0, 8, }, { 0x11fe, 0x8017, 0xffff, 0, "Comtrol RocketPort 550/16 part B", DEFAULT_RCLK * 4, PUC_PORT_12S, 0x10, 0, 8, }, { 0x11fe, 0x8018, 0xffff, 0, "Comtrol RocketPort 550/8 part A", DEFAULT_RCLK * 4, PUC_PORT_4S, 0x10, 0, 8, }, { 0x11fe, 0x8019, 0xffff, 0, "Comtrol RocketPort 550/8 part B", DEFAULT_RCLK * 4, PUC_PORT_4S, 0x10, 0, 8, }, /* * IBM SurePOS 300 Series (481033H) serial ports * Details can be found on the IBM RSS websites */ { 0x1014, 0x0297, 0xffff, 0, "IBM SurePOS 300 Series (481033H) serial ports", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 4, 0 }, /* * SIIG Boards. * * SIIG provides documentation for their boards at: * */ { 0x131f, 0x1010, 0xffff, 0, "SIIG Cyber I/O PCI 16C550 (10x family)", DEFAULT_RCLK, PUC_PORT_1S1P, 0x18, 4, 0, }, { 0x131f, 0x1011, 0xffff, 0, "SIIG Cyber I/O PCI 16C650 (10x family)", DEFAULT_RCLK, PUC_PORT_1S1P, 0x18, 4, 0, }, { 0x131f, 0x1012, 0xffff, 0, "SIIG Cyber I/O PCI 16C850 (10x family)", DEFAULT_RCLK, PUC_PORT_1S1P, 0x18, 4, 0, }, { 0x131f, 0x1021, 0xffff, 0, "SIIG Cyber Parallel Dual PCI (10x family)", 0, PUC_PORT_2P, 0x18, 8, 0, }, { 0x131f, 0x1030, 0xffff, 0, "SIIG Cyber Serial Dual PCI 16C550 (10x family)", DEFAULT_RCLK, PUC_PORT_2S, 0x18, 4, 0, }, { 0x131f, 0x1031, 0xffff, 0, "SIIG Cyber Serial Dual PCI 16C650 (10x family)", DEFAULT_RCLK, PUC_PORT_2S, 0x18, 4, 0, }, { 0x131f, 0x1032, 0xffff, 0, "SIIG Cyber Serial Dual PCI 16C850 (10x family)", DEFAULT_RCLK, PUC_PORT_2S, 0x18, 4, 0, }, { 0x131f, 0x1034, 0xffff, 0, /* XXX really? */ "SIIG Cyber 2S1P PCI 16C550 (10x family)", DEFAULT_RCLK, PUC_PORT_2S1P, 0x18, 4, 0, }, { 0x131f, 0x1035, 0xffff, 0, /* XXX really? */ "SIIG Cyber 2S1P PCI 16C650 (10x family)", DEFAULT_RCLK, PUC_PORT_2S1P, 0x18, 4, 0, }, { 0x131f, 0x1036, 0xffff, 0, /* XXX really? */ "SIIG Cyber 2S1P PCI 16C850 (10x family)", DEFAULT_RCLK, PUC_PORT_2S1P, 0x18, 4, 0, }, { 0x131f, 0x1050, 0xffff, 0, "SIIG Cyber 4S PCI 16C550 (10x family)", DEFAULT_RCLK, PUC_PORT_4S, 0x18, 4, 0, }, { 0x131f, 0x1051, 0xffff, 0, "SIIG Cyber 4S PCI 16C650 (10x family)", DEFAULT_RCLK, PUC_PORT_4S, 0x18, 4, 0, }, { 0x131f, 0x1052, 0xffff, 0, "SIIG Cyber 4S PCI 16C850 (10x family)", DEFAULT_RCLK, PUC_PORT_4S, 0x18, 4, 0, }, { 0x131f, 0x2010, 0xffff, 0, "SIIG Cyber I/O PCI 16C550 (20x family)", DEFAULT_RCLK, PUC_PORT_1S1P, 0x10, 4, 0, }, { 0x131f, 0x2011, 0xffff, 0, "SIIG Cyber I/O PCI 16C650 (20x family)", DEFAULT_RCLK, PUC_PORT_1S1P, 0x10, 4, 0, }, { 0x131f, 0x2012, 0xffff, 0, "SIIG Cyber I/O PCI 16C850 (20x family)", DEFAULT_RCLK, PUC_PORT_1S1P, 0x10, 4, 0, }, { 0x131f, 0x2021, 0xffff, 0, "SIIG Cyber Parallel Dual PCI (20x family)", 0, PUC_PORT_2P, 0x10, 8, 0, }, { 0x131f, 0x2030, 0xffff, 0, "SIIG Cyber Serial Dual PCI 16C550 (20x family)", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x131f, 0x2031, 0xffff, 0, "SIIG Cyber Serial Dual PCI 16C650 (20x family)", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x131f, 0x2032, 0xffff, 0, "SIIG Cyber Serial Dual PCI 16C850 (20x family)", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x131f, 0x2040, 0xffff, 0, "SIIG Cyber 2P1S PCI 16C550 (20x family)", DEFAULT_RCLK, PUC_PORT_1S2P, 0x10, -1, 0, .config_function = puc_config_siig }, { 0x131f, 0x2041, 0xffff, 0, "SIIG Cyber 2P1S PCI 16C650 (20x family)", DEFAULT_RCLK, PUC_PORT_1S2P, 0x10, -1, 0, .config_function = puc_config_siig }, { 0x131f, 0x2042, 0xffff, 0, "SIIG Cyber 2P1S PCI 16C850 (20x family)", DEFAULT_RCLK, PUC_PORT_1S2P, 0x10, -1, 0, .config_function = puc_config_siig }, { 0x131f, 0x2050, 0xffff, 0, "SIIG Cyber 4S PCI 16C550 (20x family)", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 4, 0, }, { 0x131f, 0x2051, 0xffff, 0, "SIIG Cyber 4S PCI 16C650 (20x family)", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 4, 0, }, { 0x131f, 0x2052, 0xffff, 0, "SIIG Cyber 4S PCI 16C850 (20x family)", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 4, 0, }, { 0x131f, 0x2060, 0xffff, 0, "SIIG Cyber 2S1P PCI 16C550 (20x family)", DEFAULT_RCLK, PUC_PORT_2S1P, 0x10, 4, 0, }, { 0x131f, 0x2061, 0xffff, 0, "SIIG Cyber 2S1P PCI 16C650 (20x family)", DEFAULT_RCLK, PUC_PORT_2S1P, 0x10, 4, 0, }, { 0x131f, 0x2062, 0xffff, 0, "SIIG Cyber 2S1P PCI 16C850 (20x family)", DEFAULT_RCLK, PUC_PORT_2S1P, 0x10, 4, 0, }, { 0x131f, 0x2081, 0xffff, 0, "SIIG PS8000 8S PCI 16C650 (20x family)", DEFAULT_RCLK, PUC_PORT_8S, 0x10, -1, -1, .config_function = puc_config_siig }, { 0x135c, 0x0010, 0xffff, 0, "Quatech QSC-100", -3, /* max 8x clock rate */ PUC_PORT_4S, 0x14, 0, 8, .config_function = puc_config_quatech }, { 0x135c, 0x0020, 0xffff, 0, "Quatech DSC-100", -1, /* max 2x clock rate */ PUC_PORT_2S, 0x14, 0, 8, .config_function = puc_config_quatech }, { 0x135c, 0x0030, 0xffff, 0, "Quatech DSC-200/300", -1, /* max 2x clock rate */ PUC_PORT_2S, 0x14, 0, 8, .config_function = puc_config_quatech }, { 0x135c, 0x0040, 0xffff, 0, "Quatech QSC-200/300", -3, /* max 8x clock rate */ PUC_PORT_4S, 0x14, 0, 8, .config_function = puc_config_quatech }, { 0x135c, 0x0050, 0xffff, 0, "Quatech ESC-100D", -3, /* max 8x clock rate */ PUC_PORT_8S, 0x14, 0, 8, .config_function = puc_config_quatech }, { 0x135c, 0x0060, 0xffff, 0, "Quatech ESC-100M", -3, /* max 8x clock rate */ PUC_PORT_8S, 0x14, 0, 8, .config_function = puc_config_quatech }, { 0x135c, 0x0170, 0xffff, 0, "Quatech QSCLP-100", -1, /* max 2x clock rate */ PUC_PORT_4S, 0x18, 0, 8, .config_function = puc_config_quatech }, { 0x135c, 0x0180, 0xffff, 0, "Quatech DSCLP-100", -1, /* max 3x clock rate */ PUC_PORT_2S, 0x18, 0, 8, .config_function = puc_config_quatech }, { 0x135c, 0x01b0, 0xffff, 0, "Quatech DSCLP-200/300", -1, /* max 2x clock rate */ PUC_PORT_2S, 0x18, 0, 8, .config_function = puc_config_quatech }, { 0x135c, 0x01e0, 0xffff, 0, "Quatech ESCLP-100", -3, /* max 8x clock rate */ PUC_PORT_8S, 0x10, 0, 8, .config_function = puc_config_quatech }, { 0x1393, 0x1024, 0xffff, 0, "Moxa Technologies, Smartio CP-102E/PCIe", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x14, 0, -1, .config_function = puc_config_moxa }, { 0x1393, 0x1025, 0xffff, 0, "Moxa Technologies, Smartio CP-102EL/PCIe", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x14, 0, -1, .config_function = puc_config_moxa }, { 0x1393, 0x1040, 0xffff, 0, "Moxa Technologies, Smartio C104H/PCI", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x18, 0, 8, }, { 0x1393, 0x1041, 0xffff, 0, "Moxa Technologies, Smartio CP-104UL/PCI", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x18, 0, 8, }, { 0x1393, 0x1042, 0xffff, 0, "Moxa Technologies, Smartio CP-104JU/PCI", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x18, 0, 8, }, { 0x1393, 0x1043, 0xffff, 0, "Moxa Technologies, Smartio CP-104EL/PCIe", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x18, 0, 8, }, { 0x1393, 0x1045, 0xffff, 0, "Moxa Technologies, Smartio CP-104EL-A/PCIe", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x14, 0, -1, .config_function = puc_config_moxa }, { 0x1393, 0x1120, 0xffff, 0, "Moxa Technologies, CP-112UL", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x18, 0, 8, }, { 0x1393, 0x1141, 0xffff, 0, "Moxa Technologies, Industio CP-114", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x18, 0, 8, }, { 0x1393, 0x1144, 0xffff, 0, "Moxa Technologies, Smartio CP-114EL/PCIe", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x14, 0, -1, .config_function = puc_config_moxa }, { 0x1393, 0x1182, 0xffff, 0, "Moxa Technologies, Smartio CP-118EL-A/PCIe", DEFAULT_RCLK * 8, PUC_PORT_8S, 0x14, 0, -1, .config_function = puc_config_moxa }, { 0x1393, 0x1680, 0xffff, 0, "Moxa Technologies, C168H/PCI", DEFAULT_RCLK * 8, PUC_PORT_8S, 0x18, 0, 8, }, { 0x1393, 0x1681, 0xffff, 0, "Moxa Technologies, C168U/PCI", DEFAULT_RCLK * 8, PUC_PORT_8S, 0x18, 0, 8, }, { 0x1393, 0x1682, 0xffff, 0, "Moxa Technologies, CP-168EL/PCIe", DEFAULT_RCLK * 8, PUC_PORT_8S, 0x18, 0, 8, }, { 0x1393, 0x1683, 0xffff, 0, "Moxa Technologies, Smartio CP-168EL-A/PCIe", DEFAULT_RCLK * 8, PUC_PORT_8S, 0x14, 0, -1, .config_function = puc_config_moxa }, { 0x13a8, 0x0152, 0xffff, 0, "Exar XR17C/D152", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x10, 0, -1, .config_function = puc_config_exar }, { 0x13a8, 0x0154, 0xffff, 0, "Exar XR17C154", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x10, 0, -1, .config_function = puc_config_exar }, { 0x13a8, 0x0158, 0xffff, 0, "Exar XR17C158", DEFAULT_RCLK * 8, PUC_PORT_8S, 0x10, 0, -1, .config_function = puc_config_exar }, { 0x13a8, 0x0258, 0xffff, 0, "Exar XR17V258IV", DEFAULT_RCLK * 8, PUC_PORT_8S, 0x10, 0, -1, .config_function = puc_config_exar }, /* The XR17V358 uses the 125MHz PCIe clock as its reference clock. */ { 0x13a8, 0x0358, 0xffff, 0, "Exar XR17V358", 125000000, PUC_PORT_8S, 0x10, 0, -1, .config_function = puc_config_exar_pcie }, { 0x13fe, 0x1600, 0x1602, 0x0002, "Advantech PCI-1602", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x10, 0, 8, }, { 0x1407, 0x0100, 0xffff, 0, "Lava Computers Dual Serial", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x1407, 0x0101, 0xffff, 0, "Lava Computers Quatro A", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x1407, 0x0102, 0xffff, 0, "Lava Computers Quatro B", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x1407, 0x0120, 0xffff, 0, "Lava Computers Quattro-PCI A", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x1407, 0x0121, 0xffff, 0, "Lava Computers Quattro-PCI B", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x1407, 0x0180, 0xffff, 0, "Lava Computers Octo A", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 4, 0, }, { 0x1407, 0x0181, 0xffff, 0, "Lava Computers Octo B", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 4, 0, }, { 0x1409, 0x7268, 0xffff, 0, "Sunix SUN1888", 0, PUC_PORT_2P, 0x10, 0, 8, }, { 0x1409, 0x7168, 0xffff, 0, NULL, DEFAULT_RCLK * 8, PUC_PORT_NONSTANDARD, 0x10, -1, -1, .config_function = puc_config_timedia }, /* * Boards with an Oxford Semiconductor chip. * * Oxford Semiconductor provides documentation for their chip at: * * * As sold by Kouwell . * I/O Flex PCI I/O Card Model-223 with 4 serial and 1 parallel ports. */ { 0x1415, 0x9501, 0x10fc, 0xc070, "I-O DATA RSA-PCI2/R", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x10, 0, 8, }, { 0x1415, 0x9501, 0x131f, 0x2050, "SIIG Cyber 4 PCI 16550", DEFAULT_RCLK * 10, PUC_PORT_4S, 0x10, 0, 8, }, { 0x1415, 0x9501, 0x131f, 0x2051, "SIIG Cyber 4S PCI 16C650 (20x family)", DEFAULT_RCLK * 10, PUC_PORT_4S, 0x10, 0, 8, }, { 0x1415, 0x9501, 0x131f, 0x2052, "SIIG Quartet Serial 850", DEFAULT_RCLK * 10, PUC_PORT_4S, 0x10, 0, 8, }, { 0x1415, 0x9501, 0x14db, 0x2150, "Kuroutoshikou SERIAL4P-LPPCI2", DEFAULT_RCLK * 10, PUC_PORT_4S, 0x10, 0, 8, }, { 0x1415, 0x9501, 0xffff, 0, "Oxford Semiconductor OX16PCI954 UARTs", 0, PUC_PORT_4S, 0x10, 0, 8, .config_function = puc_config_oxford_pci954 }, { 0x1415, 0x950a, 0x131f, 0x2030, "SIIG Cyber 2S PCIe", DEFAULT_RCLK * 10, PUC_PORT_2S, 0x10, 0, 8, }, { 0x1415, 0x950a, 0x131f, 0x2032, "SIIG Cyber Serial Dual PCI 16C850", DEFAULT_RCLK * 10, PUC_PORT_4S, 0x10, 0, 8, }, { 0x1415, 0x950a, 0xffff, 0, "Oxford Semiconductor OX16PCI954 UARTs", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 0, 8, }, { 0x1415, 0x9511, 0xffff, 0, "Oxford Semiconductor OX9160/OX16PCI954 UARTs (function 1)", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 0, 8, }, { 0x1415, 0x9521, 0xffff, 0, "Oxford Semiconductor OX16PCI952 UARTs", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x1415, 0x9538, 0xffff, 0, "Oxford Semiconductor OX16PCI958 UARTs", DEFAULT_RCLK, PUC_PORT_8S, 0x18, 0, 8, }, /* * Perle boards use Oxford Semiconductor chips, but they store the * Oxford Semiconductor device ID as a subvendor device ID and use * their own device IDs. */ { 0x155f, 0x0331, 0xffff, 0, "Perle Ultraport4 Express", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x10, 0, 8, }, { 0x155f, 0xB012, 0xffff, 0, "Perle Speed2 LE", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x10, 0, 8, }, { 0x155f, 0xB022, 0xffff, 0, "Perle Speed2 LE", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x10, 0, 8, }, { 0x155f, 0xB004, 0xffff, 0, "Perle Speed4 LE", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x10, 0, 8, }, { 0x155f, 0xB008, 0xffff, 0, "Perle Speed8 LE", DEFAULT_RCLK * 8, PUC_PORT_8S, 0x10, 0, 8, }, /* * Oxford Semiconductor PCI Express Expresso family * * Found in many 'native' PCI Express serial boards such as: * * eMegatech MP954ER4 (4 port) and MP958ER8 (8 port) * * * Lindy 51189 (4 port) * * * StarTech.com PEX4S952 (4 port) and PEX8S952 (8 port) * */ { 0x1415, 0xc11b, 0xffff, 0, "Oxford Semiconductor OXPCIe952 1S1P", DEFAULT_RCLK * 0x22, PUC_PORT_NONSTANDARD, 0x10, 0, -1, .config_function = puc_config_oxford_pcie }, { 0x1415, 0xc138, 0xffff, 0, "Oxford Semiconductor OXPCIe952 UARTs", DEFAULT_RCLK * 0x22, PUC_PORT_NONSTANDARD, 0x10, 0, -1, .config_function = puc_config_oxford_pcie }, { 0x1415, 0xc158, 0xffff, 0, "Oxford Semiconductor OXPCIe952 UARTs", DEFAULT_RCLK * 0x22, PUC_PORT_NONSTANDARD, 0x10, 0, -1, .config_function = puc_config_oxford_pcie }, { 0x1415, 0xc15d, 0xffff, 0, "Oxford Semiconductor OXPCIe952 UARTs (function 1)", DEFAULT_RCLK * 0x22, PUC_PORT_NONSTANDARD, 0x10, 0, -1, .config_function = puc_config_oxford_pcie }, { 0x1415, 0xc208, 0xffff, 0, "Oxford Semiconductor OXPCIe954 UARTs", DEFAULT_RCLK * 0x22, PUC_PORT_NONSTANDARD, 0x10, 0, -1, .config_function = puc_config_oxford_pcie }, { 0x1415, 0xc20d, 0xffff, 0, "Oxford Semiconductor OXPCIe954 UARTs (function 1)", DEFAULT_RCLK * 0x22, PUC_PORT_NONSTANDARD, 0x10, 0, -1, .config_function = puc_config_oxford_pcie }, { 0x1415, 0xc308, 0xffff, 0, "Oxford Semiconductor OXPCIe958 UARTs", DEFAULT_RCLK * 0x22, PUC_PORT_NONSTANDARD, 0x10, 0, -1, .config_function = puc_config_oxford_pcie }, { 0x1415, 0xc30d, 0xffff, 0, "Oxford Semiconductor OXPCIe958 UARTs (function 1)", DEFAULT_RCLK * 0x22, PUC_PORT_NONSTANDARD, 0x10, 0, -1, .config_function = puc_config_oxford_pcie }, { 0x14d2, 0x8010, 0xffff, 0, "VScom PCI-100L", DEFAULT_RCLK * 8, PUC_PORT_1S, 0x14, 0, 0, }, { 0x14d2, 0x8020, 0xffff, 0, "VScom PCI-200L", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x14, 4, 0, }, { 0x14d2, 0x8028, 0xffff, 0, "VScom 200Li", DEFAULT_RCLK, PUC_PORT_2S, 0x20, 0, 8, }, /* * VScom (Titan?) PCI-800L. More modern variant of the * PCI-800. Uses 6 discrete 16550 UARTs, plus another * two of them obviously implemented as macro cells in * the ASIC. This causes the weird port access pattern * below, where two of the IO port ranges each access * one of the ASIC UARTs, and a block of IO addresses * access the external UARTs. */ { 0x14d2, 0x8080, 0xffff, 0, "Titan VScom PCI-800L", DEFAULT_RCLK * 8, PUC_PORT_8S, 0x14, -1, -1, .config_function = puc_config_titan }, /* * VScom PCI-800H. Uses 8 16950 UART, behind a PCI chips that offers * 4 com port on PCI device 0 and 4 on PCI device 1. PCI device 0 has * device ID 3 and PCI device 1 device ID 4. */ { 0x14d2, 0xa003, 0xffff, 0, "Titan PCI-800H", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x10, 0, 8, }, { 0x14d2, 0xa004, 0xffff, 0, "Titan PCI-800H", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x10, 0, 8, }, { 0x14d2, 0xa005, 0xffff, 0, "Titan PCI-200H", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x10, 0, 8, }, { 0x14d2, 0xe020, 0xffff, 0, "Titan VScom PCI-200HV2", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x10, 4, 0, }, { 0x14d2, 0xa007, 0xffff, 0, "Titan VScom PCIex-800H", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x10, 0, 8, }, { 0x14d2, 0xa008, 0xffff, 0, "Titan VScom PCIex-800H", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x10, 0, 8, }, { 0x14db, 0x2130, 0xffff, 0, "Avlab Technology, PCI IO 2S", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x14db, 0x2150, 0xffff, 0, "Avlab Low Profile PCI 4 Serial", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 4, 0, }, { 0x14db, 0x2152, 0xffff, 0, "Avlab Low Profile PCI 4 Serial", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 4, 0, }, { 0x1592, 0x0781, 0xffff, 0, "Syba Tech Ltd. PCI-4S2P-550-ECP", DEFAULT_RCLK, PUC_PORT_4S1P, 0x10, 0, -1, .config_function = puc_config_syba }, { 0x1fd4, 0x1999, 0x1fd4, 0x0002, "Sunix SER5xxxx 2-port serial", DEFAULT_RCLK * 8, PUC_PORT_2S, 0x10, 0, 8, }, { 0x1fd4, 0x1999, 0x1fd4, 0x0004, "Sunix SER5xxxx 4-port serial", DEFAULT_RCLK * 8, PUC_PORT_4S, 0x10, 0, 8, }, { 0x1fd4, 0x1999, 0x1fd4, 0x0008, "Sunix SER5xxxx 8-port serial", DEFAULT_RCLK * 8, PUC_PORT_8S, -1, -1, -1, .config_function = puc_config_sunix }, { 0x1fd4, 0x1999, 0x1fd4, 0x0101, "Sunix MIO5xxxx 1-port serial and 1284 Printer port", DEFAULT_RCLK * 8, PUC_PORT_1S1P, -1, -1, -1, .config_function = puc_config_sunix }, { 0x1fd4, 0x1999, 0x1fd4, 0x0102, "Sunix MIO5xxxx 2-port serial and 1284 Printer port", DEFAULT_RCLK * 8, PUC_PORT_2S1P, -1, -1, -1, .config_function = puc_config_sunix }, { 0x1fd4, 0x1999, 0x1fd4, 0x0104, "Sunix MIO5xxxx 4-port serial and 1284 Printer port", DEFAULT_RCLK * 8, PUC_PORT_4S1P, -1, -1, -1, .config_function = puc_config_sunix }, { 0x5372, 0x6872, 0xffff, 0, "Feasso PCI FPP-02 2S1P", DEFAULT_RCLK, PUC_PORT_2S1P, 0x10, 4, 0, }, { 0x5372, 0x6873, 0xffff, 0, "Sun 1040 PCI Quad Serial", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 4, 0, }, { 0x6666, 0x0001, 0xffff, 0, "Decision Computer Inc, PCCOM 4-port serial", DEFAULT_RCLK, PUC_PORT_4S, 0x1c, 0, 8, }, { 0x6666, 0x0002, 0xffff, 0, "Decision Computer Inc, PCCOM 8-port serial", DEFAULT_RCLK, PUC_PORT_8S, 0x1c, 0, 8, }, { 0x6666, 0x0004, 0xffff, 0, "PCCOM dual port RS232/422/485", DEFAULT_RCLK, PUC_PORT_2S, 0x1c, 0, 8, }, { 0x9710, 0x9815, 0xffff, 0, "NetMos NM9815 Dual 1284 Printer port", 0, PUC_PORT_2P, 0x10, 8, 0, }, /* * This is more specific than the generic NM9835 entry, and is placed * here to _prevent_ puc(4) from claiming this single port card. * * uart(4) will claim this device. */ { 0x9710, 0x9835, 0x1000, 1, "NetMos NM9835 based 1-port serial", DEFAULT_RCLK, PUC_PORT_1S, 0x10, 4, 0, }, { 0x9710, 0x9835, 0x1000, 2, "NetMos NM9835 based 2-port serial", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x9710, 0x9835, 0xffff, 0, "NetMos NM9835 Dual UART and 1284 Printer port", DEFAULT_RCLK, PUC_PORT_2S1P, 0x10, 4, 0, }, { 0x9710, 0x9845, 0x1000, 0x0006, "NetMos NM9845 6 Port UART", DEFAULT_RCLK, PUC_PORT_6S, 0x10, 4, 0, }, { 0x9710, 0x9845, 0xffff, 0, "NetMos NM9845 Quad UART and 1284 Printer port", DEFAULT_RCLK, PUC_PORT_4S1P, 0x10, 4, 0, }, { 0x9710, 0x9865, 0xa000, 0x3002, "NetMos NM9865 Dual UART", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 4, 0, }, { 0x9710, 0x9865, 0xa000, 0x3003, "NetMos NM9865 Triple UART", DEFAULT_RCLK, PUC_PORT_3S, 0x10, 4, 0, }, { 0x9710, 0x9865, 0xa000, 0x3004, "NetMos NM9865 Quad UART", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 4, 0, }, { 0x9710, 0x9865, 0xa000, 0x3011, "NetMos NM9865 Single UART and 1284 Printer port", DEFAULT_RCLK, PUC_PORT_1S1P, 0x10, 4, 0, }, { 0x9710, 0x9865, 0xa000, 0x3012, "NetMos NM9865 Dual UART and 1284 Printer port", DEFAULT_RCLK, PUC_PORT_2S1P, 0x10, 4, 0, }, { 0x9710, 0x9865, 0xa000, 0x3020, "NetMos NM9865 Dual 1284 Printer port", DEFAULT_RCLK, PUC_PORT_2P, 0x10, 4, 0, }, { 0xb00c, 0x021c, 0xffff, 0, "IC Book Labs Gunboat x4 Lite", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 0, 8, .config_function = puc_config_icbook }, { 0xb00c, 0x031c, 0xffff, 0, "IC Book Labs Gunboat x4 Pro", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 0, 8, .config_function = puc_config_icbook }, { 0xb00c, 0x041c, 0xffff, 0, "IC Book Labs Ironclad x8 Lite", DEFAULT_RCLK, PUC_PORT_8S, 0x10, 0, 8, .config_function = puc_config_icbook }, { 0xb00c, 0x051c, 0xffff, 0, "IC Book Labs Ironclad x8 Pro", DEFAULT_RCLK, PUC_PORT_8S, 0x10, 0, 8, .config_function = puc_config_icbook }, { 0xb00c, 0x081c, 0xffff, 0, "IC Book Labs Dreadnought x16 Pro", DEFAULT_RCLK * 8, PUC_PORT_16S, 0x10, 0, 8, .config_function = puc_config_icbook }, { 0xb00c, 0x091c, 0xffff, 0, "IC Book Labs Dreadnought x16 Lite", DEFAULT_RCLK, PUC_PORT_16S, 0x10, 0, 8, .config_function = puc_config_icbook }, { 0xb00c, 0x0a1c, 0xffff, 0, "IC Book Labs Gunboat x2 Low Profile", DEFAULT_RCLK, PUC_PORT_2S, 0x10, 0, 8, }, { 0xb00c, 0x0b1c, 0xffff, 0, "IC Book Labs Gunboat x4 Low Profile", DEFAULT_RCLK, PUC_PORT_4S, 0x10, 0, 8, .config_function = puc_config_icbook }, { 0xffff, 0, 0xffff, 0, NULL, 0 } }; static int puc_config_amc(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { switch (cmd) { case PUC_CFG_GET_OFS: *res = 8 * (port & 1); return (0); case PUC_CFG_GET_RID: *res = 0x14 + (port >> 1) * 4; return (0); default: break; } return (ENXIO); } static int puc_config_diva(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { const struct puc_cfg *cfg = sc->sc_cfg; if (cmd == PUC_CFG_GET_OFS) { if (cfg->subdevice == 0x1282) /* Everest SP */ port <<= 1; else if (cfg->subdevice == 0x104b) /* Maestro SP2 */ port = (port == 3) ? 4 : port; *res = port * 8 + ((port > 2) ? 0x18 : 0); return (0); } return (ENXIO); } static int puc_config_exar(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { if (cmd == PUC_CFG_GET_OFS) { *res = port * 0x200; return (0); } return (ENXIO); } static int puc_config_exar_pcie(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { if (cmd == PUC_CFG_GET_OFS) { *res = port * 0x400; return (0); } return (ENXIO); } static int puc_config_icbook(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { if (cmd == PUC_CFG_GET_ILR) { *res = PUC_ILR_DIGI; return (0); } return (ENXIO); } static int puc_config_moxa(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { if (cmd == PUC_CFG_GET_OFS) { const struct puc_cfg *cfg = sc->sc_cfg; if (port == 3 && (cfg->device == 0x1045 || cfg->device == 0x1144)) port = 7; *res = port * 0x200; return 0; } return (ENXIO); } static int puc_config_quatech(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { const struct puc_cfg *cfg = sc->sc_cfg; struct puc_bar *bar; uint8_t v0, v1; switch (cmd) { case PUC_CFG_SETUP: /* * Check if the scratchpad register is enabled or if the * interrupt status and options registers are active. */ bar = puc_get_bar(sc, cfg->rid); if (bar == NULL) return (ENXIO); /* Set DLAB in the LCR register of UART 0. */ bus_write_1(bar->b_res, 3, 0x80); /* Write 0 to the SPR register of UART 0. */ bus_write_1(bar->b_res, 7, 0); /* Read back the contents of the SPR register of UART 0. */ v0 = bus_read_1(bar->b_res, 7); /* Write a specific value to the SPR register of UART 0. */ bus_write_1(bar->b_res, 7, 0x80 + -cfg->clock); /* Read back the contents of the SPR register of UART 0. */ v1 = bus_read_1(bar->b_res, 7); /* Clear DLAB in the LCR register of UART 0. */ bus_write_1(bar->b_res, 3, 0); /* Save the two values read-back from the SPR register. */ sc->sc_cfg_data = (v0 << 8) | v1; if (v0 == 0 && v1 == 0x80 + -cfg->clock) { /* * The SPR register echoed the two values written * by us. This means that the SPAD jumper is set. */ device_printf(sc->sc_dev, "warning: extra features " "not usable -- SPAD compatibility enabled\n"); return (0); } if (v0 != 0) { /* * The first value doesn't match. This can only mean * that the SPAD jumper is not set and that a non- * standard fixed clock multiplier jumper is set. */ if (bootverbose) device_printf(sc->sc_dev, "fixed clock rate " "multiplier of %d\n", 1 << v0); if (v0 < -cfg->clock) device_printf(sc->sc_dev, "warning: " "suboptimal fixed clock rate multiplier " "setting\n"); return (0); } /* * The first value matched, but the second didn't. We know * that the SPAD jumper is not set. We also know that the * clock rate multiplier is software controlled *and* that * we just programmed it to the maximum allowed. */ if (bootverbose) device_printf(sc->sc_dev, "clock rate multiplier of " "%d selected\n", 1 << -cfg->clock); return (0); case PUC_CFG_GET_CLOCK: v0 = (sc->sc_cfg_data >> 8) & 0xff; v1 = sc->sc_cfg_data & 0xff; if (v0 == 0 && v1 == 0x80 + -cfg->clock) { /* * XXX With the SPAD jumper applied, there's no * easy way of knowing if there's also a clock * rate multiplier jumper installed. Let's hope * not... */ *res = DEFAULT_RCLK; } else if (v0 == 0) { /* * No clock rate multiplier jumper installed, * so we programmed the board with the maximum * multiplier allowed as given to us in the * clock field of the config record (negated). */ *res = DEFAULT_RCLK << -cfg->clock; } else *res = DEFAULT_RCLK << v0; return (0); case PUC_CFG_GET_ILR: v0 = (sc->sc_cfg_data >> 8) & 0xff; v1 = sc->sc_cfg_data & 0xff; *res = (v0 == 0 && v1 == 0x80 + -cfg->clock) ? PUC_ILR_NONE : PUC_ILR_QUATECH; return (0); default: break; } return (ENXIO); } static int puc_config_syba(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { static int base[] = { 0x251, 0x3f0, 0 }; const struct puc_cfg *cfg = sc->sc_cfg; struct puc_bar *bar; int efir, idx, ofs; uint8_t v; switch (cmd) { case PUC_CFG_SETUP: bar = puc_get_bar(sc, cfg->rid); if (bar == NULL) return (ENXIO); /* configure both W83877TFs */ bus_write_1(bar->b_res, 0x250, 0x89); bus_write_1(bar->b_res, 0x3f0, 0x87); bus_write_1(bar->b_res, 0x3f0, 0x87); idx = 0; while (base[idx] != 0) { efir = base[idx]; bus_write_1(bar->b_res, efir, 0x09); v = bus_read_1(bar->b_res, efir + 1); if ((v & 0x0f) != 0x0c) return (ENXIO); bus_write_1(bar->b_res, efir, 0x16); v = bus_read_1(bar->b_res, efir + 1); bus_write_1(bar->b_res, efir, 0x16); bus_write_1(bar->b_res, efir + 1, v | 0x04); bus_write_1(bar->b_res, efir, 0x16); bus_write_1(bar->b_res, efir + 1, v & ~0x04); ofs = base[idx] & 0x300; bus_write_1(bar->b_res, efir, 0x23); bus_write_1(bar->b_res, efir + 1, (ofs + 0x78) >> 2); bus_write_1(bar->b_res, efir, 0x24); bus_write_1(bar->b_res, efir + 1, (ofs + 0xf8) >> 2); bus_write_1(bar->b_res, efir, 0x25); bus_write_1(bar->b_res, efir + 1, (ofs + 0xe8) >> 2); bus_write_1(bar->b_res, efir, 0x17); bus_write_1(bar->b_res, efir + 1, 0x03); bus_write_1(bar->b_res, efir, 0x28); bus_write_1(bar->b_res, efir + 1, 0x43); idx++; } bus_write_1(bar->b_res, 0x250, 0xaa); bus_write_1(bar->b_res, 0x3f0, 0xaa); return (0); case PUC_CFG_GET_OFS: switch (port) { case 0: *res = 0x2f8; return (0); case 1: *res = 0x2e8; return (0); case 2: *res = 0x3f8; return (0); case 3: *res = 0x3e8; return (0); case 4: *res = 0x278; return (0); } break; default: break; } return (ENXIO); } static int puc_config_siig(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { const struct puc_cfg *cfg = sc->sc_cfg; switch (cmd) { case PUC_CFG_GET_OFS: if (cfg->ports == PUC_PORT_8S) { *res = (port > 4) ? 8 * (port - 4) : 0; return (0); } break; case PUC_CFG_GET_RID: if (cfg->ports == PUC_PORT_8S) { *res = 0x10 + ((port > 4) ? 0x10 : 4 * port); return (0); } if (cfg->ports == PUC_PORT_2S1P) { switch (port) { case 0: *res = 0x10; return (0); case 1: *res = 0x14; return (0); case 2: *res = 0x1c; return (0); } } break; default: break; } return (ENXIO); } static int puc_config_timedia(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { static const uint16_t dual[] = { 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085, 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079, 0xD079, 0 }; static const uint16_t quad[] = { 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056, 0xB157, 0 }; static const uint16_t octa[] = { 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 }; static const struct { int ports; const uint16_t *ids; } subdevs[] = { { 2, dual }, { 4, quad }, { 8, octa }, { 0, NULL } }; static char desc[64]; int dev, id; uint16_t subdev; switch (cmd) { case PUC_CFG_GET_CLOCK: if (port < 2) *res = DEFAULT_RCLK * 8; else *res = DEFAULT_RCLK; return (0); case PUC_CFG_GET_DESC: snprintf(desc, sizeof(desc), "Timedia technology %d Port Serial", (int)sc->sc_cfg_data); *res = (intptr_t)desc; return (0); case PUC_CFG_GET_NPORTS: subdev = pci_get_subdevice(sc->sc_dev); dev = 0; while (subdevs[dev].ports != 0) { id = 0; while (subdevs[dev].ids[id] != 0) { if (subdev == subdevs[dev].ids[id]) { sc->sc_cfg_data = subdevs[dev].ports; *res = sc->sc_cfg_data; return (0); } id++; } dev++; } return (ENXIO); case PUC_CFG_GET_OFS: *res = (port == 1 || port == 3) ? 8 : 0; return (0); case PUC_CFG_GET_RID: *res = 0x10 + ((port > 3) ? port - 2 : port >> 1) * 4; return (0); case PUC_CFG_GET_TYPE: *res = PUC_TYPE_SERIAL; return (0); default: break; } return (ENXIO); } static int puc_config_oxford_pci954(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port __unused, intptr_t *res) { switch (cmd) { case PUC_CFG_GET_CLOCK: /* * OXu16PCI954 use a 14.7456 MHz clock by default while * OX16PCI954 and OXm16PCI954 employ a 1.8432 MHz one. */ if (pci_get_revid(sc->sc_dev) == 1) *res = DEFAULT_RCLK * 8; else *res = DEFAULT_RCLK; return (0); default: break; } return (ENXIO); } static int puc_config_oxford_pcie(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { const struct puc_cfg *cfg = sc->sc_cfg; int idx; struct puc_bar *bar; uint8_t value; switch (cmd) { case PUC_CFG_SETUP: device_printf(sc->sc_dev, "%d UARTs detected\n", sc->sc_nports); /* Set UARTs to enhanced mode */ bar = puc_get_bar(sc, cfg->rid); if (bar == NULL) return (ENXIO); for (idx = 0; idx < sc->sc_nports; idx++) { value = bus_read_1(bar->b_res, 0x1000 + (idx << 9) + 0x92); bus_write_1(bar->b_res, 0x1000 + (idx << 9) + 0x92, value | 0x10); } return (0); case PUC_CFG_GET_LEN: *res = 0x200; return (0); case PUC_CFG_GET_NPORTS: /* * Check if we are being called from puc_bfe_attach() * or puc_bfe_probe(). If puc_bfe_probe(), we cannot * puc_get_bar(), so we return a value of 16. This has cosmetic * side-effects at worst; in PUC_CFG_GET_DESC, * (int)sc->sc_cfg_data will not contain the true number of * ports in PUC_CFG_GET_DESC, but we are not implementing that * call for this device family anyway. * * The check is for initialisation of sc->sc_bar[idx], which is * only done in puc_bfe_attach(). */ idx = 0; do { if (sc->sc_bar[idx++].b_rid != -1) { sc->sc_cfg_data = 16; *res = sc->sc_cfg_data; return (0); } } while (idx < PUC_PCI_BARS); bar = puc_get_bar(sc, cfg->rid); if (bar == NULL) return (ENXIO); value = bus_read_1(bar->b_res, 0x04); if (value == 0) return (ENXIO); sc->sc_cfg_data = value; *res = sc->sc_cfg_data; return (0); case PUC_CFG_GET_OFS: *res = 0x1000 + (port << 9); return (0); case PUC_CFG_GET_TYPE: *res = PUC_TYPE_SERIAL; return (0); default: break; } return (ENXIO); } static int puc_config_sunix(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { int error; switch (cmd) { case PUC_CFG_GET_OFS: error = puc_config(sc, PUC_CFG_GET_TYPE, port, res); if (error != 0) return (error); *res = (*res == PUC_TYPE_SERIAL) ? (port & 3) * 8 : 0; return (0); case PUC_CFG_GET_RID: error = puc_config(sc, PUC_CFG_GET_TYPE, port, res); if (error != 0) return (error); *res = (*res == PUC_TYPE_SERIAL && port <= 3) ? 0x10 : 0x14; return (0); default: break; } return (ENXIO); } static int puc_config_titan(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { switch (cmd) { case PUC_CFG_GET_OFS: *res = (port < 3) ? 0 : (port - 2) << 3; return (0); case PUC_CFG_GET_RID: *res = 0x14 + ((port >= 2) ? 0x0c : port << 2); return (0); default: break; } return (ENXIO); } Index: stable/10 =================================================================== --- stable/10 (revision 287925) +++ stable/10 (revision 287926) Property changes on: stable/10 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r263109