Annotation of driverkit/Config/ConfigScan.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.