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
35#include <dev/puc/puc_bus.h>
36#include <dev/puc/puc_cfg.h>
37#include <dev/puc/puc_bfe.h>
38
39int
40puc_config(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *r)
41{
42	const struct puc_cfg *cfg = sc->sc_cfg;
43	int error;
44
45	if (cfg->config_function != NULL) {
46		error = cfg->config_function(sc, cmd, port, r);
47		if (!error)
48			return (0);
49	} else
50		error = EDOOFUS;
51
52	switch (cmd) {
53	case PUC_CFG_GET_CLOCK:
54		if (cfg->clock < 0)
55			return (error);
56		*r = cfg->clock;
57		return (0);
58	case PUC_CFG_GET_DESC:
59		if (cfg->desc == NULL)
60			return (error);
61		*r = (intptr_t)cfg->desc;
62		return (0);
63	case PUC_CFG_GET_ILR:
64		*r = PUC_ILR_NONE;
65		return (0);
66	case PUC_CFG_GET_LEN:
67		/* The length of bus space needed by the port. */
68		*r = 8;
69		return (0);
70	case PUC_CFG_GET_NPORTS:
71		/* The number of ports on this card. */
72		switch (cfg->ports) {
73		case PUC_PORT_NONSTANDARD:
74			return (error);
75		case PUC_PORT_1P:
76		case PUC_PORT_1S:
77			*r = 1;
78			return (0);
79		case PUC_PORT_1S1P:
80		case PUC_PORT_2P:
81		case PUC_PORT_2S:
82			*r = 2;
83			return (0);
84		case PUC_PORT_1S2P:
85		case PUC_PORT_2S1P:
86		case PUC_PORT_3S:
87			*r = 3;
88			return (0);
89		case PUC_PORT_4S:
90			*r = 4;
91			return (0);
92		case PUC_PORT_4S1P:
93			*r = 5;
94			return (0);
95		case PUC_PORT_6S:
96			*r = 6;
97			return (0);
98		case PUC_PORT_8S:
99			*r = 8;
100			return (0);
101		case PUC_PORT_12S:
102			*r = 12;
103			return (0);
104		case PUC_PORT_16S:
105			*r = 16;
106			return (0);
107		}
108		break;
109	case PUC_CFG_GET_OFS:
110		/* The offset relative to the RID. */
111		if (cfg->d_ofs < 0)
112			return (error);
113		*r = port * cfg->d_ofs;
114		return (0);
115	case PUC_CFG_GET_RID:
116		/* The RID for this port. */
117		if (port == 0) {
118			if (cfg->rid < 0)
119				return (error);
120			*r = cfg->rid;
121			return (0);
122		}
123		if (cfg->d_rid < 0)
124			return (error);
125		if (cfg->rid < 0) {
126			error = puc_config(sc, PUC_CFG_GET_RID, 0, r);
127			if (error)
128				return (error);
129		} else
130			*r = cfg->rid;
131		*r += port * cfg->d_rid;
132		return (0);
133	case PUC_CFG_GET_TYPE:
134		/* The type of this port. */
135		if (cfg->ports == PUC_PORT_NONSTANDARD)
136			return (error);
137		switch (port) {
138		case 0:
139			if (cfg->ports == PUC_PORT_1P ||
140			    cfg->ports == PUC_PORT_2P)
141				*r = PUC_TYPE_PARALLEL;
142			else
143				*r = PUC_TYPE_SERIAL;
144			return (0);
145		case 1:
146			if (cfg->ports == PUC_PORT_1S1P ||
147			    cfg->ports == PUC_PORT_1S2P ||
148			    cfg->ports == PUC_PORT_2P)
149				*r = PUC_TYPE_PARALLEL;
150			else
151				*r = PUC_TYPE_SERIAL;
152			return (0);
153		case 2:
154			if (cfg->ports == PUC_PORT_1S2P ||
155			    cfg->ports == PUC_PORT_2S1P)
156				*r = PUC_TYPE_PARALLEL;
157			else
158				*r = PUC_TYPE_SERIAL;
159			return (0);
160		case 4:
161			if (cfg->ports == PUC_PORT_4S1P)
162				*r = PUC_TYPE_PARALLEL;
163			else
164				*r = PUC_TYPE_SERIAL;
165			return (0);
166		}
167		*r = PUC_TYPE_SERIAL;
168		return (0);
169	case PUC_CFG_SETUP:
170		*r = ENXIO;
171		return (0);
172	}
173
174	return (ENXIO);
175}
176