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