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