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