|
|
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.