|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24: /* Copyright (c) 1991 NeXT Computer, Inc. All rights reserved.
25: *
26: * ConfigScan.c - routines to scan physical devices and start up drivers.
27: *
28: * HISTORY
29: * 14-Apr-91 Doug Mitchell at NeXT
30: * Created.
31: */
32:
33: #import <bsd/sys/types.h>
34: #import <bsd/libc.h>
35: #import <mach/mach_types.h>
36: #import <driverkit/userConfigServer.h>
37: #import "ConfigPrivate.h"
38: #import "ConfigUtils.h"
39: #import "ConfigScan.h"
40: #import "ConfigUfs.h"
41: #import <mach/kern_return.h>
42: #import <mach/mach.h>
43: #import <mach/mach_error.h>
44: #import <kernserv/queue.h>
45: #import <bsd/sys/dir.h>
46: #import <servers/bootstrap.h>
47: #import <driverkit/generalFuncs.h>
48: #import <mach/mig_errors.h>
49: /*
50: * Main device scan function.
51: *
52: * Search thru all hardware devices. Map devices onto driver_entry's and
53: * dev_entry's. Launch all drivers.
54: *
55: * Also used to scan for a driver of one particular deviceType and slotId
56: * if scan_type is SCAN_ONE.
57: */
58: IOConfigReturn config_scan(
59: scan_t scan_type,
60: IOSlotId slot_id_arg,
61: IODeviceType dev_type_arg)
62: {
63: IOReturn drtn;
64: IODeviceNumber dev_number;
65: IOSlotId slot_id;
66: IODeviceType dev_type;
67: dev_entry_t *dev_entry;
68: driver_entry_t *driver_entry;
69: filename_t filename;
70: file_id_t fid;
71: IOConfigReturn crtn;
72: BOOL in_use;
73:
74: xpr_common("config_scan\n", 1,2,3,4,5);
75:
76: if(scan_type == SCAN_ONE) {
77: crtn = IO_CNF_NOT_FOUND; // until we find it
78: }
79: else {
80: crtn = IO_CNF_SUCCESS; // can't fail
81: }
82:
83: /*
84: * First create driver_list. We scan all of the devices before
85: * exec'ing any drivers to ensure that a driver has access to all of
86: * its appropriate dev_ports when it is exec'd.
87: *
88: * Note that we hold driver_list_lock through this whole block;
89: * if this is the initial config loop, no drivers will have been
90: * started yet.
91: */
92: dev_number = 0;
93: get_driver_list_lock();
94: do {
95: drtn = _IOLookupByDeviceNumber(device_master_port,
96: dev_number,
97: &slot_id,
98: &dev_type,
99: &in_use);
100: if(drtn) {
101: xpr_common("config_scan: _IOLookupByDeviceNumber "
102: "returned "
103: "%s\n", IOFindNameForValue(drtn, dev_returns),
104: 2,3,4,5);
105: if(drtn == MIG_BAD_ID) {
106: printf("_IOLookupByObjectNumber() not "
107: "supported on "
108: "this machine; Config aborting\n");
109: exit(1);
110: }
111: goto next_dev_num;
112: }
113: if(in_use)
114: goto next_dev_num;
115: if(dev_type == IO_NULL_DEVICE_TYPE)
116: goto next_dev_num;
117: if(scan_type == SCAN_ONE) {
118: if((dev_type != dev_type_arg) ||
119: (slot_id != slot_id_arg))
120: goto next_dev_num;
121: }
122:
123: /*
124: * Looks like a valid device. Do we already have a driver
125: * mapping for it?
126: */
127: driver_entry = get_driver_entry(SK_DEVNUM,
128: PORT_NULL,
129: dev_number,
130: FID_NULL,
131: IO_NULL_DEVICE_TYPE,
132: IO_NULL_SLOT_ID,
133: &dev_entry);
134: if(driver_entry) {
135: xpr_common("config_scan: dev_num %d already mapped\n",
136: dev_number, 2,3,4,5);
137: goto next_dev_num;
138: }
139: else {
140: xpr_common("config_scan: NEW device\n", 1,2,3,4,5);
141: xpr_common(" dev_num %d dev_type 0x%x slot_id "
142: "0x%x\n", dev_number, dev_type, slot_id, 4,5);
143: }
144:
145: /*
146: * Get an executable for this device.
147: */
148: if(!get_driver_file(dev_type, slot_id, &filename, &fid)) {
149: goto next_dev_num;
150: }
151:
152: /*
153: * We have a driver for this device. See if this driver is
154: * an alias (link) to a driver we already know about.
155: */
156: driver_entry = get_driver_entry(SK_FID,
157: PORT_NULL,
158: DEV_NUM_NULL,
159: fid,
160: IO_NULL_DEVICE_TYPE,
161: IO_NULL_SLOT_ID,
162: &dev_entry);
163: if(driver_entry == NULL) {
164:
165: /*
166: * create a new driver_entry.
167: */
168: driver_entry = create_driver_entry(fid, filename);
169: if(driver_entry == NULL) {
170: /* huh? */
171: goto next_dev_num;
172: }
173: }
174:
175: /*
176: * Add this device to the driver. We're either adding a new
177: * device to an existing driver or adding the first
178: * device.
179: *
180: * Note that an existing dev_entry in the driver_entry
181: * matching this slot_id and dev_type is OK (we don't
182: * check for it); this would be a "multiple devices of
183: * same type" configuration. We need a port for each one.
184: */
185: dev_entry = create_dev_entry(driver_entry,
186: dev_number,
187: dev_type,
188: slot_id);
189:
190: next_dev_num:
191: dev_number++;
192: } while(drtn != IO_R_NO_DEVICE);
193: release_driver_list_lock();
194:
195: /*
196: * exec new drivers. We have to periodically give server_loop() a
197: * crack at executing driver_register() and driver_delete() calls.
198: * Unfortunately, a driver_delete() can cause us great hassle unless
199: * we're really careful and not hold on to any driver_entry's while
200: * we're not holding the lock. So we scan from the start of
201: * driver_list each time thru the loop, looking for the first
202: * non-running driver.
203: *
204: * If this is a SCAN_ONE operation, this should go really quickly...
205: * I don't think there is any way any more than one driver could
206: * be in a "not running" state.
207: */
208: do {
209: get_driver_list_lock();
210: driver_entry = (driver_entry_t *)queue_first(&driver_list);
211: while(!queue_end(&driver_list, (queue_t)driver_entry)) {
212: if(!driver_entry->running) {
213: if(exec_driver(driver_entry) == IO_CNF_SUCCESS)
214: crtn = IO_CNF_SUCCESS;
215: else {
216: /*
217: * Couldn't exec this driver. Remove
218: * from driver_list.
219: */
220: free_driver_entry(driver_entry);
221: }
222: break;
223: }
224: driver_entry =
225: (driver_entry_t *)driver_entry->link.next;
226: }
227:
228: /*
229: * Either got to the end of the queue or started a
230: * non-running driver. End of queue means we're done (we
231: * started up all drivers). Otherwise, go back to the
232: * head of the queue.
233: */
234: if(queue_end(&driver_list, (queue_t)driver_entry))
235: break;
236: release_driver_list_lock();
237: } while(!queue_end(&driver_list, (queue_t)driver_entry));
238: release_driver_list_lock();
239: xpr_common("config_scan returning %s\n",
240: IOFindNameForValue(crtn, config_returns), 2,3,4,5);
241: return(crtn);
242: }
243:
244: /*
245: * Start up or restart a driver. Place all necessary ports in the driver's
246: * bootstrap namespace. If driver_entry->running is TRUE, this is
247: * a restart; we have to clean up the (now useless) bootstrap port which
248: * the deceased driver used.
249: */
250: IOConfigReturn exec_driver(
251: driver_entry_t *driver_entry)
252: {
253: kern_return_t krtn;
254: port_t old_bootstrap_port;
255: port_t subset_port;
256: dev_entry_t *dev_entry;
257: filename_t portname;
258: filename_t exec_name;
259: int pid;
260:
261: xpr_common("exec_driver: filename %s\n",
262: IOCopyString(driver_entry->filename), 2,3,4,5);
263: sprintf(exec_name, "%s/%s", DRIVER_PATH, driver_entry->filename);
264: if(driver_entry->running) {
265: /*
266: * Kill off dead driver's bootstrap and signature ports.
267: */
268: xpr_common(" ...deleting requestor and sig ports\n",
269: 1,2,3,4,5);
270: krtn = port_deallocate(task_self(),
271: driver_entry->boot_requestor);
272: if(krtn) {
273: xpr_err("exec_driver: port_deallocate(): %s\n",
274: mach_error_string(krtn), 2,3,4,5);
275: }
276: krtn = port_deallocate(task_self(),
277: driver_entry->driver_sig_port);
278: if(krtn) {
279: xpr_err("exec_driver: port_deallocate(): %s\n",
280: mach_error_string(krtn), 2,3,4,5);
281: }
282: driver_entry->running = FALSE;
283: }
284:
285: /*
286: * Set up a signature port for authentication.
287: */
288: krtn = port_allocate(task_self(), &driver_entry->driver_sig_port);
289: if(krtn) {
290: xpr_err("exec_driver: port_allocate(): %s\n",
291: mach_error_string(krtn), 2,3,4,5);
292: return(IO_CNF_RESOURCE);
293: }
294:
295: /*
296: * Set up a bootstrap subset port for the driver task. Its lifetime
297: * will be the lifetime of driver_entry->boot_requestor.
298: */
299: krtn = port_allocate(task_self(), &driver_entry->boot_requestor);
300: if(krtn) {
301: xpr_err("exec_driver: port_allocate(): %s\n",
302: mach_error_string(krtn), 2,3,4,5);
303: return(IO_CNF_RESOURCE);
304: }
305: krtn = bootstrap_subset(bootstrap_port,
306: driver_entry->boot_requestor, /* requestor */
307: &subset_port);
308: if(krtn) {
309: xpr_err("exec_driver: bootstrap_subset() returned %d\n",
310: krtn, 2,3,4,5);
311: return(IO_CNF_RESOURCE);
312: }
313:
314: /*
315: * Advertise the following on the bootstrap subset port:
316: * -- dev_port for each of this driver's dev_entry's
317: * -- driver_sig_port
318: */
319: xpr_common("exec_driver: adding port driver_sig_port\n", 1,2,3,4,5);
320: krtn = bootstrap_register(subset_port,
321: SIG_PORT_NAME,
322: driver_entry->driver_sig_port);
323: if(krtn) {
324: xpr_err("exec_driver: bootstrap_register(): %s\n",
325: mach_error_string(krtn), 2,3,4,5);
326: return(IO_CNF_RESOURCE);
327: }
328: dev_entry = (dev_entry_t *)queue_first(&driver_entry->dev_list);
329: while(!queue_end(&driver_entry->dev_list, (queue_t)dev_entry)) {
330: sprintf(portname, "dev_port_%u", dev_entry->dev_number);
331: xpr_common("exec_driver: adding port %s\n",
332: IOCopyString(portname), 2,3,4,5);
333: krtn = bootstrap_register(subset_port,
334: portname,
335: dev_entry->dev_port);
336: if(krtn) {
337: printf("OOPS\n");
338: xpr_err("exec_driver: bootstrap_register(%s): %s\n",
339: IOCopyString(portname),
340: mach_error_string(krtn),
341: 3,4,5);
342: xpr_err(" filename %s dev_number %d dev_port %d\n",
343: IOCopyString(driver_entry->filename),
344: dev_entry->dev_number, dev_entry->dev_port,
345: 4,5);
346: #ifdef DEBUG
347: log_boot_servers(subset_port);
348: #endif DEBUG
349: return(IO_CNF_RESOURCE);
350: }
351: dev_entry = (dev_entry_t *)dev_entry->link.next;
352: }
353:
354: /*
355: * OK, set out bootstrap port to the subset port, and fork off the
356: * driver. Then restore our task's bootstrap_port. Note
357: * "bootstrap_port" is a crufty mach global.
358: */
359: old_bootstrap_port = bootstrap_port;
360: krtn = task_set_bootstrap_port(task_self(), subset_port);
361: if(krtn) {
362: xpr_err("exec_driver: task_set_bootstrap_port(): %s\n",
363: mach_error_string(krtn), 2,3,4,5);
364: return(IO_CNF_RESOURCE);
365: }
366: bootstrap_port = subset_port;
367: driver_entry->running = TRUE;
368: if((pid = fork()) == 0) {
369: printf("...forking off %s\n", exec_name);
370: execl(exec_name, exec_name, NULL);
371: /*
372: * FIXME: what do we do here? Should get rid of driver_entry,
373: * but we've already forked! Currently we have no way to
374: * do this without looking up our device ports with
375: * the bootstrap server, registering via IORegisterDriver(),
376: * then calling IODeleteDriver(). What a pain. Let's skip
377: * it for now; developers can use configutil -t to clean
378: * up.
379: */
380: perror("execl");
381: xpr_err("Config: execl(%s) FAILED\n",
382: IOCopyString(exec_name), 2,3,4,5);
383: exit(1);
384: }
385:
386: /*
387: * Back to our old self.
388: */
389: bootstrap_port = old_bootstrap_port;
390: krtn = task_set_bootstrap_port(task_self(), old_bootstrap_port);
391: if(krtn) {
392: xpr_err("exec_driver: task_set_bootstrap_port(): %s\n",
393: mach_error_string(krtn), 2,3,4,5);
394: }
395: return(IO_CNF_SUCCESS);
396: }
397:
398: #ifdef DEBUG
399: void log_boot_servers(port_t boot_port)
400: {
401: u_int i;
402: name_array_t service_names;
403: unsigned int service_cnt;
404: name_array_t server_names;
405: unsigned int server_cnt;
406: bool_array_t service_active;
407: unsigned int service_active_cnt;
408: kern_return_t krtn;
409:
410: krtn = bootstrap_info(boot_port,
411: &service_names,
412: &service_cnt,
413: &server_names,
414: &server_cnt,
415: &service_active,
416: &service_active_cnt);
417: if (krtn != BOOTSTRAP_SUCCESS)
418: printf("ERROR: info failed: %d", krtn);
419: else {
420: printf("log_boot_server: service_cnt = %d\n", service_cnt);
421: for (i = 0; i < service_cnt; i++)
422: printf("Name: %-15s Server: %-15s "
423: "Active: %-4s",
424: service_names[i],
425: server_names[i][0] == '\0' ?
426: "Unknown" : server_names[i],
427: service_active[i] ? "Yes\n" : "No\n");
428: }
429: }
430: #endif DEBUG
431:
432: /*
433: * Extract revision from a filename_t. Returns 0 if OK, -1 on error (i.e.,
434: * illegal filename format). This is (and should remain) file system
435: * independent - internally, we use filename_t's exclusively.
436: */
437: int get_driver_rev(
438: filename_t filename,
439: unsigned short *revision)
440: {
441: char rev_string[9];
442: unsigned int rev;
443: int bar[3]; /* position of underbars */
444: int digit;
445: int bar_num = 0;
446: int rev_length;
447:
448: /*
449: * We're pretty strict about the format....
450: *
451: * devr_<DEV_INDEX>_<REVISION>_<human_readable_name>
452: * ...or...
453: * devs_<SLOT_ID>_<REVISION>_<human_readable_name>
454: *
455: * This routine returns <REVISION> as a binary number (assuming that
456: * in the filename it's in ASCII hex).
457: */
458: bar[0] = bar[1] = bar[2] = -1;
459: for(digit=0; digit<FILENAME_SIZE; digit++) {
460: if(filename[digit] == '_') {
461: bar[bar_num++] = digit;
462: if(bar_num == 3)
463: break;
464: }
465: if(filename[digit] == '\0')
466: break;
467: }
468:
469: /*
470: * Verify proper filename format.
471: */
472: if(bar_num != 3)
473: return(-1);
474: rev_length = bar[2] - bar[1] - 1;
475: if((rev_length > 8) || (rev_length == 0))
476: return(-1);
477: strncpy(rev_string, &filename[bar[1]+1], rev_length);
478: rev_string[rev_length] = '\0';
479: rev = atoh(rev_string);
480: xpr_common("get_driver_rev(%s) returning 0x%x\n",
481: IOCopyString(filename), rev, 3,4,5);
482: *revision = rev;
483: return(0);
484: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.