|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: /* Copyright (c) 1991 NeXT Computer, Inc. All rights reserved. ! 25: * ! 26: * ConfigScan.c - routines to scan physical devices and start up drivers. ! 27: * ! 28: * HISTORY ! 29: * 14-Apr-91 Doug Mitchell at NeXT ! 30: * Created. ! 31: */ ! 32: ! 33: #import <bsd/sys/types.h> ! 34: #import <bsd/libc.h> ! 35: #import <mach/mach_types.h> ! 36: #import <driverkit/userConfigServer.h> ! 37: #import "ConfigPrivate.h" ! 38: #import "ConfigUtils.h" ! 39: #import "ConfigScan.h" ! 40: #import "ConfigUfs.h" ! 41: #import <mach/kern_return.h> ! 42: #import <mach/mach.h> ! 43: #import <mach/mach_error.h> ! 44: #import <kernserv/queue.h> ! 45: #import <bsd/sys/dir.h> ! 46: #import <servers/bootstrap.h> ! 47: #import <driverkit/generalFuncs.h> ! 48: #import <mach/mig_errors.h> ! 49: /* ! 50: * Main device scan function. ! 51: * ! 52: * Search thru all hardware devices. Map devices onto driver_entry's and ! 53: * dev_entry's. Launch all drivers. ! 54: * ! 55: * Also used to scan for a driver of one particular deviceType and slotId ! 56: * if scan_type is SCAN_ONE. ! 57: */ ! 58: IOConfigReturn config_scan( ! 59: scan_t scan_type, ! 60: IOSlotId slot_id_arg, ! 61: IODeviceType dev_type_arg) ! 62: { ! 63: IOReturn drtn; ! 64: IODeviceNumber dev_number; ! 65: IOSlotId slot_id; ! 66: IODeviceType dev_type; ! 67: dev_entry_t *dev_entry; ! 68: driver_entry_t *driver_entry; ! 69: filename_t filename; ! 70: file_id_t fid; ! 71: IOConfigReturn crtn; ! 72: BOOL in_use; ! 73: ! 74: xpr_common("config_scan\n", 1,2,3,4,5); ! 75: ! 76: if(scan_type == SCAN_ONE) { ! 77: crtn = IO_CNF_NOT_FOUND; // until we find it ! 78: } ! 79: else { ! 80: crtn = IO_CNF_SUCCESS; // can't fail ! 81: } ! 82: ! 83: /* ! 84: * First create driver_list. We scan all of the devices before ! 85: * exec'ing any drivers to ensure that a driver has access to all of ! 86: * its appropriate dev_ports when it is exec'd. ! 87: * ! 88: * Note that we hold driver_list_lock through this whole block; ! 89: * if this is the initial config loop, no drivers will have been ! 90: * started yet. ! 91: */ ! 92: dev_number = 0; ! 93: get_driver_list_lock(); ! 94: do { ! 95: drtn = _IOLookupByDeviceNumber(device_master_port, ! 96: dev_number, ! 97: &slot_id, ! 98: &dev_type, ! 99: &in_use); ! 100: if(drtn) { ! 101: xpr_common("config_scan: _IOLookupByDeviceNumber " ! 102: "returned " ! 103: "%s\n", IOFindNameForValue(drtn, dev_returns), ! 104: 2,3,4,5); ! 105: if(drtn == MIG_BAD_ID) { ! 106: printf("_IOLookupByObjectNumber() not " ! 107: "supported on " ! 108: "this machine; Config aborting\n"); ! 109: exit(1); ! 110: } ! 111: goto next_dev_num; ! 112: } ! 113: if(in_use) ! 114: goto next_dev_num; ! 115: if(dev_type == IO_NULL_DEVICE_TYPE) ! 116: goto next_dev_num; ! 117: if(scan_type == SCAN_ONE) { ! 118: if((dev_type != dev_type_arg) || ! 119: (slot_id != slot_id_arg)) ! 120: goto next_dev_num; ! 121: } ! 122: ! 123: /* ! 124: * Looks like a valid device. Do we already have a driver ! 125: * mapping for it? ! 126: */ ! 127: driver_entry = get_driver_entry(SK_DEVNUM, ! 128: PORT_NULL, ! 129: dev_number, ! 130: FID_NULL, ! 131: IO_NULL_DEVICE_TYPE, ! 132: IO_NULL_SLOT_ID, ! 133: &dev_entry); ! 134: if(driver_entry) { ! 135: xpr_common("config_scan: dev_num %d already mapped\n", ! 136: dev_number, 2,3,4,5); ! 137: goto next_dev_num; ! 138: } ! 139: else { ! 140: xpr_common("config_scan: NEW device\n", 1,2,3,4,5); ! 141: xpr_common(" dev_num %d dev_type 0x%x slot_id " ! 142: "0x%x\n", dev_number, dev_type, slot_id, 4,5); ! 143: } ! 144: ! 145: /* ! 146: * Get an executable for this device. ! 147: */ ! 148: if(!get_driver_file(dev_type, slot_id, &filename, &fid)) { ! 149: goto next_dev_num; ! 150: } ! 151: ! 152: /* ! 153: * We have a driver for this device. See if this driver is ! 154: * an alias (link) to a driver we already know about. ! 155: */ ! 156: driver_entry = get_driver_entry(SK_FID, ! 157: PORT_NULL, ! 158: DEV_NUM_NULL, ! 159: fid, ! 160: IO_NULL_DEVICE_TYPE, ! 161: IO_NULL_SLOT_ID, ! 162: &dev_entry); ! 163: if(driver_entry == NULL) { ! 164: ! 165: /* ! 166: * create a new driver_entry. ! 167: */ ! 168: driver_entry = create_driver_entry(fid, filename); ! 169: if(driver_entry == NULL) { ! 170: /* huh? */ ! 171: goto next_dev_num; ! 172: } ! 173: } ! 174: ! 175: /* ! 176: * Add this device to the driver. We're either adding a new ! 177: * device to an existing driver or adding the first ! 178: * device. ! 179: * ! 180: * Note that an existing dev_entry in the driver_entry ! 181: * matching this slot_id and dev_type is OK (we don't ! 182: * check for it); this would be a "multiple devices of ! 183: * same type" configuration. We need a port for each one. ! 184: */ ! 185: dev_entry = create_dev_entry(driver_entry, ! 186: dev_number, ! 187: dev_type, ! 188: slot_id); ! 189: ! 190: next_dev_num: ! 191: dev_number++; ! 192: } while(drtn != IO_R_NO_DEVICE); ! 193: release_driver_list_lock(); ! 194: ! 195: /* ! 196: * exec new drivers. We have to periodically give server_loop() a ! 197: * crack at executing driver_register() and driver_delete() calls. ! 198: * Unfortunately, a driver_delete() can cause us great hassle unless ! 199: * we're really careful and not hold on to any driver_entry's while ! 200: * we're not holding the lock. So we scan from the start of ! 201: * driver_list each time thru the loop, looking for the first ! 202: * non-running driver. ! 203: * ! 204: * If this is a SCAN_ONE operation, this should go really quickly... ! 205: * I don't think there is any way any more than one driver could ! 206: * be in a "not running" state. ! 207: */ ! 208: do { ! 209: get_driver_list_lock(); ! 210: driver_entry = (driver_entry_t *)queue_first(&driver_list); ! 211: while(!queue_end(&driver_list, (queue_t)driver_entry)) { ! 212: if(!driver_entry->running) { ! 213: if(exec_driver(driver_entry) == IO_CNF_SUCCESS) ! 214: crtn = IO_CNF_SUCCESS; ! 215: else { ! 216: /* ! 217: * Couldn't exec this driver. Remove ! 218: * from driver_list. ! 219: */ ! 220: free_driver_entry(driver_entry); ! 221: } ! 222: break; ! 223: } ! 224: driver_entry = ! 225: (driver_entry_t *)driver_entry->link.next; ! 226: } ! 227: ! 228: /* ! 229: * Either got to the end of the queue or started a ! 230: * non-running driver. End of queue means we're done (we ! 231: * started up all drivers). Otherwise, go back to the ! 232: * head of the queue. ! 233: */ ! 234: if(queue_end(&driver_list, (queue_t)driver_entry)) ! 235: break; ! 236: release_driver_list_lock(); ! 237: } while(!queue_end(&driver_list, (queue_t)driver_entry)); ! 238: release_driver_list_lock(); ! 239: xpr_common("config_scan returning %s\n", ! 240: IOFindNameForValue(crtn, config_returns), 2,3,4,5); ! 241: return(crtn); ! 242: } ! 243: ! 244: /* ! 245: * Start up or restart a driver. Place all necessary ports in the driver's ! 246: * bootstrap namespace. If driver_entry->running is TRUE, this is ! 247: * a restart; we have to clean up the (now useless) bootstrap port which ! 248: * the deceased driver used. ! 249: */ ! 250: IOConfigReturn exec_driver( ! 251: driver_entry_t *driver_entry) ! 252: { ! 253: kern_return_t krtn; ! 254: port_t old_bootstrap_port; ! 255: port_t subset_port; ! 256: dev_entry_t *dev_entry; ! 257: filename_t portname; ! 258: filename_t exec_name; ! 259: int pid; ! 260: ! 261: xpr_common("exec_driver: filename %s\n", ! 262: IOCopyString(driver_entry->filename), 2,3,4,5); ! 263: sprintf(exec_name, "%s/%s", DRIVER_PATH, driver_entry->filename); ! 264: if(driver_entry->running) { ! 265: /* ! 266: * Kill off dead driver's bootstrap and signature ports. ! 267: */ ! 268: xpr_common(" ...deleting requestor and sig ports\n", ! 269: 1,2,3,4,5); ! 270: krtn = port_deallocate(task_self(), ! 271: driver_entry->boot_requestor); ! 272: if(krtn) { ! 273: xpr_err("exec_driver: port_deallocate(): %s\n", ! 274: mach_error_string(krtn), 2,3,4,5); ! 275: } ! 276: krtn = port_deallocate(task_self(), ! 277: driver_entry->driver_sig_port); ! 278: if(krtn) { ! 279: xpr_err("exec_driver: port_deallocate(): %s\n", ! 280: mach_error_string(krtn), 2,3,4,5); ! 281: } ! 282: driver_entry->running = FALSE; ! 283: } ! 284: ! 285: /* ! 286: * Set up a signature port for authentication. ! 287: */ ! 288: krtn = port_allocate(task_self(), &driver_entry->driver_sig_port); ! 289: if(krtn) { ! 290: xpr_err("exec_driver: port_allocate(): %s\n", ! 291: mach_error_string(krtn), 2,3,4,5); ! 292: return(IO_CNF_RESOURCE); ! 293: } ! 294: ! 295: /* ! 296: * Set up a bootstrap subset port for the driver task. Its lifetime ! 297: * will be the lifetime of driver_entry->boot_requestor. ! 298: */ ! 299: krtn = port_allocate(task_self(), &driver_entry->boot_requestor); ! 300: if(krtn) { ! 301: xpr_err("exec_driver: port_allocate(): %s\n", ! 302: mach_error_string(krtn), 2,3,4,5); ! 303: return(IO_CNF_RESOURCE); ! 304: } ! 305: krtn = bootstrap_subset(bootstrap_port, ! 306: driver_entry->boot_requestor, /* requestor */ ! 307: &subset_port); ! 308: if(krtn) { ! 309: xpr_err("exec_driver: bootstrap_subset() returned %d\n", ! 310: krtn, 2,3,4,5); ! 311: return(IO_CNF_RESOURCE); ! 312: } ! 313: ! 314: /* ! 315: * Advertise the following on the bootstrap subset port: ! 316: * -- dev_port for each of this driver's dev_entry's ! 317: * -- driver_sig_port ! 318: */ ! 319: xpr_common("exec_driver: adding port driver_sig_port\n", 1,2,3,4,5); ! 320: krtn = bootstrap_register(subset_port, ! 321: SIG_PORT_NAME, ! 322: driver_entry->driver_sig_port); ! 323: if(krtn) { ! 324: xpr_err("exec_driver: bootstrap_register(): %s\n", ! 325: mach_error_string(krtn), 2,3,4,5); ! 326: return(IO_CNF_RESOURCE); ! 327: } ! 328: dev_entry = (dev_entry_t *)queue_first(&driver_entry->dev_list); ! 329: while(!queue_end(&driver_entry->dev_list, (queue_t)dev_entry)) { ! 330: sprintf(portname, "dev_port_%u", dev_entry->dev_number); ! 331: xpr_common("exec_driver: adding port %s\n", ! 332: IOCopyString(portname), 2,3,4,5); ! 333: krtn = bootstrap_register(subset_port, ! 334: portname, ! 335: dev_entry->dev_port); ! 336: if(krtn) { ! 337: printf("OOPS\n"); ! 338: xpr_err("exec_driver: bootstrap_register(%s): %s\n", ! 339: IOCopyString(portname), ! 340: mach_error_string(krtn), ! 341: 3,4,5); ! 342: xpr_err(" filename %s dev_number %d dev_port %d\n", ! 343: IOCopyString(driver_entry->filename), ! 344: dev_entry->dev_number, dev_entry->dev_port, ! 345: 4,5); ! 346: #ifdef DEBUG ! 347: log_boot_servers(subset_port); ! 348: #endif DEBUG ! 349: return(IO_CNF_RESOURCE); ! 350: } ! 351: dev_entry = (dev_entry_t *)dev_entry->link.next; ! 352: } ! 353: ! 354: /* ! 355: * OK, set out bootstrap port to the subset port, and fork off the ! 356: * driver. Then restore our task's bootstrap_port. Note ! 357: * "bootstrap_port" is a crufty mach global. ! 358: */ ! 359: old_bootstrap_port = bootstrap_port; ! 360: krtn = task_set_bootstrap_port(task_self(), subset_port); ! 361: if(krtn) { ! 362: xpr_err("exec_driver: task_set_bootstrap_port(): %s\n", ! 363: mach_error_string(krtn), 2,3,4,5); ! 364: return(IO_CNF_RESOURCE); ! 365: } ! 366: bootstrap_port = subset_port; ! 367: driver_entry->running = TRUE; ! 368: if((pid = fork()) == 0) { ! 369: printf("...forking off %s\n", exec_name); ! 370: execl(exec_name, exec_name, NULL); ! 371: /* ! 372: * FIXME: what do we do here? Should get rid of driver_entry, ! 373: * but we've already forked! Currently we have no way to ! 374: * do this without looking up our device ports with ! 375: * the bootstrap server, registering via IORegisterDriver(), ! 376: * then calling IODeleteDriver(). What a pain. Let's skip ! 377: * it for now; developers can use configutil -t to clean ! 378: * up. ! 379: */ ! 380: perror("execl"); ! 381: xpr_err("Config: execl(%s) FAILED\n", ! 382: IOCopyString(exec_name), 2,3,4,5); ! 383: exit(1); ! 384: } ! 385: ! 386: /* ! 387: * Back to our old self. ! 388: */ ! 389: bootstrap_port = old_bootstrap_port; ! 390: krtn = task_set_bootstrap_port(task_self(), old_bootstrap_port); ! 391: if(krtn) { ! 392: xpr_err("exec_driver: task_set_bootstrap_port(): %s\n", ! 393: mach_error_string(krtn), 2,3,4,5); ! 394: } ! 395: return(IO_CNF_SUCCESS); ! 396: } ! 397: ! 398: #ifdef DEBUG ! 399: void log_boot_servers(port_t boot_port) ! 400: { ! 401: u_int i; ! 402: name_array_t service_names; ! 403: unsigned int service_cnt; ! 404: name_array_t server_names; ! 405: unsigned int server_cnt; ! 406: bool_array_t service_active; ! 407: unsigned int service_active_cnt; ! 408: kern_return_t krtn; ! 409: ! 410: krtn = bootstrap_info(boot_port, ! 411: &service_names, ! 412: &service_cnt, ! 413: &server_names, ! 414: &server_cnt, ! 415: &service_active, ! 416: &service_active_cnt); ! 417: if (krtn != BOOTSTRAP_SUCCESS) ! 418: printf("ERROR: info failed: %d", krtn); ! 419: else { ! 420: printf("log_boot_server: service_cnt = %d\n", service_cnt); ! 421: for (i = 0; i < service_cnt; i++) ! 422: printf("Name: %-15s Server: %-15s " ! 423: "Active: %-4s", ! 424: service_names[i], ! 425: server_names[i][0] == '\0' ? ! 426: "Unknown" : server_names[i], ! 427: service_active[i] ? "Yes\n" : "No\n"); ! 428: } ! 429: } ! 430: #endif DEBUG ! 431: ! 432: /* ! 433: * Extract revision from a filename_t. Returns 0 if OK, -1 on error (i.e., ! 434: * illegal filename format). This is (and should remain) file system ! 435: * independent - internally, we use filename_t's exclusively. ! 436: */ ! 437: int get_driver_rev( ! 438: filename_t filename, ! 439: unsigned short *revision) ! 440: { ! 441: char rev_string[9]; ! 442: unsigned int rev; ! 443: int bar[3]; /* position of underbars */ ! 444: int digit; ! 445: int bar_num = 0; ! 446: int rev_length; ! 447: ! 448: /* ! 449: * We're pretty strict about the format.... ! 450: * ! 451: * devr_<DEV_INDEX>_<REVISION>_<human_readable_name> ! 452: * ...or... ! 453: * devs_<SLOT_ID>_<REVISION>_<human_readable_name> ! 454: * ! 455: * This routine returns <REVISION> as a binary number (assuming that ! 456: * in the filename it's in ASCII hex). ! 457: */ ! 458: bar[0] = bar[1] = bar[2] = -1; ! 459: for(digit=0; digit<FILENAME_SIZE; digit++) { ! 460: if(filename[digit] == '_') { ! 461: bar[bar_num++] = digit; ! 462: if(bar_num == 3) ! 463: break; ! 464: } ! 465: if(filename[digit] == '\0') ! 466: break; ! 467: } ! 468: ! 469: /* ! 470: * Verify proper filename format. ! 471: */ ! 472: if(bar_num != 3) ! 473: return(-1); ! 474: rev_length = bar[2] - bar[1] - 1; ! 475: if((rev_length > 8) || (rev_length == 0)) ! 476: return(-1); ! 477: strncpy(rev_string, &filename[bar[1]+1], rev_length); ! 478: rev_string[rev_length] = '\0'; ! 479: rev = atoh(rev_string); ! 480: xpr_common("get_driver_rev(%s) returning 0x%x\n", ! 481: IOCopyString(filename), rev, 3,4,5); ! 482: *revision = rev; ! 483: return(0); ! 484: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.