|
|
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: * Config.c - Config server. ! 27: * ! 28: * HISTORY ! 29: * 11-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 <driverkit/generalFuncs.h> ! 38: #import "ConfigPrivate.h" ! 39: #import "ConfigUtils.h" ! 40: #import "ConfigScan.h" ! 41: #import <mach/kern_return.h> ! 42: #import <mach/mach.h> ! 43: #import <servers/netname.h> ! 44: #import <mach/message.h> ! 45: #import <mach/mach_error.h> ! 46: #import <mach/cthreads.h> ! 47: #import <kernserv/queue.h> ! 48: #import <mach/notify.h> ! 49: #import <syslog.h> ! 50: #ifdef DEBUG ! 51: #import "ConfigUfs.h" ! 52: #endif DEBUG ! 53: ! 54: /* ! 55: * prototypes for private functions. ! 56: */ ! 57: static void usage(char **argv); ! 58: static void server_loop(); ! 59: boolean_t Config_server(msg_header_t *inp, msg_header_t *outp); ! 60: static void config_port_death(msg_header_t *inp); ! 61: ! 62: /* ! 63: * Static variables. ! 64: */ ! 65: static port_t config_port; // we advertise this for all takers ! 66: static port_set_name_t config_port_set; // the set on which we listen ! 67: port_t device_master_port; // used to communicate with kernel ! 68: port_t notify_port; // that's ours ! 69: static boolean_t config_in_progress; // prevents hazardous operations ! 70: // during initial config ! 71: queue_head_t driver_list; // list of driver_entry_t's ! 72: mutex_t driver_list_lock; // protects driver_list during initial ! 73: // config ! 74: condition_t driver_list_cond; ! 75: boolean_t driver_list_locked; ! 76: ! 77: extern port_t device_master_self(); ! 78: ! 79: /* ! 80: * User-specified variables. ! 81: */ ! 82: int verbose = 0; ! 83: ! 84: void main(int argc, char **argv) ! 85: { ! 86: int arg; ! 87: kern_return_t krtn; ! 88: cthread_t server_thread; ! 89: ! 90: if(argc < 1) ! 91: usage(argv); ! 92: for(arg=1; arg<argc; arg++) { ! 93: switch(argv[arg][0]) { ! 94: case 'v': ! 95: verbose++; ! 96: break; ! 97: default: ! 98: usage(argv); ! 99: } ! 100: } ! 101: ! 102: #ifdef DDM_DEBUG ! 103: IOInitDDM(200, "ConfigXpr"); ! 104: IOSetDDMMask(XPR_CONFIG_INDEX, ! 105: XPR_CONFIG | XPR_SERVER | XPR_COMMON | XPR_ERR); ! 106: #endif DDM_DEBUG ! 107: ! 108: /* ! 109: * Initialize global state. ! 110: */ ! 111: queue_init(&driver_list); ! 112: driver_list_lock = mutex_alloc(); ! 113: driver_list_cond = condition_alloc(); ! 114: config_in_progress = TRUE; ! 115: ! 116: /* ! 117: * Set up various ports and start the server thread before initial ! 118: * autoconfig so device drivers have a place to send messages. ! 119: * ! 120: * config_port is how we advertise our exported services to all. ! 121: */ ! 122: krtn = port_allocate(task_self(), &config_port); ! 123: if(krtn) { ! 124: mach_error("port_allocate", krtn); ! 125: exit(1); ! 126: } ! 127: krtn = port_set_allocate(task_self(), &config_port_set); ! 128: if(krtn) { ! 129: mach_error("port_set_allocate", krtn); ! 130: exit(1); ! 131: } ! 132: krtn = port_set_add(task_self(), config_port_set, config_port); ! 133: if(krtn) { ! 134: mach_error("port_set_add", krtn); ! 135: exit(1); ! 136: } ! 137: ! 138: /* ! 139: * we get port death notification on notify_port. ! 140: */ ! 141: krtn = port_allocate(task_self(), ¬ify_port); ! 142: if(krtn) { ! 143: mach_error("port_allocate", krtn); ! 144: exit(1); ! 145: } ! 146: krtn = task_set_notify_port(task_self(), notify_port); ! 147: if(krtn) { ! 148: mach_error("task_set_notify_port", krtn); ! 149: exit(1); ! 150: } ! 151: krtn = port_set_add(task_self(), config_port_set, notify_port); ! 152: if(krtn) { ! 153: mach_error("port_set_add", krtn); ! 154: exit(1); ! 155: } ! 156: krtn = netname_check_in(name_server_port, ! 157: CONFIG_SERVER_NAME, ! 158: task_self(), ! 159: config_port); ! 160: if(krtn) { ! 161: mach_error("netname_check_in", krtn); ! 162: exit(1); ! 163: } ! 164: device_master_port = device_master_self(); ! 165: if(device_master_port == PORT_NULL) { ! 166: syslog(LOG_ERR, "Config: Can't get device_master_port\n"); ! 167: exit(1); ! 168: } ! 169: ! 170: server_thread = cthread_fork((cthread_fn_t)server_loop, (any_t)0); ! 171: ! 172: /* ! 173: * Do initial autoconfig. ! 174: */ ! 175: config_scan(SCAN_ALL, IO_NULL_SLOT_ID, IO_NULL_DEVICE_TYPE); ! 176: ! 177: /* ! 178: * We're done; let the server_thread take it from here. ! 179: */ ! 180: config_in_progress = FALSE; ! 181: cthread_exit(0); ! 182: } ! 183: ! 184: static void usage(char **argv) ! 185: { ! 186: printf("usage: %s [options]\n", argv[0]); ! 187: printf("Options:\n"); ! 188: printf("\tv verbose mode\n"); ! 189: exit(1); ! 190: } ! 191: ! 192: ! 193: /* ! 194: * Main server loop. This thread starts running before autoconfiguration ! 195: * takes place to allow servicing of IORegisterDriver() calls during ! 196: * autoconfig. The config_in_progress flag prevents us from servicing any ! 197: * hazardous calls during this time - like IORescanDriver(). Such calls will ! 198: * return a IO_CNF_BUSY status. ! 199: */ ! 200: static void server_loop() ! 201: { ! 202: msg_header_t *inp, *outp; ! 203: kern_return_t krtn; ! 204: boolean_t return_msg; ! 205: ! 206: inp = (msg_header_t *)malloc(MSG_SIZE_MAX); ! 207: outp = (msg_header_t *)malloc(MSG_SIZE_MAX); ! 208: while (1) { ! 209: inp->msg_local_port = config_port_set; ! 210: inp->msg_size = MSG_SIZE_MAX; ! 211: krtn = msg_receive(inp, MSG_OPTION_NONE, 0); ! 212: if(krtn) { ! 213: mach_error("msg_receive", krtn); ! 214: continue; ! 215: } ! 216: xpr_server("msg_id %d received\n", inp->msg_id, 2,3,4,5); ! 217: return_msg = FALSE; ! 218: if(inp->msg_local_port == config_port) { ! 219: Config_server(inp, outp); ! 220: return_msg = TRUE; ! 221: } ! 222: else if(inp->msg_local_port == notify_port) { ! 223: config_port_death(inp); ! 224: } ! 225: else { ! 226: printf("Config server_loop: Bogus msg_local_port\n"); ! 227: } ! 228: ! 229: if(return_msg) { ! 230: /* ! 231: * Return message to client. We don't deal with ! 232: * backed up port queues for now. ! 233: */ ! 234: krtn = msg_send(outp, SEND_TIMEOUT, 0); ! 235: if(krtn) { ! 236: mach_error("msg_receive", krtn); ! 237: continue; ! 238: } ! 239: } ! 240: } ! 241: /* NOT REACHED */ ! 242: } ! 243: ! 244: /* ! 245: * Handle port death notification. The only ports we're interested in are ! 246: * driver_ports. ! 247: */ ! 248: static void config_port_death(msg_header_t *inp) ! 249: { ! 250: notification_t *msgp = (notification_t *)inp; ! 251: driver_entry_t *driver_entry; ! 252: queue_head_t dev_list; ! 253: dev_entry_t *dev_entry; ! 254: IOReturn drtn; ! 255: ! 256: /* ! 257: * FIXME: use NOTIFY_PORT_DESTOYED?? ! 258: */ ! 259: if(inp->msg_id != NOTIFY_PORT_DELETED) { ! 260: xpr_server("config_port_death: weird msg_id (%d)\n", ! 261: inp->msg_id, 2,3,4,5); ! 262: return; ! 263: } ! 264: xpr_server("config_port_death: port %d\n", msgp->notify_port, 2,3,4,5); ! 265: get_driver_list_lock(); ! 266: driver_entry = get_driver_entry( ! 267: SK_DRIVER_PORT, ! 268: msgp->notify_port, ! 269: DEV_NUM_NULL, ! 270: FID_NULL, ! 271: IO_NULL_DEVICE_TYPE, ! 272: IO_NULL_SLOT_ID, ! 273: NULL); ! 274: release_driver_list_lock(); ! 275: if(driver_entry == NULL) { ! 276: xpr_server("config_port_death: not sig port\n", ! 277: 1,2,3,4,5); ! 278: return; ! 279: } ! 280: driver_entry->driver_port = PORT_NULL; ! 281: ! 282: /* ! 283: * Shut down all devices associated with this driver. ! 284: * First, move all of this driver's dev_entry's to our local ! 285: * queue. ! 286: */ ! 287: queue_init(&dev_list); ! 288: while(!queue_empty(&driver_entry->dev_list)) { ! 289: dev_entry = (dev_entry_t *) ! 290: queue_first(&driver_entry->dev_list); ! 291: queue_remove(&driver_entry->dev_list, ! 292: dev_entry, ! 293: dev_entry_t *, ! 294: link); ! 295: queue_enter(&dev_list, ! 296: dev_entry, ! 297: dev_entry_t *, ! 298: link); ! 299: } ! 300: ! 301: /* ! 302: * For each device, destroy the associated device port, then ! 303: * create a new one for the same physical device. ! 304: */ ! 305: while(!queue_empty(&dev_list)) { ! 306: dev_entry = (dev_entry_t *)queue_first(&dev_list); ! 307: queue_remove(&dev_list, ! 308: dev_entry, ! 309: dev_entry_t *, ! 310: link); ! 311: if(dev_entry->dev_port) { ! 312: drtn = _IODestroyDevicePort(device_master_port, ! 313: dev_entry->dev_port); ! 314: if(drtn) { ! 315: xpr_common("config_port_death: " ! 316: "_IODestroyDevicePort() returned %s\n", ! 317: IOFindNameForValue(drtn, dev_returns), ! 318: 2,3,4,5); ! 319: /* but keep going... */ ! 320: } ! 321: } ! 322: create_dev_entry(driver_entry, ! 323: dev_entry->dev_number, ! 324: dev_entry->dev_type, ! 325: dev_entry->slot_id); ! 326: ! 327: /* ! 328: * Our dev_entry is a useless copy... ! 329: */ ! 330: free(dev_entry); ! 331: } ! 332: ! 333: /* ! 334: * Now restart the driver. ! 335: */ ! 336: xpr_server("config_port_death: restarting driver %s\n", ! 337: IOCopyString(driver_entry->filename), 2,3,4,5); ! 338: if(exec_driver(driver_entry) != IO_CNF_SUCCESS) { ! 339: /* ! 340: * Couldn't exec this driver. Remove from driver_list. ! 341: */ ! 342: get_driver_list_lock(); ! 343: free_driver_entry(driver_entry); ! 344: release_driver_list_lock(); ! 345: } ! 346: } ! 347: ! 348: /* ! 349: * These functions are called out from the mig-generated Config_server. ! 350: */ ! 351: ! 352: /* ! 353: * Each driver which we exec calls this exactly once. The purpose is to ! 354: * register a driver_port for the driver's driver_entry so we can detect the ! 355: * death of the driver. ! 356: */ ! 357: IOConfigReturn _IORegisterDriver( ! 358: port_t dev_config_port, ! 359: port_t driver_sig_port, ! 360: port_t driver_port) ! 361: { ! 362: driver_entry_t *driver_entry; ! 363: IOConfigReturn rtn = IO_CNF_SUCCESS; ! 364: ! 365: xpr_server("driver_register driver_port %d\n", driver_port, 2,3,4,5); ! 366: get_driver_list_lock(); ! 367: ! 368: /* ! 369: * Make sure that this is a new registration for a device we ! 370: * know about. ! 371: */ ! 372: driver_entry = get_driver_entry( ! 373: SK_SIG_PORT, ! 374: driver_sig_port, ! 375: DEV_NUM_NULL, ! 376: FID_NULL, ! 377: IO_NULL_DEVICE_TYPE, ! 378: IO_NULL_SLOT_ID, ! 379: NULL); ! 380: if(driver_entry == NULL) { ! 381: xpr_server("device_register: BAD driver_sig_port\n", ! 382: 1,2,3,4,5); ! 383: rtn = IO_CNF_NOT_REGISTERED; ! 384: goto done; ! 385: } ! 386: if(driver_entry->driver_port != PORT_NULL) { ! 387: xpr_server("device_register: REDUNDANT REGISTRATION\n", ! 388: 1,2,3,4,5); ! 389: rtn = IO_CNF_REGISTERED; ! 390: goto done; ! 391: } ! 392: driver_entry->driver_port = driver_port; ! 393: done: ! 394: release_driver_list_lock(); ! 395: return rtn; ! 396: } ! 397: ! 398: /* ! 399: * Release all state associated with specified driver. Can only be called ! 400: * by drivers we exec. ! 401: */ ! 402: IOConfigReturn _IODeleteDriver( ! 403: port_t dev_config_port, ! 404: port_t driver_sig_port) ! 405: { ! 406: driver_entry_t *driver_entry; ! 407: IOConfigReturn rtn = IO_CNF_SUCCESS; ! 408: ! 409: xpr_server("driver_delete\n", 1,2,3,4,5); ! 410: ! 411: get_driver_list_lock(); ! 412: driver_entry = get_driver_entry( ! 413: SK_SIG_PORT, ! 414: driver_sig_port, ! 415: DEV_NUM_NULL, ! 416: FID_NULL, ! 417: IO_NULL_DEVICE_TYPE, ! 418: IO_NULL_SLOT_ID, ! 419: NULL); ! 420: if(driver_entry == NULL) { ! 421: xpr_server("driver_delete: BAD driver_sig_port\n", ! 422: 1,2,3,4,5); ! 423: rtn = IO_CNF_NOT_REGISTERED; ! 424: goto done; ! 425: } ! 426: ! 427: rtn = free_driver_entry(driver_entry); ! 428: done: ! 429: release_driver_list_lock(); ! 430: return rtn; ! 431: } ! 432: ! 433: #if SUPPORT_DEVICE_DELETE ! 434: /* ! 435: * Release state associated with one device. Can only be called ! 436: * by drivers we exec. ! 437: * ! 438: * FIXME: ! 439: * problem - a driver deletes some ports via device_delete(), then crashes. ! 440: * On restart, should it have access to all of the dev_ports it initially ! 441: * had? Currently it won't because Config did device_destroy()'s on the ! 442: * dev_ports. Those dev_entry's will be missing from the driver_entry's ! 443: * dev_list... ! 444: * ! 445: * Also, how to assign a deleted device to another driver if the deletor ! 446: * keeps running? A config_scan() will just add it to that driver's ! 447: * dev_list and since that driver's already running, it won't get exec'd. ! 448: * ! 449: * SO...for now we don't support device_delete(). ! 450: */ ! 451: IOConfigReturn _IODeleteDevice( ! 452: port_t dev_config_port, ! 453: port_t driver_sig_port, ! 454: dev_port_t dev_port) ! 455: { ! 456: driver_entry_t *driver_entry; ! 457: dev_entry_t *dev_entry; ! 458: IOConfigReturn rtn = IO_CNF_SUCCESS; ! 459: ! 460: xpr_server("device_delete\n", 1,2,3,4,5); ! 461: get_driver_list_lock(); ! 462: driver_entry = get_driver_entry( ! 463: SK_DEV_PORT, ! 464: dev_port, ! 465: DEV_NUM_NULL, ! 466: FID_NULL, ! 467: IO_NULL_DEVICE_TYPE, ! 468: IO_NULL_SLOT_ID, ! 469: &dev_entry); ! 470: if(driver_entry == NULL) { ! 471: rtn = IO_CNF_NOT_REGISTERED; ! 472: goto done; ! 473: } ! 474: if(dev_entry == NULL) { ! 475: /* ! 476: * Huh? This should not happen... ! 477: */ ! 478: rtn = IO_CNF_NOT_REGISTERED; ! 479: goto done; ! 480: } ! 481: if(driver_entry->driver_sig_port != driver_sig_port) { ! 482: rtn = IO_CNF_NOT_REGISTERED; ! 483: goto done; ! 484: } ! 485: rtn = free_dev_entry(dev_entry); ! 486: done: ! 487: release_driver_list_lock(); ! 488: xpr_server("device_delete: returning %s\n", ! 489: reg_text(*rtn, config_returns), 2,3,4,5); ! 490: return rtn; ! 491: } ! 492: ! 493: #endif SUPPORT_DEVICE_DELETE ! 494: ! 495: /* ! 496: * Do a complete rescan of all potential devices. Exec drivers for the ! 497: * devices which we don't currently have registered drivers. This can be ! 498: * called by anyone who can get dev_config_port. We return Busy status if ! 499: * initial config is still in progress. ! 500: */ ! 501: IOConfigReturn _IORescanDriver( ! 502: port_t dev_config_port) ! 503: { ! 504: IOConfigReturn rtn; ! 505: ! 506: xpr_server("driver_rescan\n", 1,2,3,4,5); ! 507: if(config_in_progress) { ! 508: return(IO_CNF_BUSY); ! 509: } ! 510: rtn = config_scan(SCAN_ALL, IO_NULL_SLOT_ID, IO_NULL_DEVICE_TYPE); ! 511: return rtn; ! 512: } ! 513: ! 514: /* ! 515: * Attempt to start a driver for device specified by slot_id and dev_type. ! 516: * This can be called by anyone who can get dev_config_port. We return ! 517: * Busy status if initial config is still in progress. ! 518: */ ! 519: IOConfigReturn _IOConfigDevice( ! 520: port_t dev_config_port, ! 521: IOSlotId slot_id, ! 522: IODeviceType dev_type) ! 523: { ! 524: IOConfigReturn rtn; ! 525: ! 526: xpr_server("driver_config\n", 1,2,3,4,5); ! 527: if(config_in_progress) { ! 528: return(IO_CNF_BUSY); ! 529: } ! 530: rtn = config_scan(SCAN_ONE, slot_id, dev_type); ! 531: return rtn; ! 532: } ! 533: ! 534: #ifdef DEBUG ! 535: ! 536: /* ! 537: * For debugging new drivers. Delete state associated with specified slot_id ! 538: * and device_type. ! 539: */ ! 540: IOConfigReturn _IODeleteDeviceByType( ! 541: port_t configPort, ! 542: IOSlotId slot_id, ! 543: IODeviceType device_type) ! 544: { ! 545: IOConfigReturn rtn; ! 546: driver_entry_t *driver_entry; ! 547: dev_entry_t *dev_entry; ! 548: ! 549: xpr_server("IODeleteDeviceByType: slot_id 0x%x device_type 0x%x\n", ! 550: slot_id, device_type, 3,4,5); ! 551: ! 552: /* ! 553: * Get driver_entry associated with this slotId and deviceType. ! 554: */ ! 555: get_driver_list_lock(); ! 556: driver_entry = get_driver_entry( ! 557: SK_DEV_INDEX, ! 558: PORT_NULL, ! 559: DEV_NUM_NULL, ! 560: FID_NULL, ! 561: device_type, ! 562: slot_id, ! 563: &dev_entry); ! 564: if(driver_entry == NULL) { ! 565: rtn = IO_CNF_NOT_FOUND; ! 566: goto done; ! 567: } ! 568: ! 569: rtn = free_driver_entry(driver_entry); ! 570: done: ! 571: release_driver_list_lock(); ! 572: return rtn; ! 573: ! 574: } ! 575: #endif DEBUG
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.