hwtest.c 2.46 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/* Tests for presence or absence of hardware registers.
 * This code was originally in atari/config.c, but I noticed
 * that it was also in drivers/nubus/nubus.c and I wanted to
 * use it in hp300/config.c, so it seemed sensible to pull it
 * out into its own file.
 * 
 * The test is for use when trying to read a hardware register
 * that isn't present would cause a bus error. We set up a 
 * temporary handler so that this doesn't kill the kernel.
 *
 * There is a test-by-reading and a test-by-writing; I present
 * them here complete with the comments from the original atari
 * config.c...
 *                -- PMM <pmaydell@chiark.greenend.org.uk>, 05/1998
 */

/* This function tests for the presence of an address, specially a
 * hardware register address. It is called very early in the kernel
 * initialization process, when the VBR register isn't set up yet. On
 * an Atari, it still points to address 0, which is unmapped. So a bus
 * error would cause another bus error while fetching the exception
 * vector, and the CPU would do nothing at all. So we needed to set up
 * a temporary VBR and a vector table for the duration of the test.
 */

Andrew Morton's avatar
Andrew Morton committed
26 27
#include <linux/module.h>

Linus Torvalds's avatar
Linus Torvalds committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
int hwreg_present( volatile void *regp )
{
    int	ret = 0;
    long	save_sp, save_vbr;
    long	tmp_vectors[3];

    __asm__ __volatile__
	(	"movec	%/vbr,%2\n\t"
		"movel	#Lberr1,%4@(8)\n\t"
                "movec	%4,%/vbr\n\t"
		"movel	%/sp,%1\n\t"
		"moveq	#0,%0\n\t"
		"tstb	%3@\n\t"  
		"nop\n\t"
		"moveq	#1,%0\n"
                "Lberr1:\n\t"
		"movel	%1,%/sp\n\t"
		"movec	%2,%/vbr"
		: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
		: "a" (regp), "a" (tmp_vectors)
                );

    return( ret );
}
Andrew Morton's avatar
Andrew Morton committed
52
EXPORT_SYMBOL(hwreg_present);
Linus Torvalds's avatar
Linus Torvalds committed
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
  
/* Basically the same, but writes a value into a word register, protected
 * by a bus error handler. Returns 1 if successful, 0 otherwise.
 */

int hwreg_write( volatile void *regp, unsigned short val )
{
	int		ret;
	long	save_sp, save_vbr;
	long	tmp_vectors[3];

	__asm__ __volatile__
	(	"movec	%/vbr,%2\n\t"
		"movel	#Lberr2,%4@(8)\n\t"
		"movec	%4,%/vbr\n\t"
		"movel	%/sp,%1\n\t"
		"moveq	#0,%0\n\t"
		"movew	%5,%3@\n\t"  
		"nop	\n\t"	/* If this nop isn't present, 'ret' may already be
				 * loaded with 1 at the time the bus error
				 * happens! */
		"moveq	#1,%0\n"
	"Lberr2:\n\t"
		"movel	%1,%/sp\n\t"
		"movec	%2,%/vbr"
		: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
		: "a" (regp), "a" (tmp_vectors), "g" (val)
	);

	return( ret );
}
Andrew Morton's avatar
Andrew Morton committed
84
EXPORT_SYMBOL(hwreg_write);
Linus Torvalds's avatar
Linus Torvalds committed
85