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