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