/* $FreeBSD$ */ /* $NecBSD: busiosubr.c,v 1.30.4.4 1999/08/28 02:25:35 honda Exp $ */ /* $NetBSD$ */ /*- * [NetBSD for NEC PC-98 series] * Copyright (c) 1996, 1997, 1998 * NetBSD/pc98 porting staff. All rights reserved. * * [Ported for FreeBSD] * Copyright (c) 2001 * TAKAHASHI Yoshihiro. 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. 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. */ /* * Copyright (c) 1997, 1998 * Naofumi HONDA. All rights reserved. */ #include #include #include #include #include static MALLOC_DEFINE(M_BUSSPACEHANDLE, "busspacehandle", "Bus space handle"); _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_io,u_int8_t,1) _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_io,u_int16_t,2) _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_io,u_int32_t,4) _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_mem,u_int8_t,1) _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_mem,u_int16_t,2) _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_mem,u_int32_t,4) _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_io,u_int8_t,1) _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_io,u_int16_t,2) _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_io,u_int32_t,4) _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_mem,u_int8_t,1) _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_mem,u_int16_t,2) _BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_mem,u_int32_t,4) struct bus_space_tag SBUS_io_space_tag = { BUS_SPACE_TAG_IO, /* direct bus access methods */ { _BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int8_t,1), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int16_t,2), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int32_t,4), }, /* relocate bus access methods */ { _BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int8_t,1), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int16_t,2), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int32_t,4), } }; struct bus_space_tag SBUS_mem_space_tag = { BUS_SPACE_TAG_MEM, /* direct bus access methods */ { _BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int8_t,1), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int16_t,2), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int32_t,4), }, /* relocate bus access methods */ { _BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int8_t,1), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int16_t,2), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int32_t,4), } }; #include "opt_mecia.h" #ifdef DEV_MECIA _BUS_SPACE_CALL_FUNCS_PROTO(NEPC_DA_io,u_int16_t,2) _BUS_SPACE_CALL_FUNCS_PROTO(NEPC_DA_io,u_int32_t,4) _BUS_SPACE_CALL_FUNCS_PROTO(NEPC_RA_io,u_int16_t,2) _BUS_SPACE_CALL_FUNCS_PROTO(NEPC_RA_io,u_int32_t,4) struct bus_space_tag NEPC_io_space_tag = { BUS_SPACE_TAG_IO, /* direct bus access methods */ { _BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int8_t,1), _BUS_SPACE_CALL_FUNCS_TAB(NEPC_DA_io,u_int16_t,2), _BUS_SPACE_CALL_FUNCS_TAB(NEPC_DA_io,u_int32_t,4), }, /* relocate bus access methods */ { _BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int8_t,1), _BUS_SPACE_CALL_FUNCS_TAB(NEPC_RA_io,u_int16_t,2), _BUS_SPACE_CALL_FUNCS_TAB(NEPC_RA_io,u_int32_t,4), } }; struct bus_space_tag NEPC_mem_space_tag = { BUS_SPACE_TAG_MEM, /* direct bus access methods */ { _BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int8_t,1), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int16_t,2), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int32_t,4), }, /* relocate bus access methods */ { _BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int8_t,1), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int16_t,2), _BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int32_t,4), } }; #endif /* DEV_MECIA */ /************************************************************************* * map init *************************************************************************/ static __inline void bus_space_iat_init(bus_space_handle_t bsh) { int i; for (i = 0; i < bsh->bsh_maxiatsz; i++) bsh->bsh_iat[i] = bsh->bsh_base + i; } /************************************************************************* * handle allocation *************************************************************************/ int i386_bus_space_handle_alloc(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, bus_space_handle_t *bshp) { bus_space_handle_t bsh; bsh = (bus_space_handle_t) malloc(sizeof (*bsh), M_BUSSPACEHANDLE, M_NOWAIT | M_ZERO); if (bsh == NULL) return ENOMEM; bsh->bsh_maxiatsz = BUS_SPACE_IAT_MAXSIZE; bsh->bsh_iatsz = 0; bsh->bsh_base = bpa; bsh->bsh_sz = size; bsh->bsh_res = NULL; bsh->bsh_ressz = 0; bus_space_iat_init(bsh); bsh->bsh_bam = t->bs_da; /* default: direct access */ *bshp = bsh; return 0; } void i386_bus_space_handle_free(bus_space_tag_t t, bus_space_handle_t bsh, size_t size) { free(bsh, M_BUSSPACEHANDLE); } /************************************************************************* * map *************************************************************************/ int i386_memio_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, int flags, bus_space_handle_t *bshp) { return i386_bus_space_handle_alloc(t, bpa, size, bshp); } void i386_memio_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) { i386_bus_space_handle_free(t, bsh, bsh->bsh_sz); } void i386_memio_free(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) { /* i386_memio_unmap() does all that we need to do. */ i386_memio_unmap(t, bsh, bsh->bsh_sz); } int i386_memio_map_load(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size, bus_space_iat_t iat, u_int flags __unused) { int i; if (size > bsh->bsh_maxiatsz) { printf("i386_memio_map_load: map size too large\n"); return EINVAL; } for (i = 0; i < bsh->bsh_maxiatsz; i++) { if (i < size) bsh->bsh_iat[i] = iat[i]; else bsh->bsh_iat[i] = 0; bsh->bsh_iat[i] += bsh->bsh_base; } bsh->bsh_iatsz = size; bsh->bsh_bam = t->bs_ra; /* relocate access */ return 0; } int i386_memio_subregion(bus_space_tag_t t, bus_space_handle_t pbsh, bus_size_t offset, bus_size_t size, bus_space_handle_t *tbshp) { int i, error = 0; bus_space_handle_t bsh; bus_addr_t pbase; pbase = pbsh->bsh_base + offset; switch (t->bs_tag) { case BUS_SPACE_TAG_IO: if (pbsh->bsh_iatsz > 0) { if (offset >= pbsh->bsh_iatsz || offset + size > pbsh->bsh_iatsz) return EINVAL; pbase = pbsh->bsh_base; } break; case BUS_SPACE_TAG_MEM: if (pbsh->bsh_iatsz > 0) return EINVAL; if (offset > pbsh->bsh_sz || offset + size > pbsh->bsh_sz) return EINVAL; break; default: panic("i386_memio_subregion: bad bus space tag"); break; } error = i386_bus_space_handle_alloc(t, pbase, size, &bsh); if (error != 0) return error; switch (t->bs_tag) { case BUS_SPACE_TAG_IO: if (pbsh->bsh_iatsz > 0) { for (i = 0; i < size; i ++) bsh->bsh_iat[i] = pbsh->bsh_iat[i + offset]; bsh->bsh_iatsz = size; } else if (pbsh->bsh_base > bsh->bsh_base || pbsh->bsh_base + pbsh->bsh_sz < bsh->bsh_base + bsh->bsh_sz) { i386_bus_space_handle_free(t, bsh, size); return EINVAL; } break; case BUS_SPACE_TAG_MEM: break; } if (pbsh->bsh_iatsz > 0) bsh->bsh_bam = t->bs_ra; /* relocate access */ *tbshp = bsh; return error; } int i386_memio_compare(bus_space_tag_t t1, bus_space_handle_t bsh1, bus_space_tag_t t2, bus_space_handle_t bsh2) { int i; if (t1->bs_tag != t2->bs_tag) return (1); if (bsh1->bsh_base != bsh2->bsh_base) return (1); if (bsh1->bsh_sz != bsh2->bsh_sz) return (1); if (bsh1->bsh_bam.bs_read_1 != bsh2->bsh_bam.bs_read_1) /* XXX */ return (1); if (bsh1->bsh_iatsz != bsh2->bsh_iatsz) return (1); for (i = 0; i < bsh1->bsh_iatsz; i++) { if (bsh1->bsh_iat[i] != bsh2->bsh_iat[i]) return (1); } return (0); }