Annotation of driverkit/Config/ConfigScan.c, revision 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.