/*-
* Copyright (c) 2000, 2001, 2006 Ben Harris
* 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.
*/
/*
* sec.c -- driver for Acorn SCSI expansion cards (AKA30, AKA31, AKA32)
*
* These cards are documented in:
* Acorn Archimedes 500 series / Acorn R200 series Technical Reference Manual
* Published by Acorn Computers Limited
* ISBN 1 85250 086 7
* Part number 0486,052
* Issue 1, November 1990
*/
/* Details of the current DMA transfer */
bool sc_dmaactive;
void * sc_dmaaddr;
int sc_dmaoff;
size_t sc_dmalen;
bool sc_dmain;
/* Details of the current block within the above transfer */
size_t sc_dmablk;
};
/* Standard ROM, skipping the MCS card that used the same ID. */
if (pa->pa_product == PODULE_ACORN_SCSI &&
strncmp(pa->pa_descr, "MCS", 3) != 0)
return 1;
/*
* Before reboot, reset the page register to 0 so that RISC OS can see
* the podule ROM.
*/
static bool
sec_shutdown(device_t dev, int howto)
{
struct sec_softc *sc = device_private(dev);
sec_setpage(sc, 0);
return true;
}
static void
sec_copyin(struct sec_softc *sc, void *dest, int src, size_t size)
{
uint16_t tmp, *wptr;
int cnt, extra_byte;
KASSERT(dest >= 0);
KASSERT(dest + size <= SEC_MEMSIZE);
if (dest % 2 != 0) {
/*
* There's a stray byte at the start. Read the word
* containing it.
*/
sec_setpage(sc, dest / SEC_PAGESIZE);
tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h,
SEC_SRAM + (dest % SEC_PAGESIZE / 2));
tmp &= 0xff;
tmp |= *(uint8_t const *)src << 8;
bus_space_write_2(sc->sc_mod_t, sc->sc_mod_h,
SEC_SRAM + (dest % SEC_PAGESIZE / 2), tmp);
src = ((uint8_t const *)src) + 1;
dest++; size--;
}
KASSERT(dest % 2 == 0);
KASSERT(ALIGNED_POINTER(src, uint16_t));
wptr = src;
extra_byte = size % 2;
size -= extra_byte;
while (size > 0) {
cnt = SEC_PAGESIZE - dest % SEC_PAGESIZE;
if (cnt > size)
cnt = size;
sec_setpage(sc, dest / SEC_PAGESIZE);
/* bus ops are in words */
bus_space_write_region_2(sc->sc_mod_t, sc->sc_mod_h,
dest % SEC_PAGESIZE / 2, wptr, cnt / 2);
wptr += cnt / 2;
dest += cnt;
size -= cnt;
}
if (extra_byte) {
/*
* There's a stray byte at the end. Read the word
* containing it.
*/
sec_setpage(sc, dest / SEC_PAGESIZE);
tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h,
SEC_SRAM + (dest % SEC_PAGESIZE / 2));
tmp &= 0xff00;
tmp |= *(uint8_t const *)wptr;
bus_space_write_2(sc->sc_mod_t, sc->sc_mod_h,
SEC_SRAM + (dest % SEC_PAGESIZE / 2), tmp);
}
}
static void
sec_dmablk(struct sec_softc *sc, int blk)
{
int off;
size_t len;
KASSERT(blk >= 0);
KASSERT(blk * SEC_DMABLK < sc->sc_dmalen);
off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff;
len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK));
dmac_write(sc, NEC71071_ADDRLO, off & 0xff);
dmac_write(sc, NEC71071_ADDRMID, off >> 8);
dmac_write(sc, NEC71071_ADDRHI, 0);
/*
* "Note: The number of DMA transfer cycles is actually the
* value of the current count register + 1. Therefore, when
* programming the count register, specify the number of DMA
* transfers minus one." -- uPD71071 datasheet
*/
dmac_write(sc, NEC71071_COUNTLO, (len - 1) & 0xff);
dmac_write(sc, NEC71071_COUNTHI, (len - 1) >> 8);
}
static void
sec_copyoutblk(struct sec_softc *sc, int blk)
{
int off;
size_t len;