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