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