Exemplo n.º 1
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);
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
0
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);
}