|
|
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(¬ify_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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.