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