|
|
1.1 root 1: /* Copyright (c) 1991 NeXT Computer, Inc. All rights reserved.
2: *
3: * Config.c - Config server.
4: *
5: * HISTORY
6: * 11-Apr-91 Doug Mitchell at NeXT
7: * Created.
8: */
9:
10: #import <bsd/sys/types.h>
11: #import <bsd/libc.h>
12: #import <mach/mach_types.h>
13: #import <driverkit/ConfigPublic.h>
14: #import <driverkit/libIO.h>
15: #import "ConfigPrivate.h"
16: #import "ConfigUtils.h"
17: #import "ConfigScan.h"
18: #import <mach/kern_return.h>
19: #import <mach/mach.h>
20: #import <servers/netname.h>
21: #import <mach/message.h>
22: #import <mach/mach_error.h>
23: #import <mach/cthreads.h>
24: #import <kernserv/queue.h>
25: #import <mach/notify.h>
26: #import <syslog.h>
27: #ifdef DEBUG
28: #import "ConfigUfs.h"
29: #endif DEBUG
30:
31: /*
32: * prototypes for private functions.
33: */
34: static void usage(char **argv);
35: static void server_loop();
36: boolean_t Config_server(msg_header_t *inp, msg_header_t *outp);
37: static void config_port_death(msg_header_t *inp);
38:
39: /*
40: * Static variables.
41: */
42: static port_t config_port; // we advertise this for all takers
43: static port_set_name_t config_port_set; // the set on which we listen
44: port_t device_master_port; // used to communicate with kernel
45: port_t notify_port; // that's ours
46: static boolean_t config_in_progress; // prevents hazardous operations
47: // during initial config
48: queue_head_t driver_list; // list of driver_entry_t's
49: mutex_t driver_list_lock; // protects driver_list during initial
50: // config
51: condition_t driver_list_cond;
52: boolean_t driver_list_locked;
53:
54: extern port_t device_master_self();
55:
56: /*
57: * User-specified variables.
58: */
59: int verbose = 0;
60:
61: void main(int argc, char **argv)
62: {
63: int arg;
64: kern_return_t krtn;
65: cthread_t server_thread;
66:
67: if(argc < 1)
68: usage(argv);
69: for(arg=1; arg<argc; arg++) {
70: switch(argv[arg][0]) {
71: case 'v':
72: verbose++;
73: break;
74: default:
75: usage(argv);
76: }
77: }
78:
79: #ifdef XPR_DEBUG
80: xprInit(200, "ConfigXpr");
81: xprSetBitmask(XPR_CONFIG_INDEX,
82: XPR_CONFIG | XPR_SERVER | XPR_COMMON | XPR_ERR);
83: #endif XPR_DEBUG
84:
85: /*
86: * Initialize global state.
87: */
88: queue_init(&driver_list);
89: driver_list_lock = mutex_alloc();
90: driver_list_cond = condition_alloc();
91: config_in_progress = TRUE;
92:
93: /*
94: * Set up various ports and start the server thread before initial
95: * autoconfig so device drivers have a place to send messages.
96: *
97: * config_port is how we advertise our exported services to all.
98: */
99: krtn = port_allocate(task_self(), &config_port);
100: if(krtn) {
101: mach_error("port_allocate", krtn);
102: exit(1);
103: }
104: krtn = port_set_allocate(task_self(), &config_port_set);
105: if(krtn) {
106: mach_error("port_set_allocate", krtn);
107: exit(1);
108: }
109: krtn = port_set_add(task_self(), config_port_set, config_port);
110: if(krtn) {
111: mach_error("port_set_add", krtn);
112: exit(1);
113: }
114:
115: /*
116: * we get port death notification on notify_port.
117: */
118: krtn = port_allocate(task_self(), ¬ify_port);
119: if(krtn) {
120: mach_error("port_allocate", krtn);
121: exit(1);
122: }
123: krtn = task_set_notify_port(task_self(), notify_port);
124: if(krtn) {
125: mach_error("task_set_notify_port", krtn);
126: exit(1);
127: }
128: krtn = port_set_add(task_self(), config_port_set, notify_port);
129: if(krtn) {
130: mach_error("port_set_add", krtn);
131: exit(1);
132: }
133: krtn = netname_check_in(name_server_port,
134: CONFIG_SERVER_NAME,
135: task_self(),
136: config_port);
137: if(krtn) {
138: mach_error("netname_check_in", krtn);
139: exit(1);
140: }
141: device_master_port = device_master_self();
142: if(device_master_port == PORT_NULL) {
143: syslog(LOG_ERR, "Config: Can't get device_master_port\n");
144: exit(1);
145: }
146:
147: server_thread = cthread_fork((cthread_fn_t)server_loop, (any_t)0);
148:
149: /*
150: * Do initial autoconfig.
151: */
152: config_scan(SCAN_ALL, SLOT_ID_NULL, DEV_TYPE_NULL);
153:
154: /*
155: * We're done; let the server_thread take it from here.
156: */
157: config_in_progress = FALSE;
158: cthread_exit(0);
159: }
160:
161: static void usage(char **argv)
162: {
163: printf("usage: %s [options]\n", argv[0]);
164: printf("Options:\n");
165: printf("\tv verbose mode\n");
166: exit(1);
167: }
168:
169:
170: /*
171: * Main server loop. This thread starts running before autoconfiguration
172: * takes place to allow servicing of IORegisterDriver() calls during
173: * autoconfig. The config_in_progress flag prevents us from servicing any
174: * hazardous calls during this time - like IORescanDriver(). Such calls will
175: * return a IO_CNF_BUSY status.
176: */
177: static void server_loop()
178: {
179: msg_header_t *inp, *outp;
180: kern_return_t krtn;
181: boolean_t return_msg;
182:
183: inp = (msg_header_t *)malloc(MSG_SIZE_MAX);
184: outp = (msg_header_t *)malloc(MSG_SIZE_MAX);
185: while (1) {
186: inp->msg_local_port = config_port_set;
187: inp->msg_size = MSG_SIZE_MAX;
188: krtn = msg_receive(inp, MSG_OPTION_NONE, 0);
189: if(krtn) {
190: mach_error("msg_receive", krtn);
191: continue;
192: }
193: xpr_server("msg_id %d received\n", inp->msg_id, 2,3,4,5);
194: return_msg = FALSE;
195: if(inp->msg_local_port == config_port) {
196: Config_server(inp, outp);
197: return_msg = TRUE;
198: }
199: else if(inp->msg_local_port == notify_port) {
200: config_port_death(inp);
201: }
202: else {
203: printf("Config server_loop: Bogus msg_local_port\n");
204: }
205:
206: if(return_msg) {
207: /*
208: * Return message to client. We don't deal with
209: * backed up port queues for now.
210: */
211: krtn = msg_send(outp, SEND_TIMEOUT, 0);
212: if(krtn) {
213: mach_error("msg_receive", krtn);
214: continue;
215: }
216: }
217: }
218: /* NOT REACHED */
219: }
220:
221: /*
222: * Handle port death notification. The only ports we're interested in are
223: * driver_ports.
224: */
225: static void config_port_death(msg_header_t *inp)
226: {
227: notification_t *msgp = (notification_t *)inp;
228: driver_entry_t *driver_entry;
229: queue_head_t dev_list;
230: dev_entry_t *dev_entry;
231: IODeviceReturn drtn;
232:
233: /*
234: * FIXME: use NOTIFY_PORT_DESTOYED??
235: */
236: if(inp->msg_id != NOTIFY_PORT_DELETED) {
237: xpr_server("config_port_death: weird msg_id (%d)\n",
238: inp->msg_id, 2,3,4,5);
239: return;
240: }
241: xpr_server("config_port_death: port %d\n", msgp->notify_port, 2,3,4,5);
242: get_driver_list_lock();
243: driver_entry = get_driver_entry(
244: SK_DRIVER_PORT,
245: msgp->notify_port,
246: DEV_NUM_NULL,
247: FID_NULL,
248: DEV_TYPE_NULL,
249: SLOT_ID_NULL,
250: NULL);
251: release_driver_list_lock();
252: if(driver_entry == NULL) {
253: xpr_server("config_port_death: not sig port\n",
254: 1,2,3,4,5);
255: return;
256: }
257: driver_entry->driver_port = PORT_NULL;
258:
259: /*
260: * Shut down all devices associated with this driver.
261: * First, move all of this driver's dev_entry's to our local
262: * queue.
263: */
264: queue_init(&dev_list);
265: while(!queue_empty(&driver_entry->dev_list)) {
266: dev_entry = (dev_entry_t *)
267: queue_first(&driver_entry->dev_list);
268: queue_remove(&driver_entry->dev_list,
269: dev_entry,
270: dev_entry_t *,
271: link);
272: queue_enter(&dev_list,
273: dev_entry,
274: dev_entry_t *,
275: link);
276: }
277:
278: /*
279: * For each device, destroy the associated device port, then
280: * create a new one for the same physical device.
281: */
282: while(!queue_empty(&dev_list)) {
283: dev_entry = (dev_entry_t *)queue_first(&dev_list);
284: queue_remove(&dev_list,
285: dev_entry,
286: dev_entry_t *,
287: link);
288: if(dev_entry->dev_port) {
289: drtn = IODestroyDevicePort(device_master_port,
290: dev_entry->dev_port);
291: if(drtn) {
292: xpr_common("config_port_death: "
293: "IODestroyDevicePort() returned %s\n",
294: IOIntToString(drtn, dev_returns),
295: 2,3,4,5);
296: /* but keep going... */
297: }
298: }
299: create_dev_entry(driver_entry,
300: dev_entry->dev_number,
301: dev_entry->dev_type,
302: dev_entry->slot_id);
303:
304: /*
305: * Our dev_entry is a useless copy...
306: */
307: free(dev_entry);
308: }
309:
310: /*
311: * Now restart the driver.
312: */
313: xpr_server("config_port_death: restarting driver %s\n",
314: xpr_string(driver_entry->filename), 2,3,4,5);
315: if(exec_driver(driver_entry) != IO_CNF_SUCCESS) {
316: /*
317: * Couldn't exec this driver. Remove from driver_list.
318: */
319: get_driver_list_lock();
320: free_driver_entry(driver_entry);
321: release_driver_list_lock();
322: }
323: }
324:
325: /*
326: * These functions are called out from the mig-generated Config_server.
327: */
328:
329: /*
330: * Each driver which we exec calls this exactly once. The purpose is to
331: * register a driver_port for the driver's driver_entry so we can detect the
332: * death of the driver.
333: */
334: IOConfigReturn _IORegisterDriver(
335: port_t dev_config_port,
336: port_t driver_sig_port,
337: port_t driver_port)
338: {
339: driver_entry_t *driver_entry;
340: IOConfigReturn rtn = IO_CNF_SUCCESS;
341:
342: xpr_server("driver_register driver_port %d\n", driver_port, 2,3,4,5);
343: get_driver_list_lock();
344:
345: /*
346: * Make sure that this is a new registration for a device we
347: * know about.
348: */
349: driver_entry = get_driver_entry(
350: SK_SIG_PORT,
351: driver_sig_port,
352: DEV_NUM_NULL,
353: FID_NULL,
354: DEV_TYPE_NULL,
355: SLOT_ID_NULL,
356: NULL);
357: if(driver_entry == NULL) {
358: xpr_server("device_register: BAD driver_sig_port\n",
359: 1,2,3,4,5);
360: rtn = IO_CNF_NOT_REGISTERED;
361: goto done;
362: }
363: if(driver_entry->driver_port != PORT_NULL) {
364: xpr_server("device_register: REDUNDANT REGISTRATION\n",
365: 1,2,3,4,5);
366: rtn = IO_CNF_REGISTERED;
367: goto done;
368: }
369: driver_entry->driver_port = driver_port;
370: done:
371: release_driver_list_lock();
372: return rtn;
373: }
374:
375: /*
376: * Release all state associated with specified driver. Can only be called
377: * by drivers we exec.
378: */
379: IOConfigReturn _IODeleteDriver(
380: port_t dev_config_port,
381: port_t driver_sig_port)
382: {
383: driver_entry_t *driver_entry;
384: IOConfigReturn rtn = IO_CNF_SUCCESS;
385:
386: xpr_server("driver_delete\n", 1,2,3,4,5);
387:
388: get_driver_list_lock();
389: driver_entry = get_driver_entry(
390: SK_SIG_PORT,
391: driver_sig_port,
392: DEV_NUM_NULL,
393: FID_NULL,
394: DEV_TYPE_NULL,
395: SLOT_ID_NULL,
396: NULL);
397: if(driver_entry == NULL) {
398: xpr_server("driver_delete: BAD driver_sig_port\n",
399: 1,2,3,4,5);
400: rtn = IO_CNF_NOT_REGISTERED;
401: goto done;
402: }
403:
404: rtn = free_driver_entry(driver_entry);
405: done:
406: release_driver_list_lock();
407: return rtn;
408: }
409:
410: #if SUPPORT_DEVICE_DELETE
411: /*
412: * Release state associated with one device. Can only be called
413: * by drivers we exec.
414: *
415: * FIXME:
416: * problem - a driver deletes some ports via device_delete(), then crashes.
417: * On restart, should it have access to all of the dev_ports it initially
418: * had? Currently it won't because Config did device_destroy()'s on the
419: * dev_ports. Those dev_entry's will be missing from the driver_entry's
420: * dev_list...
421: *
422: * Also, how to assign a deleted device to another driver if the deletor
423: * keeps running? A config_scan() will just add it to that driver's
424: * dev_list and since that driver's already running, it won't get exec'd.
425: *
426: * SO...for now we don't support device_delete().
427: */
428: IOConfigReturn _IODeleteDevice(
429: port_t dev_config_port,
430: port_t driver_sig_port,
431: dev_port_t dev_port)
432: {
433: driver_entry_t *driver_entry;
434: dev_entry_t *dev_entry;
435: IOConfigReturn rtn = IO_CNF_SUCCESS;
436:
437: xpr_server("device_delete\n", 1,2,3,4,5);
438: get_driver_list_lock();
439: driver_entry = get_driver_entry(
440: SK_DEV_PORT,
441: dev_port,
442: DEV_NUM_NULL,
443: FID_NULL,
444: DEV_TYPE_NULL,
445: SLOT_ID_NULL,
446: &dev_entry);
447: if(driver_entry == NULL) {
448: rtn = IO_CNF_NOT_REGISTERED;
449: goto done;
450: }
451: if(dev_entry == NULL) {
452: /*
453: * Huh? This should not happen...
454: */
455: rtn = IO_CNF_NOT_REGISTERED;
456: goto done;
457: }
458: if(driver_entry->driver_sig_port != driver_sig_port) {
459: rtn = IO_CNF_NOT_REGISTERED;
460: goto done;
461: }
462: rtn = free_dev_entry(dev_entry);
463: done:
464: release_driver_list_lock();
465: xpr_server("device_delete: returning %s\n",
466: reg_text(*rtn, config_returns), 2,3,4,5);
467: return rtn;
468: }
469:
470: #endif SUPPORT_DEVICE_DELETE
471:
472: /*
473: * Do a complete rescan of all potential devices. Exec drivers for the
474: * devices which we don't currently have registered drivers. This can be
475: * called by anyone who can get dev_config_port. We return Busy status if
476: * initial config is still in progress.
477: */
478: IOConfigReturn _IORescanDriver(
479: port_t dev_config_port)
480: {
481: IOConfigReturn rtn;
482:
483: xpr_server("driver_rescan\n", 1,2,3,4,5);
484: if(config_in_progress) {
485: return(IO_CNF_BUSY);
486: }
487: rtn = config_scan(SCAN_ALL, SLOT_ID_NULL, DEV_TYPE_NULL);
488: return rtn;
489: }
490:
491: /*
492: * Attempt to start a driver for device specified by slot_id and dev_type.
493: * This can be called by anyone who can get dev_config_port. We return
494: * Busy status if initial config is still in progress.
495: */
496: IOConfigReturn _IOConfigDevice(
497: port_t dev_config_port,
498: IOSlotId slot_id,
499: IODeviceType dev_type)
500: {
501: IOConfigReturn rtn;
502:
503: xpr_server("driver_config\n", 1,2,3,4,5);
504: if(config_in_progress) {
505: return(IO_CNF_BUSY);
506: }
507: rtn = config_scan(SCAN_ONE, slot_id, dev_type);
508: return rtn;
509: }
510:
511: #ifdef DEBUG
512:
513: /*
514: * For debugging new drivers. Delete state associated with specified slot_id
515: * and device_type.
516: */
517: IOConfigReturn _IODeleteDeviceByType(
518: port_t configPort,
519: IOSlotId slot_id,
520: IODeviceType device_type)
521: {
522: IOConfigReturn rtn;
523: driver_entry_t *driver_entry;
524: dev_entry_t *dev_entry;
525:
526: xpr_server("IODeleteDeviceByType: slot_id 0x%x device_type 0x%x\n",
527: slot_id, device_type, 3,4,5);
528:
529: /*
530: * Get driver_entry associated with this slotId and deviceType.
531: */
532: get_driver_list_lock();
533: driver_entry = get_driver_entry(
534: SK_DEV_INDEX,
535: PORT_NULL,
536: DEV_NUM_NULL,
537: FID_NULL,
538: device_type,
539: slot_id,
540: &dev_entry);
541: if(driver_entry == NULL) {
542: rtn = IO_CNF_NOT_FOUND;
543: goto done;
544: }
545:
546: rtn = free_driver_entry(driver_entry);
547: done:
548: release_driver_list_lock();
549: return rtn;
550:
551: }
552: #endif DEBUG
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.