|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
4: * All Rights Reserved.
5: *
6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
11: *
12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * Author: David B. Golub, Carnegie Mellon University
28: * Date: 3/89
29: */
30:
31: #include <mach/port.h>
32: #include <mach/vm_param.h>
33:
34: #include <kern/queue.h>
35: #include <kern/zalloc.h>
36:
37: #include <device/device_types.h>
38: #include <device/dev_hdr.h>
39: #include <device/conf.h>
40: #include <device/param.h> /* DEV_BSIZE, as default */
41:
42: #include <ipc/ipc_port.h>
43: #include <kern/ipc_kobject.h>
44:
45: #ifdef i386
46: #include <i386at/device_emul.h>
47: #endif
48:
49: /*
50: * Device structure routines: reference counting, port->device.
51: */
52:
53: /*
54: * Lookup/enter by device number.
55: */
56: #define NDEVHASH 8
57: #define DEV_NUMBER_HASH(dev) ((dev) & (NDEVHASH-1))
58: queue_head_t dev_number_hash_table[NDEVHASH];
59:
60: /*
61: * Lock for device-number to device lookup.
62: * Must be held before device-ref_count lock.
63: */
64: decl_simple_lock_data(,
65: dev_number_lock)
66:
67: zone_t dev_hdr_zone;
68:
69: /*
70: * Enter device in the number lookup table.
71: * The number table lock must be held.
72: */
73: void
74: dev_number_enter(device)
75: register mach_device_t device;
76: {
77: register queue_t q;
78:
79: q = &dev_number_hash_table[DEV_NUMBER_HASH(device->dev_number)];
80: queue_enter(q, device, mach_device_t, number_chain);
81: }
82:
83: /*
84: * Remove device from the device-number lookup table.
85: * The device-number table lock must be held.
86: */
87: void
88: dev_number_remove(device)
89: register mach_device_t device;
90: {
91: register queue_t q;
92:
93: q = &dev_number_hash_table[DEV_NUMBER_HASH(device->dev_number)];
94: queue_remove(q, device, mach_device_t, number_chain);
95: }
96:
97: /*
98: * Lookup a device by device operations and minor number.
99: * The number table lock must be held.
100: */
101: mach_device_t
102: dev_number_lookup(ops, devnum)
103: dev_ops_t ops;
104: int devnum;
105: {
106: register queue_t q;
107: register mach_device_t device;
108:
109: q = &dev_number_hash_table[DEV_NUMBER_HASH(devnum)];
110: queue_iterate(q, device, mach_device_t, number_chain) {
111: if (device->dev_ops == ops && device->dev_number == devnum) {
112: return (device);
113: }
114: }
115: return (MACH_DEVICE_NULL);
116: }
117:
118: /*
119: * Look up a device by name, and create the device structure
120: * if it does not exist. Enter it in the dev_number lookup
121: * table.
122: */
123: mach_device_t
124: device_lookup(name)
125: char * name;
126: {
127: dev_ops_t dev_ops;
128: int dev_minor;
129: register mach_device_t device;
130: register mach_device_t new_device;
131:
132: /*
133: * Get the device and unit number from the name.
134: */
135: if (!dev_name_lookup(name, &dev_ops, &dev_minor))
136: return (MACH_DEVICE_NULL);
137:
138: /*
139: * Look up the device in the hash table. If it is
140: * not there, enter it.
141: */
142: new_device = MACH_DEVICE_NULL;
143: simple_lock(&dev_number_lock);
144: while ((device = dev_number_lookup(dev_ops, dev_minor))
145: == MACH_DEVICE_NULL) {
146: /*
147: * Must unlock to allocate the structure. If
148: * the structure has appeared after we have allocated,
149: * release the new structure.
150: */
151: if (new_device != MACH_DEVICE_NULL)
152: break; /* allocated */
153:
154: simple_unlock(&dev_number_lock);
155:
156: new_device = (mach_device_t) zalloc(dev_hdr_zone);
157: simple_lock_init(&new_device->ref_lock);
158: new_device->ref_count = 1;
159: simple_lock_init(&new_device->lock);
160: new_device->state = DEV_STATE_INIT;
161: new_device->flag = 0;
162: new_device->open_count = 0;
163: new_device->io_in_progress = 0;
164: new_device->io_wait = FALSE;
165: new_device->port = IP_NULL;
166: new_device->dev_ops = dev_ops;
167: new_device->dev_number = dev_minor;
168: new_device->bsize = DEV_BSIZE; /* change later */
169:
170: simple_lock(&dev_number_lock);
171: }
172:
173: if (device == MACH_DEVICE_NULL) {
174: /*
175: * No existing device structure. Insert the
176: * new one.
177: */
178: assert(new_device != MACH_DEVICE_NULL);
179: device = new_device;
180:
181: dev_number_enter(device);
182: simple_unlock(&dev_number_lock);
183: }
184: else {
185: /*
186: * Have existing device.
187: */
188: mach_device_reference(device);
189: simple_unlock(&dev_number_lock);
190:
191: if (new_device != MACH_DEVICE_NULL)
192: zfree(dev_hdr_zone, (vm_offset_t)new_device);
193: }
194:
195: return (device);
196: }
197:
198: /*
199: * Add a reference to the device.
200: */
201: void
202: mach_device_reference(device)
203: register mach_device_t device;
204: {
205: simple_lock(&device->ref_lock);
206: device->ref_count++;
207: simple_unlock(&device->ref_lock);
208: }
209:
210: /*
211: * Remove a reference to the device, and deallocate the
212: * structure if no references are left.
213: */
214: void
215: mach_device_deallocate(device)
216: register mach_device_t device;
217: {
218: simple_lock(&device->ref_lock);
219: if (--device->ref_count > 0) {
220: simple_unlock(&device->ref_lock);
221: return;
222: }
223: device->ref_count = 1;
224: simple_unlock(&device->ref_lock);
225:
226: simple_lock(&dev_number_lock);
227: simple_lock(&device->ref_lock);
228: if (--device->ref_count > 0) {
229: simple_unlock(&device->ref_lock);
230: simple_unlock(&dev_number_lock);
231: return;
232: }
233:
234: dev_number_remove(device);
235: simple_unlock(&device->ref_lock);
236: simple_unlock(&dev_number_lock);
237:
238: zfree(dev_hdr_zone, (vm_offset_t)device);
239: }
240:
241: /*
242:
243: */
244: /*
245: * port-to-device lookup routines.
246: */
247: decl_simple_lock_data(,
248: dev_port_lock)
249:
250: /*
251: * Enter a port-to-device mapping.
252: */
253: void
254: dev_port_enter(device)
255: register mach_device_t device;
256: {
257: mach_device_reference(device);
258: #ifdef i386
259: ipc_kobject_set(device->port,
260: (ipc_kobject_t) &device->dev, IKOT_DEVICE);
261: device->dev.emul_data = device;
262: {
263: extern struct device_emulation_ops mach_device_emulation_ops;
264:
265: device->dev.emul_ops = &mach_device_emulation_ops;
266: }
267: #else
268: ipc_kobject_set(device->port, (ipc_kobject_t) device, IKOT_DEVICE);
269: #endif
270: }
271:
272: /*
273: * Remove a port-to-device mapping.
274: */
275: void
276: dev_port_remove(device)
277: register mach_device_t device;
278: {
279: ipc_kobject_set(device->port, IKO_NULL, IKOT_NONE);
280: mach_device_deallocate(device);
281: }
282:
283: /*
284: * Lookup a device by its port.
285: * Doesn't consume the naked send right; produces a device reference.
286: */
287: device_t
288: dev_port_lookup(port)
289: ipc_port_t port;
290: {
291: register device_t device;
292:
293: if (!IP_VALID(port))
294: return (DEVICE_NULL);
295:
296: ip_lock(port);
297: if (ip_active(port) && (ip_kotype(port) == IKOT_DEVICE)) {
298: device = (device_t) port->ip_kobject;
299: #ifdef i386
300: if (device->emul_ops->reference)
301: (*device->emul_ops->reference)(device->emul_data);
302: #else
303: mach_device_reference(device);
304: #endif
305: }
306: else
307: device = DEVICE_NULL;
308:
309: ip_unlock(port);
310: return (device);
311: }
312:
313: /*
314: * Get the port for a device.
315: * Consumes a device reference; produces a naked send right.
316: */
317: ipc_port_t
318: convert_device_to_port(device)
319: register device_t device;
320: {
321: #ifndef i386
322: register ipc_port_t port;
323: #endif
324:
325: if (device == DEVICE_NULL)
326: return IP_NULL;
327:
328: #ifdef i386
329: return (*device->emul_ops->dev_to_port) (device->emul_data);
330: #else
331: device_lock(device);
332: if (device->state == DEV_STATE_OPEN)
333: port = ipc_port_make_send(device->port);
334: else
335: port = IP_NULL;
336: device_unlock(device);
337:
338: mach_device_deallocate(device);
339: return port;
340: #endif
341: }
342:
343: /*
344: * Call a supplied routine on each device, passing it
345: * the port as an argument. If the routine returns TRUE,
346: * stop the search and return TRUE. If none returns TRUE,
347: * return FALSE.
348: */
349: boolean_t
350: dev_map(routine, port)
351: boolean_t (*routine)();
352: mach_port_t port;
353: {
354: register int i;
355: register queue_t q;
356: register mach_device_t dev, prev_dev;
357:
358: for (i = 0, q = &dev_number_hash_table[0];
359: i < NDEVHASH;
360: i++, q++) {
361: prev_dev = MACH_DEVICE_NULL;
362: simple_lock(&dev_number_lock);
363: queue_iterate(q, dev, mach_device_t, number_chain) {
364: mach_device_reference(dev);
365: simple_unlock(&dev_number_lock);
366: if (prev_dev != MACH_DEVICE_NULL)
367: mach_device_deallocate(prev_dev);
368:
369: if ((*routine)(dev, port)) {
370: /*
371: * Done
372: */
373: mach_device_deallocate(dev);
374: return (TRUE);
375: }
376:
377: simple_lock(&dev_number_lock);
378: prev_dev = dev;
379: }
380: simple_unlock(&dev_number_lock);
381: if (prev_dev != MACH_DEVICE_NULL)
382: mach_device_deallocate(prev_dev);
383: }
384: return (FALSE);
385: }
386:
387: /*
388: * Initialization
389: */
390: #define NDEVICES 256
391:
392: void
393: dev_lookup_init()
394: {
395: register int i;
396:
397: simple_lock_init(&dev_number_lock);
398:
399: for (i = 0; i < NDEVHASH; i++)
400: queue_init(&dev_number_hash_table[i]);
401:
402: simple_lock_init(&dev_port_lock);
403:
404: dev_hdr_zone = zinit(sizeof(struct mach_device),
405: sizeof(struct mach_device) * NDEVICES,
406: PAGE_SIZE,
407: FALSE,
408: "open device entry");
409: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.