552 lines
13 KiB
C
552 lines
13 KiB
C
/* $NetBSD: autoconf.c,v 1.64 1999/06/07 20:16:10 thorpej Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1994 Christian E. Hopps
|
|
* 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. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Christian E. Hopps.
|
|
* 4. 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.
|
|
*/
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/reboot.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/device.h>
|
|
#include <sys/disklabel.h>
|
|
#include <sys/disk.h>
|
|
#include <machine/cpu.h>
|
|
#include <amiga/amiga/cfdev.h>
|
|
#include <amiga/amiga/device.h>
|
|
#include <amiga/amiga/custom.h>
|
|
|
|
void findroot __P((struct device **, int *));
|
|
void mbattach __P((struct device *, struct device *, void *));
|
|
int mbprint __P((void *, const char *));
|
|
int mbmatch __P((struct device *, struct cfdata *, void *));
|
|
|
|
int cold; /* 1 if still booting */
|
|
#include <sys/kernel.h>
|
|
|
|
u_long boot_partition;
|
|
|
|
/*
|
|
* called at boot time, configure all devices on system
|
|
*/
|
|
void
|
|
configure()
|
|
{
|
|
int s;
|
|
#ifdef DEBUG_KERNEL_START
|
|
int i;
|
|
#endif
|
|
|
|
/*
|
|
* this is the real thing baby (i.e. not console init)
|
|
*/
|
|
amiga_realconfig = 1;
|
|
#ifdef DRACO
|
|
if (is_draco()) {
|
|
*draco_intena &= ~DRIRQ_GLOBAL;
|
|
} else
|
|
#endif
|
|
custom.intena = INTF_INTEN;
|
|
s = splhigh();
|
|
|
|
if (config_rootfound("mainbus", "mainbus") == NULL)
|
|
panic("no mainbus found");
|
|
|
|
#ifdef DEBUG_KERNEL_START
|
|
printf("survived autoconf, going to enable interrupts\n");
|
|
#endif
|
|
|
|
#ifdef DRACO
|
|
if (is_draco()) {
|
|
*draco_intena |= DRIRQ_GLOBAL;
|
|
/* softints always enabled */
|
|
} else
|
|
#endif
|
|
{
|
|
custom.intena = INTF_SETCLR | INTF_INTEN;
|
|
|
|
/* also enable hardware aided software interrupts */
|
|
custom.intena = INTF_SETCLR | INTF_SOFTINT;
|
|
}
|
|
#ifdef DEBUG_KERNEL_START
|
|
for (i=splhigh(); i>=s ;i-=0x100) {
|
|
splx(i);
|
|
printf("%d...", (i>>8) & 7);
|
|
}
|
|
printf("survived interrupt enable\n");
|
|
#else
|
|
splx(s);
|
|
#endif
|
|
cold = 0;
|
|
#ifdef DEBUG_KERNEL_START
|
|
printf("survived configure...\n");
|
|
#endif
|
|
}
|
|
|
|
void
|
|
cpu_rootconf()
|
|
{
|
|
struct device *booted_device;
|
|
int booted_partition;
|
|
|
|
findroot(&booted_device, &booted_partition);
|
|
#ifdef DEBUG_KERNEL_START
|
|
printf("survived findroot()\n");
|
|
#endif
|
|
setroot(booted_device, booted_partition);
|
|
#ifdef DEBUG_KERNEL_START
|
|
printf("survived setroot()\n");
|
|
#endif
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
simple_devprint(auxp, pnp)
|
|
void *auxp;
|
|
const char *pnp;
|
|
{
|
|
return(QUIET);
|
|
}
|
|
|
|
int
|
|
matchname(fp, sp)
|
|
char *fp, *sp;
|
|
{
|
|
int len;
|
|
|
|
len = strlen(fp);
|
|
if (strlen(sp) != len)
|
|
return(0);
|
|
if (bcmp(fp, sp, len) == 0)
|
|
return(1);
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* use config_search to find appropriate device, then call that device
|
|
* directly with NULL device variable storage. A device can then
|
|
* always tell the difference betwean the real and console init
|
|
* by checking for NULL.
|
|
*/
|
|
int
|
|
amiga_config_found(pcfp, pdp, auxp, pfn)
|
|
struct cfdata *pcfp;
|
|
struct device *pdp;
|
|
void *auxp;
|
|
cfprint_t pfn;
|
|
{
|
|
struct device temp;
|
|
struct cfdata *cf;
|
|
|
|
if (amiga_realconfig)
|
|
return(config_found(pdp, auxp, pfn) != NULL);
|
|
|
|
if (pdp == NULL)
|
|
pdp = &temp;
|
|
|
|
pdp->dv_cfdata = pcfp;
|
|
if ((cf = config_search((cfmatch_t)NULL, pdp, auxp)) != NULL) {
|
|
cf->cf_attach->ca_attach(pdp, NULL, auxp);
|
|
pdp->dv_cfdata = NULL;
|
|
return(1);
|
|
}
|
|
pdp->dv_cfdata = NULL;
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* this function needs to get enough configured to do a console
|
|
* basically this means start attaching the grfxx's that support
|
|
* the console. Kinda hacky but it works.
|
|
*/
|
|
void
|
|
config_console()
|
|
{
|
|
struct cfdata *cf;
|
|
|
|
/*
|
|
* we need mainbus' cfdata.
|
|
*/
|
|
cf = config_rootsearch(NULL, "mainbus", "mainbus");
|
|
if (cf == NULL) {
|
|
panic("no mainbus");
|
|
}
|
|
/*
|
|
* delay clock calibration.
|
|
*/
|
|
amiga_config_found(cf, NULL, "clock", NULL);
|
|
|
|
/*
|
|
* internal grf.
|
|
*/
|
|
#ifdef DRACO
|
|
if (!(is_draco()))
|
|
#endif
|
|
amiga_config_found(cf, NULL, "grfcc", NULL);
|
|
/*
|
|
* zbus knows when its not for real and will
|
|
* only configure the appropriate hardware
|
|
*/
|
|
amiga_config_found(cf, NULL, "zbus", NULL);
|
|
}
|
|
|
|
/*
|
|
* mainbus driver
|
|
*/
|
|
struct cfattach mainbus_ca = {
|
|
sizeof(struct device), mbmatch, mbattach
|
|
};
|
|
|
|
int
|
|
mbmatch(pdp, cfp, auxp)
|
|
struct device *pdp;
|
|
struct cfdata *cfp;
|
|
void *auxp;
|
|
{
|
|
|
|
if (cfp->cf_unit > 0)
|
|
return(0);
|
|
/*
|
|
* We are always here
|
|
*/
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
* "find" all the things that should be there.
|
|
*/
|
|
void
|
|
mbattach(pdp, dp, auxp)
|
|
struct device *pdp, *dp;
|
|
void *auxp;
|
|
{
|
|
printf("\n");
|
|
config_found(dp, "clock", simple_devprint);
|
|
if (is_a3000() || is_a4000()) {
|
|
config_found(dp, "a34kbbc", simple_devprint);
|
|
} else
|
|
#ifdef DRACO
|
|
if (!is_draco())
|
|
#endif
|
|
{
|
|
config_found(dp, "a2kbbc", simple_devprint);
|
|
}
|
|
#ifdef DRACO
|
|
if (is_draco()) {
|
|
config_found(dp, "drbbc", simple_devprint);
|
|
config_found(dp, "kbd", simple_devprint);
|
|
config_found(dp, "drsc", simple_devprint);
|
|
config_found(dp, "drsupio", simple_devprint);
|
|
} else
|
|
#endif
|
|
{
|
|
config_found(dp, "ser", simple_devprint);
|
|
config_found(dp, "par", simple_devprint);
|
|
config_found(dp, "kbd", simple_devprint);
|
|
config_found(dp, "ms", simple_devprint);
|
|
config_found(dp, "ms", simple_devprint);
|
|
config_found(dp, "grfcc", simple_devprint);
|
|
config_found(dp, "fdc", simple_devprint);
|
|
}
|
|
if (is_a4000() || is_a1200())
|
|
config_found(dp, "idesc", simple_devprint);
|
|
if (is_a4000()) /* Try to configure A4000T SCSI */
|
|
config_found(dp, "afsc", simple_devprint);
|
|
if (is_a3000())
|
|
config_found(dp, "ahsc", simple_devprint);
|
|
#ifdef DRACO
|
|
if (!is_draco())
|
|
#endif
|
|
config_found(dp, "aucc", simple_devprint);
|
|
|
|
config_found(dp, "zbus", simple_devprint);
|
|
}
|
|
|
|
int
|
|
mbprint(auxp, pnp)
|
|
void *auxp;
|
|
const char *pnp;
|
|
{
|
|
if (pnp)
|
|
printf("%s at %s", (char *)auxp, pnp);
|
|
return(UNCONF);
|
|
}
|
|
|
|
/*
|
|
* The system will assign the "booted device" indicator (and thus
|
|
* rootdev if rootspec is wildcarded) to the first partition 'a'
|
|
* in preference of boot. However, it does walk unit backwards
|
|
* to remain compatible with the old Amiga method of picking the
|
|
* last root found.
|
|
*/
|
|
#include <sys/fcntl.h> /* XXXX and all that uses it */
|
|
#include <sys/proc.h> /* XXXX and all that uses it */
|
|
|
|
#include "fd.h"
|
|
#include "sd.h"
|
|
#include "cd.h"
|
|
|
|
#if NFD > 0
|
|
extern struct cfdriver fd_cd;
|
|
#endif
|
|
#if NSD > 0
|
|
extern struct cfdriver sd_cd;
|
|
#endif
|
|
#if NCD > 0
|
|
extern struct cfdriver cd_cd;
|
|
#endif
|
|
|
|
struct cfdriver *genericconf[] = {
|
|
#if NFD > 0
|
|
&fd_cd,
|
|
#endif
|
|
#if NSD > 0
|
|
&sd_cd,
|
|
#endif
|
|
#if NCD > 0
|
|
&cd_cd,
|
|
#endif
|
|
NULL,
|
|
};
|
|
|
|
void
|
|
findroot(devpp, partp)
|
|
struct device **devpp;
|
|
int *partp;
|
|
{
|
|
struct disk *dkp;
|
|
struct partition *pp;
|
|
struct device **devs;
|
|
int i, maj, unit;
|
|
|
|
/*
|
|
* Default to "not found".
|
|
*/
|
|
*devpp = NULL;
|
|
|
|
/* always partition 'a' */
|
|
*partp = 0;
|
|
|
|
#if NSD > 0
|
|
/*
|
|
* If we have the boot partition offset (boot_partition), try
|
|
* to locate the device corresponding to that partition.
|
|
*/
|
|
#ifdef DEBUG_KERNEL_START
|
|
printf("Boot partition offset is %ld\n", boot_partition);
|
|
#endif
|
|
if (boot_partition != 0) {
|
|
struct bdevsw *bdp;
|
|
int i;
|
|
|
|
for (unit = 0; unit < sd_cd.cd_ndevs; ++unit) {
|
|
#ifdef DEBUG_KERNEL_START
|
|
printf("probing for sd%d\n", unit);
|
|
#endif
|
|
if (sd_cd.cd_devs[unit] == NULL)
|
|
continue;
|
|
|
|
/*
|
|
* Find the disk corresponding to the current
|
|
* device.
|
|
*/
|
|
devs = (struct device **)sd_cd.cd_devs;
|
|
if ((dkp = disk_find(devs[unit]->dv_xname)) == NULL)
|
|
continue;
|
|
|
|
if (dkp->dk_driver == NULL ||
|
|
dkp->dk_driver->d_strategy == NULL)
|
|
continue;
|
|
for (bdp = bdevsw; bdp < (bdevsw + nblkdev); bdp++)
|
|
if (bdp->d_strategy ==
|
|
dkp->dk_driver->d_strategy)
|
|
break;
|
|
if (bdp->d_open(MAKEDISKDEV(4, unit, RAW_PART),
|
|
FREAD | FNONBLOCK, 0, curproc))
|
|
continue;
|
|
bdp->d_close(MAKEDISKDEV(4, unit, RAW_PART),
|
|
FREAD | FNONBLOCK, 0, curproc);
|
|
pp = &dkp->dk_label->d_partitions[0];
|
|
for (i = 0; i < dkp->dk_label->d_npartitions;
|
|
i++, pp++) {
|
|
#ifdef DEBUG_KERNEL_START
|
|
printf("sd%d%c type %d offset %d size %d\n",
|
|
unit, i+'a', pp->p_fstype,
|
|
pp->p_offset, pp->p_size);
|
|
#endif
|
|
if (pp->p_size == 0 ||
|
|
(pp->p_fstype != FS_BSDFFS &&
|
|
pp->p_fstype != FS_SWAP))
|
|
continue;
|
|
if (pp->p_offset == boot_partition) {
|
|
if (*devpp == NULL) {
|
|
*devpp = devs[unit];
|
|
*partp = i;
|
|
} else
|
|
printf("Ambiguous boot device\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (*devpp != NULL)
|
|
return; /* we found the boot device */
|
|
#endif
|
|
|
|
for (i = 0; genericconf[i] != NULL; i++) {
|
|
for (unit = genericconf[i]->cd_ndevs - 1; unit >= 0; unit--) {
|
|
if (genericconf[i]->cd_devs[unit] == NULL)
|
|
continue;
|
|
|
|
/*
|
|
* Find the disk structure corresponding to the
|
|
* current device.
|
|
*/
|
|
devs = (struct device **)genericconf[i]->cd_devs;
|
|
if ((dkp = disk_find(devs[unit]->dv_xname)) == NULL)
|
|
continue;
|
|
|
|
if (dkp->dk_driver == NULL ||
|
|
dkp->dk_driver->d_strategy == NULL)
|
|
continue;
|
|
|
|
for (maj = 0; maj < nblkdev; maj++)
|
|
if (bdevsw[maj].d_strategy ==
|
|
dkp->dk_driver->d_strategy)
|
|
break;
|
|
#ifdef DIAGNOSTIC
|
|
if (maj >= nblkdev)
|
|
panic("findroot: impossible");
|
|
#endif
|
|
|
|
/* Open disk; forces read of disklabel. */
|
|
if ((*bdevsw[maj].d_open)(MAKEDISKDEV(maj,
|
|
unit, 0), FREAD|FNONBLOCK, 0, &proc0))
|
|
continue;
|
|
(void)(*bdevsw[maj].d_close)(MAKEDISKDEV(maj,
|
|
unit, 0), FREAD|FNONBLOCK, 0, &proc0);
|
|
|
|
pp = &dkp->dk_label->d_partitions[0];
|
|
if (pp->p_size != 0 && pp->p_fstype == FS_BSDFFS) {
|
|
*devpp = devs[unit];
|
|
*partp = 0;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Try to determine, of this machine is an A3000, which has a builtin
|
|
* realtime clock and scsi controller, so that this hardware is only
|
|
* included as "configured" if this IS an A3000
|
|
*/
|
|
|
|
int a3000_flag = 1; /* patchable */
|
|
#ifdef A4000
|
|
int a4000_flag = 1; /* patchable - default to A4000 */
|
|
#else
|
|
int a4000_flag = 0; /* patchable */
|
|
#endif
|
|
|
|
int
|
|
is_a3000()
|
|
{
|
|
/* this is a dirty kludge.. but how do you do this RIGHT ? :-) */
|
|
extern long boot_fphystart;
|
|
short sc;
|
|
|
|
if ((machineid >> 16) == 3000)
|
|
return (1); /* It's an A3000 */
|
|
if (machineid >> 16)
|
|
return (0); /* It's not an A3000 */
|
|
/* Machine type is unknown, so try to guess it */
|
|
/* where is fastram on the A4000 ?? */
|
|
/* if fastram is below 0x07000000, assume it's not an A3000 */
|
|
if (boot_fphystart < 0x07000000)
|
|
return(0);
|
|
/*
|
|
* OK, fastram starts at or above 0x07000000, check specific
|
|
* machines
|
|
*/
|
|
for (sc = 0; sc < ncfdev; sc++) {
|
|
switch (cfdev[sc].rom.manid) {
|
|
case 2026: /* Progressive Peripherals, Inc */
|
|
switch (cfdev[sc].rom.prodid) {
|
|
case 0: /* PPI Mercury - A3000 */
|
|
case 1: /* PP&S A3000 '040 */
|
|
return(1);
|
|
case 150: /* PPI Zeus - it's an A2000 */
|
|
case 105: /* PP&S A2000 '040 */
|
|
case 187: /* PP&S A500 '040 */
|
|
return(0);
|
|
}
|
|
break;
|
|
|
|
case 2112: /* IVS */
|
|
switch (cfdev[sc].rom.prodid) {
|
|
case 242:
|
|
return(0); /* A2000 accelerator? */
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return (a3000_flag); /* XXX let flag tell now */
|
|
}
|
|
|
|
int
|
|
is_a4000()
|
|
{
|
|
if ((machineid >> 16) == 4000)
|
|
return (1); /* It's an A4000 */
|
|
if ((machineid >> 16) == 1200)
|
|
return (0); /* It's an A1200, so not A4000 */
|
|
#ifdef DRACO
|
|
if (is_draco())
|
|
return (0);
|
|
#endif
|
|
/* Do I need this any more? */
|
|
if ((custom.deniseid & 0xff) == 0xf8)
|
|
return (1);
|
|
#ifdef DEBUG
|
|
if (a4000_flag)
|
|
printf("Denise ID = %04x\n", (unsigned short)custom.deniseid);
|
|
#endif
|
|
if (machineid >> 16)
|
|
return (0); /* It's not an A4000 */
|
|
return (a4000_flag); /* Machine type not set */
|
|
}
|
|
|
|
int
|
|
is_a1200()
|
|
{
|
|
if ((machineid >> 16) == 1200)
|
|
return (1); /* It's an A1200 */
|
|
return (0); /* Machine type not set */
|
|
}
|