busiosubr.c revision 90850
1/* $FreeBSD: head/sys/pc98/pc98/busiosubr.c 90850 2002-02-18 13:44:46Z nyan $ */
2/*	$NecBSD: busiosubr.c,v 1.30.4.4 1999/08/28 02:25:35 honda Exp $	*/
3/*	$NetBSD$	*/
4
5/*
6 * [NetBSD for NEC PC-98 series]
7 *  Copyright (c) 1996, 1997, 1998
8 *	NetBSD/pc98 porting staff. All rights reserved.
9 *
10 * [Ported for FreeBSD]
11 *  Copyright (c) 2001
12 *	TAKAHASHI Yoshihiro. All rights reserved.
13 *
14 *  Redistribution and use in source and binary forms, with or without
15 *  modification, are permitted provided that the following conditions
16 *  are met:
17 *  1. Redistributions of source code must retain the above copyright
18 *     notice, this list of conditions and the following disclaimer.
19 *  2. Redistributions in binary form must reproduce the above copyright
20 *     notice, this list of conditions and the following disclaimer in the
21 *     documentation and/or other materials provided with the distribution.
22 *  3. The name of the author may not be used to endorse or promote products
23 *     derived from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38/*
39 * Copyright (c) 1997, 1998
40 *	Naofumi HONDA.  All rights reserved.
41 */
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/kernel.h>
46#include <sys/malloc.h>
47#include <machine/bus.h>
48
49static MALLOC_DEFINE(M_BUSSPACEHANDLE, "busspacehandle", "Bus space handle");
50
51_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_io,u_int8_t,1)
52_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_io,u_int16_t,2)
53_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_io,u_int32_t,4)
54_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_mem,u_int8_t,1)
55_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_mem,u_int16_t,2)
56_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_mem,u_int32_t,4)
57
58_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_io,u_int8_t,1)
59_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_io,u_int16_t,2)
60_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_io,u_int32_t,4)
61_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_mem,u_int8_t,1)
62_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_mem,u_int16_t,2)
63_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_mem,u_int32_t,4)
64
65struct bus_space_tag SBUS_io_space_tag = {
66	BUS_SPACE_IO,
67
68	/* direct bus access methods */
69	{
70		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int8_t,1),
71		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int16_t,2),
72		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int32_t,4),
73	},
74
75	/* relocate bus access methods */
76	{
77		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int8_t,1),
78		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int16_t,2),
79		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int32_t,4),
80	}
81};
82
83struct bus_space_tag SBUS_mem_space_tag = {
84	BUS_SPACE_MEM,
85
86	/* direct bus access methods */
87	{
88		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int8_t,1),
89		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int16_t,2),
90		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int32_t,4),
91	},
92
93	/* relocate bus access methods */
94	{
95		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int8_t,1),
96		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int16_t,2),
97		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int32_t,4),
98	}
99};
100
101
102#include "opt_mecia.h"
103#ifdef DEV_MECIA
104
105_BUS_SPACE_CALL_FUNCS_PROTO(NEPC_DA_io,u_int16_t,2)
106_BUS_SPACE_CALL_FUNCS_PROTO(NEPC_DA_io,u_int32_t,4)
107
108_BUS_SPACE_CALL_FUNCS_PROTO(NEPC_RA_io,u_int16_t,2)
109_BUS_SPACE_CALL_FUNCS_PROTO(NEPC_RA_io,u_int32_t,4)
110
111struct bus_space_tag NEPC_io_space_tag = {
112	BUS_SPACE_IO,
113
114	/* direct bus access methods */
115	{
116		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int8_t,1),
117		_BUS_SPACE_CALL_FUNCS_TAB(NEPC_DA_io,u_int16_t,2),
118		_BUS_SPACE_CALL_FUNCS_TAB(NEPC_DA_io,u_int32_t,4),
119	},
120
121	/* relocate bus access methods */
122	{
123		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int8_t,1),
124		_BUS_SPACE_CALL_FUNCS_TAB(NEPC_RA_io,u_int16_t,2),
125		_BUS_SPACE_CALL_FUNCS_TAB(NEPC_RA_io,u_int32_t,4),
126	}
127};
128
129struct bus_space_tag NEPC_mem_space_tag = {
130	BUS_SPACE_MEM,
131
132	/* direct bus access methods */
133	{
134		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int8_t,1),
135		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int16_t,2),
136		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int32_t,4),
137	},
138
139	/* relocate bus access methods */
140	{
141		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int8_t,1),
142		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int16_t,2),
143		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int32_t,4),
144	}
145};
146
147#endif /* DEV_MECIA */
148
149/*************************************************************************
150 * map init
151 *************************************************************************/
152static __inline void
153bus_space_iat_init(bus_space_handle_t bsh)
154{
155	int i;
156
157	for (i = 0; i < bsh->bsh_maxiatsz; i++)
158		bsh->bsh_iat[i] = bsh->bsh_base + i;
159}
160
161/*************************************************************************
162 * handle allocation
163 *************************************************************************/
164int
165i386_bus_space_handle_alloc(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size,
166			    bus_space_handle_t *bshp)
167{
168	bus_space_handle_t bsh;
169
170	bsh = (bus_space_handle_t) malloc(sizeof (*bsh), M_BUSSPACEHANDLE,
171					  M_NOWAIT | M_ZERO);
172	if (bsh == NULL)
173		return ENOMEM;
174
175	bsh->bsh_maxiatsz = BUS_SPACE_IAT_MAXSIZE;
176	bsh->bsh_iatsz = 0;
177	bsh->bsh_base = bpa;
178	bsh->bsh_sz = size;
179	bsh->bsh_res = NULL;
180	bsh->bsh_ressz = 0;
181	bus_space_iat_init(bsh);
182
183	bsh->bsh_bam = t->bs_da;		/* default: direct access */
184
185	*bshp = bsh;
186	return 0;
187}
188
189void
190i386_bus_space_handle_free(bus_space_tag_t t, bus_space_handle_t bsh,
191			   size_t size)
192{
193
194	free(bsh, M_BUSSPACEHANDLE);
195}
196
197/*************************************************************************
198 * map
199 *************************************************************************/
200void
201i386_memio_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
202{
203
204	i386_bus_space_handle_free(t, bsh, bsh->bsh_sz);
205}
206
207void
208i386_memio_free(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
209{
210
211	/* i386_memio_unmap() does all that we need to do. */
212	i386_memio_unmap(t, bsh, bsh->bsh_sz);
213}
214
215int
216i386_memio_subregion(bus_space_tag_t t, bus_space_handle_t pbsh,
217		     bus_size_t offset, bus_size_t size,
218		     bus_space_handle_t *tbshp)
219{
220	int i, error = 0;
221	bus_space_handle_t bsh;
222	bus_addr_t pbase;
223
224	pbase = pbsh->bsh_base + offset;
225	switch (t->bs_tag) {
226	case BUS_SPACE_IO:
227		if (pbsh->bsh_iatsz > 0) {
228			if (offset >= pbsh->bsh_iatsz ||
229			    offset + size > pbsh->bsh_iatsz)
230				return EINVAL;
231			pbase = pbsh->bsh_base;
232		}
233		break;
234
235	case BUS_SPACE_MEM:
236		if (pbsh->bsh_iatsz > 0)
237			return EINVAL;
238		if (offset > pbsh->bsh_sz || offset + size > pbsh->bsh_sz)
239			return EINVAL;
240		break;
241
242	default:
243		panic("i386_memio_subregion: bad bus space tag");
244		break;
245	}
246
247	error = i386_bus_space_handle_alloc(t, pbase, size, &bsh);
248	if (error != 0)
249		return error;
250
251	switch (t->bs_tag) {
252	case BUS_SPACE_IO:
253		if (pbsh->bsh_iatsz > 0) {
254			for (i = 0; i < size; i ++)
255				bsh->bsh_iat[i] = pbsh->bsh_iat[i + offset];
256			bsh->bsh_iatsz = size;
257		} else if (pbsh->bsh_base > bsh->bsh_base ||
258		         pbsh->bsh_base + pbsh->bsh_sz <
259		         bsh->bsh_base + bsh->bsh_sz) {
260			i386_bus_space_handle_free(t, bsh, size);
261			return EINVAL;
262		}
263		break;
264
265	case BUS_SPACE_MEM:
266		break;
267	}
268
269	if (pbsh->bsh_iatsz > 0)
270		bsh->bsh_bam = t->bs_ra;	/* relocate access */
271	*tbshp = bsh;
272	return error;
273}
274