Annotation of kernel/bsd/dev/vol.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: 
                     25: /*     @(#)vol.c       2.0     03/19/90        (c) 1990 NeXT   */
                     26: 
                     27: /* 
                     28:  * vol.c - volume insertion device
                     29:  *
                     30:  * HISTORY
                     31:  * 03-19-90    Doug Mitchell at NeXT
                     32:  *     Created.
                     33:  */ 
                     34: 
                     35: #import <sys/types.h>
                     36: #import <sys/errno.h>
                     37: #import <sys/ioctl.h>
                     38: #import <sys/systm.h>
                     39: #import <sys/disktab.h>
                     40: #import <kern/kern_port.h>
                     41: #import <kern/thread.h> 
                     42: #import <kern/lock.h>
                     43: #import <kernserv/insertmsg.h>
                     44: #import <bsd/dev/disk.h>
                     45: #import <kernserv/prototypes.h>
                     46: #import <bsd/dev/voldev.h>
                     47: #import <kern/queue.h>
                     48: #import <kernserv/kern_notify.h>
                     49: #import <mach/notify.h>
                     50: #if    hppa
                     51: # import <bsd/dev/hppa/sdvol.h>
                     52: #endif hppa
                     53: #import "driverkit.h"
                     54: 
                     55: /* #define VOL_DEBUG   1       /* */
                     56: 
                     57: #ifdef VOL_DEBUG
                     58: #define vol_debug(x)   printf x
                     59: #else  VOL_DEBUG
                     60: #define vol_debug(x)
                     61: #endif VOL_DEBUG
                     62: 
                     63: /*
                     64:  * Struct used for queueing notifications prior to first DKIOCMNOTIFY
                     65:  */
                     66: struct vol_notify_entry {
                     67:        queue_chain_t           link;
                     68:        int                     dev_desc;       /* IND_DD_DEV, IND_DD_PORT */
                     69:        dev_t                   block_dev;      /* for IND_DD_DEV */
                     70:        dev_t                   raw_dev;        /* ditto */
                     71:        kern_port_t             dev_port;       /* for IND_DD_PORT */
                     72:        int                     vol_state;      /* IND_VS_LABEL, etc. */
                     73:        char                    form_type[FORM_TYPE_LENGTH];
                     74:        char                    dev_str[OID_DEVSTR_LEN];
                     75:        int                     flags;
                     76: };
                     77: 
                     78: typedef struct vol_notify_entry *vne_t;
                     79: 
                     80: /*
                     81:  * Struct for maintaining state of panel requests
                     82:  */
                     83: 
                     84: struct vol_panel_entry {
                     85:        queue_chain_t           link;
                     86:        int                     tag;
                     87:        vpt_func                fnc;            /* to be called upon receipt of
                     88:                                                 * vol_panel_resp message */    
                     89:        void                    *param;
                     90: };
                     91: 
                     92: typedef struct vol_panel_entry *vpe_t;
                     93: 
                     94: 
                     95: /*
                     96:  * Local functions.
                     97:  */
                     98: static kern_return_t vol_notify_com(int in_dev_desc,   
                     99:        dev_t block_dev, 
                    100:        dev_t raw_dev,
                    101:        kern_port_t dev_port, 
                    102:        int vol_state,
                    103:        const char *form_type,
                    104:        const char *dev_str,
                    105:        int flags);
                    106: static void vol_thread();
                    107: static vpe_t vol_panel_get_entry(int tag);
                    108: static void vol_port_death(notification_t *nmsg);
                    109: 
                    110: /*
                    111:  * Prototypes for kernel functions.
                    112:  */
                    113: msg_return_t msg_send_from_kernel(msg_header_t *msgptr, msg_option_t option, 
                    114:        msg_timeout_t tout);
                    115: 
                    116: int volopen(dev_t dev);
                    117: int volclose(dev_t dev);
                    118: int volioctl(dev_t dev, 
                    119:        int cmd, 
                    120:        caddr_t data, 
                    121:        int flag);
                    122: 
                    123: /*
                    124:  * Globals.
                    125:  */
                    126: static char vol_dev_open;
                    127: static char vol_dev_init_flag;
                    128: static kern_port_t vol_check_port=PORT_NULL;   
                    129:                                        /* port to which disk insertion 
                    130:                                         * messages are sent; usually allocated 
                    131:                                         * by autodiskmount. */
                    132: kern_port_t panel_req_port=PORT_NULL;
                    133:                                        /* port to which Panel Requests are
                    134:                                         * sent. */
                    135: static kern_port_t vol_local_port=PORT_NULL;   
                    136:                                        /* port on which vol_thread listens. */
                    137: static port_t  vol_receive_port = PORT_NULL;
                    138: static queue_head_t vol_notify_q = {&vol_notify_q, &vol_notify_q};
                    139:                                        /* hold notifications prior to
                    140:                                         * first DKIOCMNOTIFY */
                    141: static lock_data_t vol_notify_lock;    /* protects vol_notify_q */
                    142: static queue_head_t vol_panel_q = {&vol_panel_q, &vol_panel_q};
                    143: static int vol_panel_tag;
                    144: static vol_thread_alive=0;
                    145: #if    DRIVERKIT
                    146: static int manual_poll;
                    147: #endif DRIVERKIT
                    148: 
                    149: /*
                    150:  * message templates.
                    151:  */
                    152: static struct insert_notify insert_notify_temp = { 
                    153:        {                                       /* in_header */
                    154:                0,                              /* msg_unused */
                    155:                FALSE,                          /* msg_simple */
                    156:                0,                              /* msg_size */
                    157:                MSG_TYPE_NORMAL,                /* msg_type */
                    158:                PORT_NULL,                      /* msg_local_port */
                    159:                PORT_NULL,                      /* msg_remote_port */
                    160:                VOL_CHECK_MSG_ID                /* msg_id */
                    161:        },
                    162:        {                                       /* in_vd_type */
                    163:                MSG_TYPE_INTEGER_32,            /* msg_type_name */
                    164:                32,                             /* msg_type_size */
                    165:                2,                              /* msg_type_number */
                    166:                TRUE,                           /* msg_type_inline */
                    167:                FALSE,                          /* msg_type_longform */
                    168:                FALSE,                          /* msg_type_deallocate */
                    169:        },
                    170:        0,                                      /* in_vol_state */
                    171:        0,                                      /* in_dev_desc */
                    172:        {                                       /* in_flags_type */
                    173:                MSG_TYPE_INTEGER_32,            /* msg_type_name */
                    174:                32,                             /* msg_type_size */
                    175:                1,                              /* msg_type_number */
                    176:                TRUE,                           /* msg_type_inline */
                    177:                FALSE,                          /* msg_type_longform */
                    178:                FALSE,                          /* msg_type_deallocate */
                    179:        },
                    180:        0,                                      /* in_flags */
                    181:        {                                       /* in_form_type */
                    182:                MSG_TYPE_CHAR,                  /* msg_type_name */
                    183:                8,                              /* msg_type_size */
                    184:                FORM_TYPE_LENGTH,               /* msg_type_number */
                    185:                TRUE,                           /* msg_type_inline */
                    186:                FALSE,                          /* msg_type_longform */
                    187:                FALSE,                          /* msg_type_deallocate */
                    188:        },
                    189:        NULL                                    /* in_form_type */
                    190: };
                    191: 
                    192: static struct vol_panel_req vol_panel_req_temp = {
                    193:        {                                       /* pr_header */
                    194:                0,                              /* msg_unused */
                    195:                TRUE,                           /* msg_simple */
                    196:                sizeof(struct vol_panel_req),   /* msg_size */
                    197:                MSG_TYPE_NORMAL,                /* msg_type */
                    198:                PORT_NULL,                      /* msg_local_port */
                    199:                PORT_NULL,                      /* msg_remote_port */
                    200:                VOL_PANEL_REQ                   /* msg_id */
                    201:        },
                    202:        {                                       /* pr_int_desc */
                    203:                MSG_TYPE_INTEGER_32,            /* msg_type_name */
                    204:                32,                             /* msg_type_size */
                    205:                7,                              /* msg_type_number */
                    206:                TRUE,                           /* msg_type_inline */
                    207:                FALSE,                          /* msg_type_longform */
                    208:                FALSE,                          /* msg_type_deallocate */
                    209:        },
                    210:        0,                                      /* pr_panel_type */
                    211:        0,                                      /* pr_resp_type */
                    212:        0,                                      /* pr_tag */
                    213:        0,                                      /* p1 */
                    214:        0,                                      /* p2 */
                    215:        0,                                      /* p3 */
                    216:        0,                                      /* p4 */
                    217:        {                                       /* pr_string_desc */
                    218:                MSG_TYPE_CHAR,                  /* msg_type_name */
                    219:                8,                              /* msg_type_size */
                    220:                2 * VP_STRING_LEN,              /* msg_type_number */
                    221:                TRUE,                           /* msg_type_inline */
                    222:                FALSE,                          /* msg_type_longform */
                    223:                FALSE                           /* msg_type_deallocate */
                    224:        },
                    225:        NULL,                                   /* string1 */
                    226:        NULL                                    /* string2 */
                    227: };
                    228: 
                    229: static struct vol_panel_cancel vol_panel_cancel_temp = {
                    230:        {                                       /* pc_header */
                    231:                0,                              /* msg_unused */
                    232:                TRUE,                           /* msg_simple */
                    233:                sizeof(struct vol_panel_cancel),/* msg_size */
                    234:                MSG_TYPE_NORMAL,                /* msg_type */
                    235:                PORT_NULL,                      /* msg_local_port */
                    236:                PORT_NULL,                      /* msg_remote_port */
                    237:                VOL_PANEL_CANCEL                /* msg_id */
                    238:        },
                    239:        {                                       /* pc_int_desc */
                    240:                MSG_TYPE_INTEGER_32,            /* msg_type_name */
                    241:                32,                             /* msg_type_size */
                    242:                1,                              /* msg_type_number */
                    243:                TRUE,                           /* msg_type_inline */
                    244:                FALSE,                          /* msg_type_longform */
                    245:                FALSE                           /* msg_type_deallocate */
                    246:        },
                    247:        0                                       /* pc_tag */
                    248: };
                    249: 
                    250: int volopen(dev_t dev)
                    251: {
                    252:        if(vol_dev_open)
                    253:                return(EBUSY);
                    254:        else {
                    255:                vol_dev_open = 1;
                    256:                return(0);
                    257:        }
                    258: }
                    259: 
                    260: int volclose(dev_t dev)
                    261: {
                    262:        vol_dev_open = 0;
                    263:        return(0);
                    264: }
                    265: 
                    266: int volioctl(dev_t dev, 
                    267:        int cmd, 
                    268:        caddr_t data, 
                    269:        int flag)
                    270: {
                    271:        int rtn=0;
                    272:        port_t remote_port;
                    273:        dev_t mydev;
                    274:        
                    275:        switch (cmd) {
                    276:            case DKIOCMNOTIFY:
                    277:                /*
                    278:                 * Send disk insert notification to port specified in *data.
                    279:                 */
                    280:                vol_debug(("volioctl: registering NOTIFY port\n"));
                    281:                remote_port = *(port_t *)data;
                    282:                if(get_kern_port(current_task(), remote_port, &vol_check_port)) 
                    283:                        rtn = EINVAL;
                    284:                else {
                    285:                        /* 
                    286:                         * Send notification for each entry in vol_notify_q.
                    287:                         */
                    288:                        vne_t vnep, vne_next_p;
                    289:                        
                    290:                        lock_write(&vol_notify_lock);
                    291:                        vnep = (vne_t)queue_first(&vol_notify_q);
                    292:                        while(!queue_end(&vol_notify_q, (queue_entry_t)vnep)) {
                    293:                                vne_next_p = (vne_t)vnep->link.next;
                    294:                                queue_remove(&vol_notify_q,
                    295:                                        vnep,
                    296:                                        vne_t,
                    297:                                        link); 
                    298:                                if(vnep->block_dev != rootdev) {
                    299:                                        /*
                    300:                                         * skip notification for root device 
                    301:                                         */
                    302:                                        vol_notify_com(vnep->dev_desc,  
                    303:                                                vnep->block_dev, 
                    304:                                                vnep->raw_dev,
                    305:                                                vnep->dev_port, 
                    306:                                                vnep->vol_state,
                    307:                                                vnep->form_type,
                    308:                                                vnep->dev_str,
                    309:                                                vnep->flags);
                    310:                                }
                    311:                                kfree(vnep, sizeof(struct vol_notify_entry));
                    312:                                vnep = vne_next_p;
                    313:                        }
                    314:                        lock_done(&vol_notify_lock);
                    315:                }
                    316:                /*
                    317:                 * Register this port so we'll know when it dies.
                    318:                 */
                    319:                if(rtn == 0) 
                    320:                        port_request_notification(vol_check_port, 
                    321:                                vol_local_port);
                    322:                break;
                    323: 
                    324:            case DKIOCPANELPRT:
                    325:                /*
                    326:                 * register port to which we send Panel request messages.
                    327:                 */
                    328:                vol_debug(("volioctl: registering PANEL port\n"));
                    329:                remote_port = *(port_t *)data;
                    330:                if(get_kern_port(current_task(), remote_port, &panel_req_port)) 
                    331:                        rtn = EINVAL;
                    332:                /*
                    333:                 * Register this port so we'll know when it dies.
                    334:                 */
                    335:                port_request_notification(panel_req_port, vol_local_port);
                    336:                break;
                    337:                
                    338: #if    DRIVERKIT
                    339:            case DKIOCCHECKINSERT:
                    340: #if 0
                    341: #if    hppa
                    342:                sd_check_disks(SD_CHECK_DISKS);
                    343: #endif hppa
                    344: #endif 0
                    345:                manual_poll = 1;
                    346:                break;
                    347: #endif DRIVERKIT
                    348: 
                    349:            case DKIOCCANCELAUTOMOUNT:
                    350:                mydev = *(dev_t *)data;
                    351:                vol_notify_cancel(mydev);
                    352: 
                    353: /* note: for hppa, if we go with the different vol driver behavior,
                    354:  * this function needs to be taken from the 3.2 HP kernel
                    355:  */
                    356: #if 0
                    357: #ifdef hppa
                    358:                sd_ignore_vol(mydev);
                    359: #endif
                    360: #endif
                    361: 
                    362:                break;
                    363: 
                    364:            default:
                    365:                rtn = EINVAL;
                    366:                break;
                    367:        }
                    368:        return(rtn);
                    369: } /* volioctl() */
                    370: 
                    371: /*
                    372:  * Any driver may call these functions to notify appropriate user task of disk
                    373:  * insertion. If no port has been registered via DKIOCMNOTIFY, no action
                    374:  * is taken.
                    375:  */
                    376:  
                    377: kern_return_t vol_notify_dev(dev_t block_dev, 
                    378:        dev_t raw_dev,
                    379:        const char *form_type,
                    380:        int vol_state,                          /* IND_VS_LABEL, etc. */
                    381:        const char *dev_str,
                    382:        int flags)
                    383: {
                    384:        return(vol_notify_com(IND_DD_DEV,
                    385:                block_dev,
                    386:                raw_dev,
                    387:                0,
                    388:                vol_state,
                    389:                form_type,
                    390:                dev_str,
                    391:                flags));
                    392: }
                    393: 
                    394: #if    SUPPORT_PORT_DEVICE
                    395:        
                    396: kern_return_t vol_notify_port(kern_port_t dev_port, 
                    397:        char *const form_type,
                    398:        int vol_state,                          /* IND_VS_LABEL, etc. */
                    399:        int flags)
                    400: {
                    401:        return(vol_notify_com(IND_DD_PORT,
                    402:                0,
                    403:                0,
                    404:                dev_port,
                    405:                vol_state,
                    406:                form_type,
                    407:                "",
                    408:                flags));
                    409: }
                    410: 
                    411: #endif SUPPORT_PORT_DEVICE
                    412: 
                    413: static kern_return_t vol_notify_com(int in_dev_desc,   
                    414:        dev_t block_dev, 
                    415:        dev_t raw_dev,
                    416:        kern_port_t dev_port, 
                    417:        int vol_state,                          /* IND_VS_LABEL, etc. */
                    418:        const char *form_type,
                    419:        const char *dev_str,
                    420:        int flags)
                    421: {
                    422:        struct insert_notify *notify_msg;
                    423:        struct of_insert_notify_dev *dev_msg;
                    424:        struct of_insert_notify_port *port_msg;
                    425:        int size;       
                    426:        kern_return_t krtn;
                    427:        
                    428:        vol_debug(("vol_notify_com: block_dev=0x%x vol_state=0x%x\n", 
                    429:                block_dev, vol_state));
                    430:        if(!vol_dev_init_flag) {
                    431:                lock_init(&vol_notify_lock, TRUE);
                    432:                vol_dev_init_flag = TRUE;
                    433:        }
                    434:        if(vol_check_port == (kern_port_t)NULL) {
                    435:                vne_t vnep;
                    436:                
                    437:                /* 
                    438:                 * nobody has registered yet. Queue up this request.
                    439:                 */
                    440:                vnep = (vne_t)kalloc(sizeof(struct vol_notify_entry));
                    441:                vnep->dev_desc = in_dev_desc;
                    442:                vnep->block_dev = block_dev;
                    443:                vnep->raw_dev = raw_dev;
                    444:                vnep->dev_port = dev_port;
                    445:                vnep->vol_state = vol_state;
                    446:                vnep->flags = flags;
                    447:                strcpy(vnep->form_type, form_type);
                    448:                strcpy(vnep->dev_str, dev_str);
                    449:                lock_write(&vol_notify_lock);
                    450:                queue_enter(&vol_notify_q,
                    451:                        vnep,
                    452:                        struct vol_notify_entry *,
                    453:                        link); 
                    454:                lock_done(&vol_notify_lock);
                    455:                return(KERN_SUCCESS);
                    456:        }
                    457: 
                    458:        switch(in_dev_desc) {
                    459:            case IND_DD_DEV:
                    460:                size = sizeof(struct of_insert_notify_dev);
                    461:                break;
                    462:                
                    463: #if    SUPPORT_PORT_DEVICE
                    464:            case IND_DD_PORT:
                    465:                size = sizeof(struct of_insert_notify_port);
                    466: #endif SUPPORT_PORT_DEVICE
                    467: 
                    468:            default:
                    469:                return(KERN_INVALID_ARGUMENT);
                    470:        }
                    471:        notify_msg = (struct insert_notify *)kalloc(size);
                    472:        *notify_msg = insert_notify_temp;
                    473:        notify_msg->in_header.msg_simple      = (in_dev_desc == IND_DD_PORT) ? 
                    474:                                                FALSE : TRUE;
                    475:        notify_msg->in_header.msg_size        = size;
                    476:        notify_msg->in_header.msg_remote_port = (port_t)vol_check_port;
                    477:        notify_msg->in_vol_state              = vol_state;
                    478:        notify_msg->in_dev_desc               = in_dev_desc;
                    479:        notify_msg->in_flags                  = flags;
                    480:        strcpy(notify_msg->in_form_type, form_type);
                    481: 
                    482:        /*
                    483:         * dev or port 
                    484:         */
                    485:        switch(in_dev_desc) {
                    486:            case IND_DD_DEV:
                    487:                dev_msg = (struct of_insert_notify_dev *)notify_msg;
                    488:                dev_msg->oid_dev_type.msg_type_name      = MSG_TYPE_INTEGER_32;
                    489:                dev_msg->oid_dev_type.msg_type_size       = 32;
                    490:                dev_msg->oid_dev_type.msg_type_number     = 2;
                    491:                dev_msg->oid_dev_type.msg_type_inline     = TRUE;
                    492:                dev_msg->oid_dev_type.msg_type_longform   = FALSE;
                    493:                dev_msg->oid_dev_type.msg_type_deallocate = FALSE;
                    494:                dev_msg->oid_bdev_t = block_dev;
                    495:                dev_msg->oid_cdev_t = raw_dev;
                    496:                dev_msg->oid_ds_type.msg_type_name       = MSG_TYPE_CHAR;
                    497:                dev_msg->oid_ds_type.msg_type_size       = 8;
                    498:                dev_msg->oid_ds_type.msg_type_number     = OID_DEVSTR_LEN;
                    499:                dev_msg->oid_ds_type.msg_type_inline     = TRUE;
                    500:                dev_msg->oid_ds_type.msg_type_longform   = FALSE;
                    501:                dev_msg->oid_ds_type.msg_type_deallocate = FALSE;
                    502:                strcpy(dev_msg->oid_dev_str, dev_str);
                    503:                break;
                    504:                
                    505: #if    SUPPORT_PORT_DEVICE
                    506: 
                    507:            case IND_DD_PORT:
                    508:                port_msg = (struct of_insert_notify_port *)notify_msg;
                    509:                port_msg->oip_p_type.msg_type_name       = MSG_TYPE_PORT;
                    510:                port_msg->oip_p_type.msg_type_size       = 32;
                    511:                port_msg->oip_p_type.msg_type_number     = 1;
                    512:                port_msg->oip_p_type.msg_type_inline     = TRUE;
                    513:                port_msg->oip_p_type.msg_type_longform   = FALSE;
                    514:                port_msg->oip_p_type.msg_type_deallocate = FALSE;
                    515:                port_msg->oip_port = (port_t)dev_port;
                    516:                
                    517: #endif SUPPORT_PORT_DEVICE
                    518:            default:
                    519:                break;                  // can't happen, avoid compiler
                    520:                                        //    warning
                    521: 
                    522:        }
                    523:        krtn = msg_send_from_kernel(&notify_msg->in_header,
                    524:                SEND_TIMEOUT,
                    525:                0);                     /* don't block if queue full */
                    526: #ifdef DEBUG
                    527:        if(krtn)
                    528:                printf("vol_check_notify: msg_send returned %d\n", krtn);
                    529: #endif         DEBUG
                    530:        return(krtn);
                    531: } /* vol_check_notify */
                    532: 
                    533: /*
                    534:  * Cancel a (possibly) queued notify message. Normally called when a device
                    535:  * is mounted.
                    536:  */
                    537: void vol_notify_cancel(dev_t device)
                    538: {
                    539:        vne_t vnep, vne_next_p;
                    540:        
                    541:        /*
                    542:         * Inserts are always registered for partition a; mounts can be
                    543:         * on other partitions...
                    544:         */
                    545:        device &= ~(NPART - 1);
                    546:        
                    547:        if(!vol_dev_init_flag) {
                    548:                lock_init(&vol_notify_lock, TRUE);
                    549:                vol_dev_init_flag = TRUE;
                    550:        }
                    551: 
                    552:        lock_write(&vol_notify_lock);
                    553:        vnep = (vne_t)queue_first(&vol_notify_q);
                    554:        while(!queue_end(&vol_notify_q, (queue_entry_t)vnep)) {
                    555:                vne_next_p = (vne_t)vnep->link.next;
                    556:                if((vnep->block_dev == device) ||
                    557:                   (vnep->raw_dev == device)) {
                    558:                        queue_remove(&vol_notify_q,
                    559:                                vnep,
                    560:                                vne_t,
                    561:                                link); 
                    562:                        kfree(vnep, sizeof(struct vol_notify_entry));
                    563:                }
                    564:                vnep = vne_next_p;
                    565:        }
                    566:        lock_done(&vol_notify_lock);
                    567: }
                    568: 
                    569: /*
                    570:  * Functions to request and cancel alert panels via WSM
                    571:  */
                    572:  
                    573: /*
                    574:  * Generic panel request.
                    575:  */
                    576: kern_return_t vol_panel_request(vpt_func fnc,
                    577:        int panel_type,                         /* PR_PT_DISK_NUM, etc. */
                    578:        int response_type,                      /* PR_RT_ACK, etc. */
                    579:        int p1,
                    580:        int p2,
                    581:        int p3,
                    582:        int p4,
                    583:        char *string1,
                    584:        char *string2,
                    585:        void *param,
                    586:        int *tag) {                             /* RETURNED */
                    587:        
                    588:        kern_return_t krtn;
                    589:        vpe_t vpe;
                    590:        struct vol_panel_req *panel_msgp;
                    591:        
                    592:        vol_debug(("vol_panel_request: panel_type=%d\n", panel_type));
                    593:        if(panel_req_port == (kern_port_t)NULL) {
                    594:                char *disk_string;
                    595:                
                    596:                /*
                    597:                 * Nobody registered to deal with these requests yet. Punt
                    598:                 * and send notification to the console; no ack is possible.
                    599:                 *
                    600:                 * For some panels, this switch is meaningless (but harmless).
                    601:                 */
                    602:                switch(p2) {
                    603:                    case PR_DRIVE_FLOPPY:
                    604:                        disk_string = "Floppy";
                    605:                        break;
                    606:                    case PR_DRIVE_OPTICAL:
                    607:                        disk_string = "Optical";
                    608:                        break;
                    609:                    case PR_DRIVE_SCSI:
                    610:                        disk_string = "SCSI";
                    611:                        break;
                    612:                    default: 
                    613:                        disk_string = "";
                    614:                        break;
                    615:                }  
                    616:                switch(panel_type) {
                    617:                    case PR_PT_DISK_NUM:
                    618:                        printf("Please Insert %s Disk %d in Drive %d\n", 
                    619:                                disk_string, p1, p3);
                    620:                        break;
                    621:                    case PR_PT_DISK_LABEL:
                    622:                        printf("Please Insert %s Disk \'%s\' in Drive %d\n", 
                    623:                                disk_string, string1, p3);
                    624:                        break;
                    625:                    case PR_PT_DISK_NUM_W:
                    626:                        printf("Wrong Disk: Please Insert %s Disk %d in Drive "
                    627:                                "%d\n", disk_string, p1, p3);
                    628:                        break;
                    629:                    case PR_PT_DISK_LABEL_W:
                    630:                        printf("Wrong Disk: Please Insert %s Disk \'%s\' in "
                    631:                                "Drive %d\n", disk_string, string1, p3);
                    632:                        break;
                    633:                    case PR_PT_SWAPDEV_FULL:
                    634:                        printf("***Swap Device Full***\n");
                    635:                        break;
                    636:                    case PR_PT_FILESYS_FULL:
                    637:                        printf("***File System %s Full***\n", string1);
                    638:                        break;
                    639:                    case PR_RT_EJECT_REQ:
                    640:                        printf("Please Eject %s Disk %d\n", disk_string, p3);
                    641:                        break;
                    642:                    default:
                    643:                        /* FIXME: what do we do here? */
                    644:                        printf("vol_panel_request: bogus panel_type (%d)\n",
                    645:                                panel_type);
                    646:                        break;
                    647:                }
                    648:                return(0);
                    649:        }
                    650:        /*
                    651:         * Build a panel request message.
                    652:         */
                    653:        panel_msgp = (struct vol_panel_req *)kalloc(sizeof(*panel_msgp));
                    654:        *panel_msgp = vol_panel_req_temp;
                    655:        panel_msgp->pr_header.msg_local_port    = (port_t)vol_local_port;
                    656:        panel_msgp->pr_header.msg_remote_port   = (port_t)panel_req_port;
                    657:        panel_msgp->pr_panel_type               = panel_type;
                    658:        panel_msgp->pr_resp_type                = response_type;
                    659:        panel_msgp->pr_tag                      = vol_panel_tag++;
                    660:        panel_msgp->pr_p1                       = p1;
                    661:        panel_msgp->pr_p2                       = p2;
                    662:        panel_msgp->pr_p3                       = p3;
                    663:        panel_msgp->pr_p4                       = p4;
                    664:        if(strlen(string1) >= VP_STRING_LEN)
                    665:                string1[VP_STRING_LEN-1] = '\0';
                    666:        if(strlen(string2) >= VP_STRING_LEN)
                    667:                string2[VP_STRING_LEN-1] = '\0';
                    668:        strcpy(panel_msgp->pr_string1, string1);
                    669:        strcpy(panel_msgp->pr_string2, string2);
                    670:        /*
                    671:         * send the message.
                    672:         */
                    673:        krtn = msg_send_from_kernel(&panel_msgp->pr_header,
                    674:                SEND_TIMEOUT,
                    675:                0);                     /* don't block if queue full */
                    676: #ifdef DEBUG
                    677:        if(krtn)
                    678:                printf("vol_panel_request: msg_send returned %d\n", krtn);
                    679: #endif         DEBUG
                    680:        if(krtn)
                    681:                return(krtn);
                    682:        *tag = panel_msgp->pr_tag;
                    683:        /*
                    684:         * Enqueue this event on vol_panel_q if we expect an ack 
                    685:         */
                    686:        if(response_type == PR_RT_NONE)
                    687:                return(KERN_SUCCESS);
                    688:        vpe = (vpe_t)kalloc(sizeof(struct vol_panel_entry));
                    689:        if(vpe == NULL)
                    690:                return(KERN_RESOURCE_SHORTAGE);
                    691:        vpe->tag = panel_msgp->pr_tag;
                    692:        vpe->fnc = fnc;
                    693:        vpe->param = param;
                    694:        queue_enter(&vol_panel_q, vpe, struct vol_panel_entry *, link);
                    695:        return(KERN_SUCCESS);
                    696:        
                    697: } /* vol_panel_request */
                    698: 
                    699: /*
                    700:  * remove an existing panel.
                    701:  */
                    702: kern_return_t vol_panel_remove(int tag) {
                    703:        struct vol_panel_cancel *msgp;
                    704:        kern_return_t krtn = KERN_SUCCESS;
                    705:        vpe_t vpe;
                    706:        
                    707:        vol_debug(("vol_panel_remove\n"));
                    708:        if(panel_req_port != (kern_port_t)NULL) {
                    709:                msgp = (struct vol_panel_cancel *)kalloc(sizeof(*msgp));
                    710:                *msgp = vol_panel_cancel_temp;
                    711:                msgp->pc_header.msg_local_port        = (port_t)vol_local_port;
                    712:                msgp->pc_header.msg_remote_port       = (port_t)panel_req_port;
                    713:                msgp->pc_tag                          = tag;
                    714:                krtn = msg_send_from_kernel(&msgp->pc_header,
                    715:                        SEND_TIMEOUT,
                    716:                        0);                     /* don't block if queue full */
                    717:                if(krtn)
                    718:                        printf("vol_panel_remove: msg_send returned %d\n",
                    719:                                krtn);
                    720:        }
                    721:        /*
                    722:         * Remove entry in vol_panel_q for this panel.
                    723:         */
                    724:        vpe = vol_panel_get_entry(tag);
                    725:        if(vpe) 
                    726:                kfree(vpe, sizeof(*vpe));
                    727:        else {
                    728:                /*
                    729:                 * This is not an error; it could happen in a race condition in 
                    730:                 * which this function were called just after we received a
                    731:                 * vol_panel_cancel message.
                    732:                 */
                    733:                vol_debug(("vol_panel_remove: panel resp, tag not found\n"));
                    734:        }
                    735:        return(krtn);
                    736: }
                    737: 
                    738: /*
                    739:  * Panel requests specifically for disk drivers.
                    740:  */
                    741: kern_return_t vol_panel_disk_num(vpt_func fnc,
                    742:        int volume_num,
                    743:        int drive_type,                         /* PR_DRIVE_FLOPPY, etc. */
                    744:        int drive_num,
                    745:        void *param,
                    746:        boolean_t wrong_disk,
                    747:        int *tag) {                             /* RETURNED */
                    748:        
                    749:        return(vol_panel_request(fnc,
                    750:                wrong_disk ? PR_PT_DISK_NUM_W : PR_PT_DISK_NUM,
                    751:                PR_RT_ACK,
                    752:                volume_num,
                    753:                drive_type,
                    754:                drive_num,
                    755:                0,
                    756:                "",
                    757:                "",
                    758:                param,
                    759:                tag));  
                    760: }
                    761: 
                    762: kern_return_t vol_panel_disk_label(vpt_func fnc,
                    763:        char *label,
                    764:        int drive_type,                         /* PR_DRIVE_FLOPPY, etc. */
                    765:        int drive_num,
                    766:        void *param,
                    767:        boolean_t wrong_disk,
                    768:        int *tag) {                             /* RETURNED */
                    769: 
                    770:        return(vol_panel_request(fnc,
                    771:                wrong_disk ? PR_PT_DISK_LABEL_W : PR_PT_DISK_LABEL,
                    772:                PR_RT_ACK,
                    773:                0,
                    774:                drive_type,
                    775:                drive_num,
                    776:                0,
                    777:                label,
                    778:                "",
                    779:                param,
                    780:                tag));  
                    781: } 
                    782: 
                    783: void vol_thread() {
                    784:        /*
                    785:         * The job here is to receive and handle two kinds of messages:
                    786:         *
                    787:         * -- messages from the Workspace (like vol_panel_resp messages). 
                    788:         * -- port death messages, forwarded to us from voltask. The death of 
                    789:         *    panel_req_port will cause all pending panels in vol_panel_q to be
                    790:         *    acked and removed. The death of vol_check_port isn't very 
                    791:         *    interesting; we just NULL it out so we don't send any more
                    792:         *    insertion events.
                    793:         */
                    794:         
                    795:        struct vol_panel_resp *msgp;
                    796:        kern_return_t krtn;
                    797:        vpe_t vpe;
                    798: 
                    799:        msgp = (struct vol_panel_resp *)kalloc(MSG_SIZE_MAX);
                    800:        
                    801:        while(1) {
                    802:                msgp->ps_header.msg_local_port = vol_receive_port;
                    803:                msgp->ps_header.msg_size       = MSG_SIZE_MAX;
                    804:                krtn = msg_receive(&msgp->ps_header, MSG_OPTION_NONE, 0);
                    805:                if(krtn) {
                    806:                        printf("vol_thread: msg_receive() returned %d\n", 
                    807:                                krtn);
                    808:                        continue;
                    809:                }
                    810:                vol_debug(("vol_thread: msg_id = 0x%x\n", 
                    811:                        msgp->ps_header.msg_id));
                    812:                switch(msgp->ps_header.msg_id) {
                    813:                    case VOL_PANEL_RESP:
                    814:                        /*
                    815:                         * First we have to see if we know about a panel with 
                    816:                         * this tag.
                    817:                         */
                    818:                        vpe = vol_panel_get_entry(msgp->ps_tag);
                    819:                        if(vpe == NULL) {
                    820:                                /*
                    821:                                 * This is not an error; it could happen
                    822:                                 * in a race condition in which this message
                    823:                                 * came in just after a driver sent a 
                    824:                                 * vol_panel_cancel message.
                    825:                                 */
                    826:                                vol_debug(("vol_thread: panel resp, tag not"
                    827:                                        " found\n"));
                    828:                                break;
                    829:                        }
                    830:                        /*
                    831:                         * Perform callout if necessary, then dispose of
                    832:                         * entry.
                    833:                         */
                    834:                        vol_debug(("vol_thread: doing VOL_PANEL_RESP "
                    835:                                "callout\n"));
                    836:                        if(vpe->fnc) {
                    837:                                (*vpe->fnc)(vpe->param, 
                    838:                                        vpe->tag, 
                    839:                                        msgp->ps_value);
                    840:                        }
                    841:                        kfree(vpe, sizeof(*vpe));
                    842:                        break;
                    843:                        
                    844:                    case NOTIFY_PORT_DELETED:
                    845:                        vol_debug(("vol_thread: port death\n"));
                    846:                        vol_port_death((notification_t *)msgp);
                    847:                        break;
                    848:                        
                    849:                    default:
                    850:                        printf("vol_thread: bogus message rec'd (msg_id = "
                    851:                                "%d)\n", msgp->ps_header.msg_id);
                    852:                        break;
                    853:                }
                    854:        }
                    855: } /* vol_thread() */
                    856: 
                    857: static vpe_t vol_panel_get_entry(int tag) {
                    858:        /*
                    859:         * get vol_panel_entry associated with 'tag' from vol_panel_q. Removes
                    860:         * entry from vol_panel_q. Returns NULL if entry not found.
                    861:         */
                    862:        vpe_t vpe;
                    863: 
                    864:        vpe = (vpe_t)queue_first(&vol_panel_q);
                    865:        while(!queue_end(&vol_panel_q, (queue_entry_t)vpe)) {
                    866:                if(vpe->tag == tag) {
                    867:                        /*
                    868:                         * Found it. 
                    869:                         */
                    870:                        queue_remove(&vol_panel_q,
                    871:                                vpe,
                    872:                                struct vol_panel_entry *,
                    873:                                link);
                    874:                        return(vpe);
                    875:                }
                    876:                vpe = (vpe_t)vpe->link.next;
                    877:        }
                    878:        /*
                    879:         * Not found. 
                    880:         */
                    881:        return((vpe_t)NULL);
                    882: }
                    883: 
                    884: static void vol_port_death(notification_t *nmsg)
                    885: {
                    886:        /*
                    887:         * voltask has detected port death of one of our ports.
                    888:         */
                    889:        vol_debug(("vol_port_death: "));
                    890:        if((kern_port_t)nmsg->notify_port == vol_check_port) {
                    891:                vol_debug(("vol_check_port dead\n"));
                    892:                vol_check_port = PORT_NULL;
                    893:        }
                    894:        else if ((kern_port_t)nmsg->notify_port == panel_req_port) {
                    895:                vpe_t vpe, vpe_next;
                    896:                
                    897:                vol_debug(("panel_req_port dead\n"));
                    898:                /*
                    899:                 * Ack and dispose of every vol_panel_entry in vol_panel_q.
                    900:                 */
                    901:                vpe = (vpe_t)queue_first(&vol_panel_q);
                    902:                while(!queue_end(&vol_panel_q, (queue_entry_t)vpe)) {
                    903:                        vol_debug(("vol_port_death: doing VOL_PANEL_RESP "
                    904:                                "callout\n"));
                    905:                        vpe_next = (vpe_t)vpe->link.next;
                    906:                        if(vpe->fnc) {
                    907:                                (*vpe->fnc)(vpe->param, 
                    908:                                        vpe->tag, 
                    909:                                        0);     /* as in "disk not 
                    910:                                                 * available" */
                    911:                        }
                    912:                        queue_remove(&vol_panel_q,
                    913:                                vpe,
                    914:                                struct vol_panel_entry *,
                    915:                                link);
                    916:                        kfree(vpe, sizeof(*vpe));
                    917:                        vpe = vpe_next;
                    918:                }
                    919:                /*
                    920:                 * Finally, inhibit further panel request messages.
                    921:                 */
                    922:                panel_req_port = PORT_NULL;
                    923:        }
                    924:        else 
                    925:                vol_debug(("bogus notification\n"));
                    926: }
                    927: 
                    928: void vol_start_thread()
                    929: {
                    930:        kern_return_t krtn;
                    931: 
                    932:        mach_port_t     name;
                    933: 
                    934:        krtn = ipc_port_alloc(kernel_task->itk_space, &name, &vol_local_port);
                    935:        if(krtn) {
                    936:                printf("vol_start_thread: port_alloc returned %d\n", 
                    937:                        krtn);
                    938:                return;
                    939:        }
                    940:        vol_receive_port = vol_local_port->ip_receiver_name;
                    941:        ip_unlock(vol_local_port);
                    942:        kernel_thread(kernel_task, vol_thread, (void *)0);
                    943:        queue_init(&vol_panel_q);
                    944:        vol_thread_alive = 1;
                    945:        if(!vol_dev_init_flag) {
                    946:                lock_init(&vol_notify_lock, TRUE);
                    947:                vol_dev_init_flag = TRUE;
                    948:        }
                    949: }
                    950: 
                    951: #if    DRIVERKIT
                    952: /* 
                    953:  * Returns 1 if DKIOCCHECKINSERT has been executed since the last call,
                    954:  * else returns 0.
                    955:  */
                    956: int vol_check_manual_poll()
                    957: {
                    958:        if(manual_poll) {
                    959:                manual_poll = 0;
                    960:                return(1);
                    961:        }
                    962:        else {
                    963:                return(0);
                    964:        }
                    965: }
                    966: 
                    967: /*
                    968:  * Internal version of ioctl(DKIOCCHECKINSERT).
                    969:  */
                    970: void vol_check_set_poll()
                    971: {
                    972:        manual_poll = 1;
                    973: }
                    974: 
                    975: #endif DRIVERKIT
                    976: 
                    977: /* end of vol.c */
                    978: 

unix.superglobalmegacorp.com

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