1/*-
2 * Copyright (c) 2006 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/bus.h>
33#include <sys/rman.h>
34#include <sys/sysctl.h>
35
36#include <dev/puc/puc_bus.h>
37#include <dev/puc/puc_cfg.h>
38#include <dev/puc/puc_bfe.h>
39
40int
41puc_config(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *r)
42{
43	const struct puc_cfg *cfg = sc->sc_cfg;
44	int error;
45
46	if (cfg->config_function != NULL) {
47		error = cfg->config_function(sc, cmd, port, r);
48		if (!error)
49			return (0);
50	} else
51		error = EDOOFUS;
52
53	switch (cmd) {
54	case PUC_CFG_GET_CLOCK:
55		if (cfg->clock < 0)
56			return (error);
57		*r = cfg->clock;
58		return (0);
59	case PUC_CFG_GET_DESC:
60		if (cfg->desc == NULL)
61			return (error);
62		*r = (intptr_t)cfg->desc;
63		return (0);
64	case PUC_CFG_GET_ILR:
65		*r = PUC_ILR_NONE;
66		return (0);
67	case PUC_CFG_GET_LEN:
68		/* The length of bus space needed by the port. */
69		*r = 8;
70		return (0);
71	case PUC_CFG_GET_NPORTS:
72		/* The number of ports on this card. */
73		switch (cfg->ports) {
74		case PUC_PORT_NONSTANDARD:
75			return (error);
76		case PUC_PORT_1P:
77		case PUC_PORT_1S:
78			*r = 1;
79			return (0);
80		case PUC_PORT_1S1P:
81		case PUC_PORT_2P:
82		case PUC_PORT_2S:
83			*r = 2;
84			return (0);
85		case PUC_PORT_1S2P:
86		case PUC_PORT_2S1P:
87		case PUC_PORT_3S:
88			*r = 3;
89			return (0);
90		case PUC_PORT_4S:
91			*r = 4;
92			return (0);
93		case PUC_PORT_4S1P:
94			*r = 5;
95			return (0);
96		case PUC_PORT_6S:
97			*r = 6;
98			return (0);
99		case PUC_PORT_8S:
100			*r = 8;
101			return (0);
102		case PUC_PORT_12S:
103			*r = 12;
104			return (0);
105		case PUC_PORT_16S:
106			*r = 16;
107			return (0);
108		}
109		break;
110	case PUC_CFG_GET_OFS:
111		/* The offset relative to the RID. */
112		if (cfg->d_ofs < 0)
113			return (error);
114		*r = port * cfg->d_ofs;
115		return (0);
116	case PUC_CFG_GET_RID:
117		/* The RID for this port. */
118		if (port == 0) {
119			if (cfg->rid < 0)
120				return (error);
121			*r = cfg->rid;
122			return (0);
123		}
124		if (cfg->d_rid < 0)
125			return (error);
126		if (cfg->rid < 0) {
127			error = puc_config(sc, PUC_CFG_GET_RID, 0, r);
128			if (error)
129				return (error);
130		} else
131			*r = cfg->rid;
132		*r += port * cfg->d_rid;
133		return (0);
134	case PUC_CFG_GET_TYPE:
135		/* The type of this port. */
136		if (cfg->ports == PUC_PORT_NONSTANDARD)
137			return (error);
138		switch (port) {
139		case 0:
140			if (cfg->ports == PUC_PORT_1P ||
141			    cfg->ports == PUC_PORT_2P)
142				*r = PUC_TYPE_PARALLEL;
143			else
144				*r = PUC_TYPE_SERIAL;
145			return (0);
146		case 1:
147			if (cfg->ports == PUC_PORT_1S1P ||
148			    cfg->ports == PUC_PORT_1S2P ||
149			    cfg->ports == PUC_PORT_2P)
150				*r = PUC_TYPE_PARALLEL;
151			else
152				*r = PUC_TYPE_SERIAL;
153			return (0);
154		case 2:
155			if (cfg->ports == PUC_PORT_1S2P ||
156			    cfg->ports == PUC_PORT_2S1P)
157				*r = PUC_TYPE_PARALLEL;
158			else
159				*r = PUC_TYPE_SERIAL;
160			return (0);
161		case 4:
162			if (cfg->ports == PUC_PORT_4S1P)
163				*r = PUC_TYPE_PARALLEL;
164			else
165				*r = PUC_TYPE_SERIAL;
166			return (0);
167		}
168		*r = PUC_TYPE_SERIAL;
169		return (0);
170	case PUC_CFG_SETUP:
171		*r = ENXIO;
172		return (0);
173	}
174
175	return (ENXIO);
176}
177