autoconf.c revision 1.64
1/* $NetBSD: autoconf.c,v 1.64 1999/06/07 20:16:10 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1994 Christian E. Hopps 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christian E. Hopps. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/reboot.h> 35#include <sys/conf.h> 36#include <sys/buf.h> 37#include <sys/device.h> 38#include <sys/disklabel.h> 39#include <sys/disk.h> 40#include <machine/cpu.h> 41#include <amiga/amiga/cfdev.h> 42#include <amiga/amiga/device.h> 43#include <amiga/amiga/custom.h> 44 45void findroot __P((struct device **, int *)); 46void mbattach __P((struct device *, struct device *, void *)); 47int mbprint __P((void *, const char *)); 48int mbmatch __P((struct device *, struct cfdata *, void *)); 49 50int cold; /* 1 if still booting */ 51#include <sys/kernel.h> 52 53u_long boot_partition; 54 55/* 56 * called at boot time, configure all devices on system 57 */ 58void 59configure() 60{ 61 int s; 62#ifdef DEBUG_KERNEL_START 63 int i; 64#endif 65 66 /* 67 * this is the real thing baby (i.e. not console init) 68 */ 69 amiga_realconfig = 1; 70#ifdef DRACO 71 if (is_draco()) { 72 *draco_intena &= ~DRIRQ_GLOBAL; 73 } else 74#endif 75 custom.intena = INTF_INTEN; 76 s = splhigh(); 77 78 if (config_rootfound("mainbus", "mainbus") == NULL) 79 panic("no mainbus found"); 80 81#ifdef DEBUG_KERNEL_START 82 printf("survived autoconf, going to enable interrupts\n"); 83#endif 84 85#ifdef DRACO 86 if (is_draco()) { 87 *draco_intena |= DRIRQ_GLOBAL; 88 /* softints always enabled */ 89 } else 90#endif 91 { 92 custom.intena = INTF_SETCLR | INTF_INTEN; 93 94 /* also enable hardware aided software interrupts */ 95 custom.intena = INTF_SETCLR | INTF_SOFTINT; 96 } 97#ifdef DEBUG_KERNEL_START 98 for (i=splhigh(); i>=s ;i-=0x100) { 99 splx(i); 100 printf("%d...", (i>>8) & 7); 101 } 102 printf("survived interrupt enable\n"); 103#else 104 splx(s); 105#endif 106 cold = 0; 107#ifdef DEBUG_KERNEL_START 108 printf("survived configure...\n"); 109#endif 110} 111 112void 113cpu_rootconf() 114{ 115 struct device *booted_device; 116 int booted_partition; 117 118 findroot(&booted_device, &booted_partition); 119#ifdef DEBUG_KERNEL_START 120 printf("survived findroot()\n"); 121#endif 122 setroot(booted_device, booted_partition); 123#ifdef DEBUG_KERNEL_START 124 printf("survived setroot()\n"); 125#endif 126} 127 128/*ARGSUSED*/ 129int 130simple_devprint(auxp, pnp) 131 void *auxp; 132 const char *pnp; 133{ 134 return(QUIET); 135} 136 137int 138matchname(fp, sp) 139 char *fp, *sp; 140{ 141 int len; 142 143 len = strlen(fp); 144 if (strlen(sp) != len) 145 return(0); 146 if (bcmp(fp, sp, len) == 0) 147 return(1); 148 return(0); 149} 150 151/* 152 * use config_search to find appropriate device, then call that device 153 * directly with NULL device variable storage. A device can then 154 * always tell the difference betwean the real and console init 155 * by checking for NULL. 156 */ 157int 158amiga_config_found(pcfp, pdp, auxp, pfn) 159 struct cfdata *pcfp; 160 struct device *pdp; 161 void *auxp; 162 cfprint_t pfn; 163{ 164 struct device temp; 165 struct cfdata *cf; 166 167 if (amiga_realconfig) 168 return(config_found(pdp, auxp, pfn) != NULL); 169 170 if (pdp == NULL) 171 pdp = &temp; 172 173 pdp->dv_cfdata = pcfp; 174 if ((cf = config_search((cfmatch_t)NULL, pdp, auxp)) != NULL) { 175 cf->cf_attach->ca_attach(pdp, NULL, auxp); 176 pdp->dv_cfdata = NULL; 177 return(1); 178 } 179 pdp->dv_cfdata = NULL; 180 return(0); 181} 182 183/* 184 * this function needs to get enough configured to do a console 185 * basically this means start attaching the grfxx's that support 186 * the console. Kinda hacky but it works. 187 */ 188void 189config_console() 190{ 191 struct cfdata *cf; 192 193 /* 194 * we need mainbus' cfdata. 195 */ 196 cf = config_rootsearch(NULL, "mainbus", "mainbus"); 197 if (cf == NULL) { 198 panic("no mainbus"); 199 } 200 /* 201 * delay clock calibration. 202 */ 203 amiga_config_found(cf, NULL, "clock", NULL); 204 205 /* 206 * internal grf. 207 */ 208#ifdef DRACO 209 if (!(is_draco())) 210#endif 211 amiga_config_found(cf, NULL, "grfcc", NULL); 212 /* 213 * zbus knows when its not for real and will 214 * only configure the appropriate hardware 215 */ 216 amiga_config_found(cf, NULL, "zbus", NULL); 217} 218 219/* 220 * mainbus driver 221 */ 222struct cfattach mainbus_ca = { 223 sizeof(struct device), mbmatch, mbattach 224}; 225 226int 227mbmatch(pdp, cfp, auxp) 228 struct device *pdp; 229 struct cfdata *cfp; 230 void *auxp; 231{ 232 233 if (cfp->cf_unit > 0) 234 return(0); 235 /* 236 * We are always here 237 */ 238 return(1); 239} 240 241/* 242 * "find" all the things that should be there. 243 */ 244void 245mbattach(pdp, dp, auxp) 246 struct device *pdp, *dp; 247 void *auxp; 248{ 249 printf("\n"); 250 config_found(dp, "clock", simple_devprint); 251 if (is_a3000() || is_a4000()) { 252 config_found(dp, "a34kbbc", simple_devprint); 253 } else 254#ifdef DRACO 255 if (!is_draco()) 256#endif 257 { 258 config_found(dp, "a2kbbc", simple_devprint); 259 } 260#ifdef DRACO 261 if (is_draco()) { 262 config_found(dp, "drbbc", simple_devprint); 263 config_found(dp, "kbd", simple_devprint); 264 config_found(dp, "drsc", simple_devprint); 265 config_found(dp, "drsupio", simple_devprint); 266 } else 267#endif 268 { 269 config_found(dp, "ser", simple_devprint); 270 config_found(dp, "par", simple_devprint); 271 config_found(dp, "kbd", simple_devprint); 272 config_found(dp, "ms", simple_devprint); 273 config_found(dp, "ms", simple_devprint); 274 config_found(dp, "grfcc", simple_devprint); 275 config_found(dp, "fdc", simple_devprint); 276 } 277 if (is_a4000() || is_a1200()) 278 config_found(dp, "idesc", simple_devprint); 279 if (is_a4000()) /* Try to configure A4000T SCSI */ 280 config_found(dp, "afsc", simple_devprint); 281 if (is_a3000()) 282 config_found(dp, "ahsc", simple_devprint); 283#ifdef DRACO 284 if (!is_draco()) 285#endif 286 config_found(dp, "aucc", simple_devprint); 287 288 config_found(dp, "zbus", simple_devprint); 289} 290 291int 292mbprint(auxp, pnp) 293 void *auxp; 294 const char *pnp; 295{ 296 if (pnp) 297 printf("%s at %s", (char *)auxp, pnp); 298 return(UNCONF); 299} 300 301/* 302 * The system will assign the "booted device" indicator (and thus 303 * rootdev if rootspec is wildcarded) to the first partition 'a' 304 * in preference of boot. However, it does walk unit backwards 305 * to remain compatible with the old Amiga method of picking the 306 * last root found. 307 */ 308#include <sys/fcntl.h> /* XXXX and all that uses it */ 309#include <sys/proc.h> /* XXXX and all that uses it */ 310 311#include "fd.h" 312#include "sd.h" 313#include "cd.h" 314 315#if NFD > 0 316extern struct cfdriver fd_cd; 317#endif 318#if NSD > 0 319extern struct cfdriver sd_cd; 320#endif 321#if NCD > 0 322extern struct cfdriver cd_cd; 323#endif 324 325struct cfdriver *genericconf[] = { 326#if NFD > 0 327 &fd_cd, 328#endif 329#if NSD > 0 330 &sd_cd, 331#endif 332#if NCD > 0 333 &cd_cd, 334#endif 335 NULL, 336}; 337 338void 339findroot(devpp, partp) 340 struct device **devpp; 341 int *partp; 342{ 343 struct disk *dkp; 344 struct partition *pp; 345 struct device **devs; 346 int i, maj, unit; 347 348 /* 349 * Default to "not found". 350 */ 351 *devpp = NULL; 352 353 /* always partition 'a' */ 354 *partp = 0; 355 356#if NSD > 0 357 /* 358 * If we have the boot partition offset (boot_partition), try 359 * to locate the device corresponding to that partition. 360 */ 361#ifdef DEBUG_KERNEL_START 362 printf("Boot partition offset is %ld\n", boot_partition); 363#endif 364 if (boot_partition != 0) { 365 struct bdevsw *bdp; 366 int i; 367 368 for (unit = 0; unit < sd_cd.cd_ndevs; ++unit) { 369#ifdef DEBUG_KERNEL_START 370 printf("probing for sd%d\n", unit); 371#endif 372 if (sd_cd.cd_devs[unit] == NULL) 373 continue; 374 375 /* 376 * Find the disk corresponding to the current 377 * device. 378 */ 379 devs = (struct device **)sd_cd.cd_devs; 380 if ((dkp = disk_find(devs[unit]->dv_xname)) == NULL) 381 continue; 382 383 if (dkp->dk_driver == NULL || 384 dkp->dk_driver->d_strategy == NULL) 385 continue; 386 for (bdp = bdevsw; bdp < (bdevsw + nblkdev); bdp++) 387 if (bdp->d_strategy == 388 dkp->dk_driver->d_strategy) 389 break; 390 if (bdp->d_open(MAKEDISKDEV(4, unit, RAW_PART), 391 FREAD | FNONBLOCK, 0, curproc)) 392 continue; 393 bdp->d_close(MAKEDISKDEV(4, unit, RAW_PART), 394 FREAD | FNONBLOCK, 0, curproc); 395 pp = &dkp->dk_label->d_partitions[0]; 396 for (i = 0; i < dkp->dk_label->d_npartitions; 397 i++, pp++) { 398#ifdef DEBUG_KERNEL_START 399 printf("sd%d%c type %d offset %d size %d\n", 400 unit, i+'a', pp->p_fstype, 401 pp->p_offset, pp->p_size); 402#endif 403 if (pp->p_size == 0 || 404 (pp->p_fstype != FS_BSDFFS && 405 pp->p_fstype != FS_SWAP)) 406 continue; 407 if (pp->p_offset == boot_partition) { 408 if (*devpp == NULL) { 409 *devpp = devs[unit]; 410 *partp = i; 411 } else 412 printf("Ambiguous boot device\n"); 413 } 414 } 415 } 416 } 417 if (*devpp != NULL) 418 return; /* we found the boot device */ 419#endif 420 421 for (i = 0; genericconf[i] != NULL; i++) { 422 for (unit = genericconf[i]->cd_ndevs - 1; unit >= 0; unit--) { 423 if (genericconf[i]->cd_devs[unit] == NULL) 424 continue; 425 426 /* 427 * Find the disk structure corresponding to the 428 * current device. 429 */ 430 devs = (struct device **)genericconf[i]->cd_devs; 431 if ((dkp = disk_find(devs[unit]->dv_xname)) == NULL) 432 continue; 433 434 if (dkp->dk_driver == NULL || 435 dkp->dk_driver->d_strategy == NULL) 436 continue; 437 438 for (maj = 0; maj < nblkdev; maj++) 439 if (bdevsw[maj].d_strategy == 440 dkp->dk_driver->d_strategy) 441 break; 442#ifdef DIAGNOSTIC 443 if (maj >= nblkdev) 444 panic("findroot: impossible"); 445#endif 446 447 /* Open disk; forces read of disklabel. */ 448 if ((*bdevsw[maj].d_open)(MAKEDISKDEV(maj, 449 unit, 0), FREAD|FNONBLOCK, 0, &proc0)) 450 continue; 451 (void)(*bdevsw[maj].d_close)(MAKEDISKDEV(maj, 452 unit, 0), FREAD|FNONBLOCK, 0, &proc0); 453 454 pp = &dkp->dk_label->d_partitions[0]; 455 if (pp->p_size != 0 && pp->p_fstype == FS_BSDFFS) { 456 *devpp = devs[unit]; 457 *partp = 0; 458 return; 459 } 460 } 461 } 462} 463 464/* 465 * Try to determine, of this machine is an A3000, which has a builtin 466 * realtime clock and scsi controller, so that this hardware is only 467 * included as "configured" if this IS an A3000 468 */ 469 470int a3000_flag = 1; /* patchable */ 471#ifdef A4000 472int a4000_flag = 1; /* patchable - default to A4000 */ 473#else 474int a4000_flag = 0; /* patchable */ 475#endif 476 477int 478is_a3000() 479{ 480 /* this is a dirty kludge.. but how do you do this RIGHT ? :-) */ 481 extern long boot_fphystart; 482 short sc; 483 484 if ((machineid >> 16) == 3000) 485 return (1); /* It's an A3000 */ 486 if (machineid >> 16) 487 return (0); /* It's not an A3000 */ 488 /* Machine type is unknown, so try to guess it */ 489 /* where is fastram on the A4000 ?? */ 490 /* if fastram is below 0x07000000, assume it's not an A3000 */ 491 if (boot_fphystart < 0x07000000) 492 return(0); 493 /* 494 * OK, fastram starts at or above 0x07000000, check specific 495 * machines 496 */ 497 for (sc = 0; sc < ncfdev; sc++) { 498 switch (cfdev[sc].rom.manid) { 499 case 2026: /* Progressive Peripherals, Inc */ 500 switch (cfdev[sc].rom.prodid) { 501 case 0: /* PPI Mercury - A3000 */ 502 case 1: /* PP&S A3000 '040 */ 503 return(1); 504 case 150: /* PPI Zeus - it's an A2000 */ 505 case 105: /* PP&S A2000 '040 */ 506 case 187: /* PP&S A500 '040 */ 507 return(0); 508 } 509 break; 510 511 case 2112: /* IVS */ 512 switch (cfdev[sc].rom.prodid) { 513 case 242: 514 return(0); /* A2000 accelerator? */ 515 } 516 break; 517 } 518 } 519 return (a3000_flag); /* XXX let flag tell now */ 520} 521 522int 523is_a4000() 524{ 525 if ((machineid >> 16) == 4000) 526 return (1); /* It's an A4000 */ 527 if ((machineid >> 16) == 1200) 528 return (0); /* It's an A1200, so not A4000 */ 529#ifdef DRACO 530 if (is_draco()) 531 return (0); 532#endif 533 /* Do I need this any more? */ 534 if ((custom.deniseid & 0xff) == 0xf8) 535 return (1); 536#ifdef DEBUG 537 if (a4000_flag) 538 printf("Denise ID = %04x\n", (unsigned short)custom.deniseid); 539#endif 540 if (machineid >> 16) 541 return (0); /* It's not an A4000 */ 542 return (a4000_flag); /* Machine type not set */ 543} 544 545int 546is_a1200() 547{ 548 if ((machineid >> 16) == 1200) 549 return (1); /* It's an A1200 */ 550 return (0); /* Machine type not set */ 551} 552