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