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