|
|
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>
1.1.1.2 ! root 35: #include <kern/slab.h>
1.1 root 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:
1.1.1.2 ! root 45: #include <device/device_emul.h>
1.1 root 46:
47: /*
48: * Device structure routines: reference counting, port->device.
49: */
50:
51: /*
52: * Lookup/enter by device number.
53: */
54: #define NDEVHASH 8
55: #define DEV_NUMBER_HASH(dev) ((dev) & (NDEVHASH-1))
56: queue_head_t dev_number_hash_table[NDEVHASH];
57:
58: /*
59: * Lock for device-number to device lookup.
60: * Must be held before device-ref_count lock.
61: */
62: decl_simple_lock_data(,
63: dev_number_lock)
64:
1.1.1.2 ! root 65: struct kmem_cache dev_hdr_cache;
1.1 root 66:
67: /*
68: * Enter device in the number lookup table.
69: * The number table lock must be held.
70: */
71: void
72: dev_number_enter(device)
1.1.1.2 ! root 73: mach_device_t device;
1.1 root 74: {
1.1.1.2 ! root 75: queue_t q;
1.1 root 76:
77: q = &dev_number_hash_table[DEV_NUMBER_HASH(device->dev_number)];
78: queue_enter(q, device, mach_device_t, number_chain);
79: }
80:
81: /*
82: * Remove device from the device-number lookup table.
83: * The device-number table lock must be held.
84: */
85: void
86: dev_number_remove(device)
1.1.1.2 ! root 87: mach_device_t device;
1.1 root 88: {
1.1.1.2 ! root 89: queue_t q;
1.1 root 90:
91: q = &dev_number_hash_table[DEV_NUMBER_HASH(device->dev_number)];
92: queue_remove(q, device, mach_device_t, number_chain);
93: }
94:
95: /*
96: * Lookup a device by device operations and minor number.
97: * The number table lock must be held.
98: */
99: mach_device_t
100: dev_number_lookup(ops, devnum)
101: dev_ops_t ops;
102: int devnum;
103: {
1.1.1.2 ! root 104: queue_t q;
! 105: mach_device_t device;
1.1 root 106:
107: q = &dev_number_hash_table[DEV_NUMBER_HASH(devnum)];
108: queue_iterate(q, device, mach_device_t, number_chain) {
109: if (device->dev_ops == ops && device->dev_number == devnum) {
110: return (device);
111: }
112: }
113: return (MACH_DEVICE_NULL);
114: }
115:
116: /*
117: * Look up a device by name, and create the device structure
118: * if it does not exist. Enter it in the dev_number lookup
119: * table.
120: */
121: mach_device_t
122: device_lookup(name)
123: char * name;
124: {
125: dev_ops_t dev_ops;
126: int dev_minor;
1.1.1.2 ! root 127: mach_device_t device;
! 128: mach_device_t new_device;
1.1 root 129:
130: /*
131: * Get the device and unit number from the name.
132: */
133: if (!dev_name_lookup(name, &dev_ops, &dev_minor))
134: return (MACH_DEVICE_NULL);
135:
136: /*
137: * Look up the device in the hash table. If it is
138: * not there, enter it.
139: */
140: new_device = MACH_DEVICE_NULL;
141: simple_lock(&dev_number_lock);
142: while ((device = dev_number_lookup(dev_ops, dev_minor))
143: == MACH_DEVICE_NULL) {
144: /*
145: * Must unlock to allocate the structure. If
146: * the structure has appeared after we have allocated,
147: * release the new structure.
148: */
149: if (new_device != MACH_DEVICE_NULL)
150: break; /* allocated */
151:
152: simple_unlock(&dev_number_lock);
153:
1.1.1.2 ! root 154: new_device = (mach_device_t) kmem_cache_alloc(&dev_hdr_cache);
1.1 root 155: simple_lock_init(&new_device->ref_lock);
156: new_device->ref_count = 1;
157: simple_lock_init(&new_device->lock);
158: new_device->state = DEV_STATE_INIT;
159: new_device->flag = 0;
160: new_device->open_count = 0;
161: new_device->io_in_progress = 0;
162: new_device->io_wait = FALSE;
163: new_device->port = IP_NULL;
164: new_device->dev_ops = dev_ops;
165: new_device->dev_number = dev_minor;
166: new_device->bsize = DEV_BSIZE; /* change later */
167:
168: simple_lock(&dev_number_lock);
169: }
170:
171: if (device == MACH_DEVICE_NULL) {
172: /*
173: * No existing device structure. Insert the
174: * new one.
175: */
176: assert(new_device != MACH_DEVICE_NULL);
177: device = new_device;
178:
179: dev_number_enter(device);
180: simple_unlock(&dev_number_lock);
181: }
182: else {
183: /*
184: * Have existing device.
185: */
186: mach_device_reference(device);
187: simple_unlock(&dev_number_lock);
188:
189: if (new_device != MACH_DEVICE_NULL)
1.1.1.2 ! root 190: kmem_cache_free(&dev_hdr_cache, (vm_offset_t)new_device);
1.1 root 191: }
192:
193: return (device);
194: }
195:
196: /*
197: * Add a reference to the device.
198: */
199: void
200: mach_device_reference(device)
1.1.1.2 ! root 201: mach_device_t device;
1.1 root 202: {
203: simple_lock(&device->ref_lock);
204: device->ref_count++;
205: simple_unlock(&device->ref_lock);
206: }
207:
208: /*
209: * Remove a reference to the device, and deallocate the
210: * structure if no references are left.
211: */
212: void
213: mach_device_deallocate(device)
1.1.1.2 ! root 214: mach_device_t device;
1.1 root 215: {
216: simple_lock(&device->ref_lock);
217: if (--device->ref_count > 0) {
218: simple_unlock(&device->ref_lock);
219: return;
220: }
221: device->ref_count = 1;
222: simple_unlock(&device->ref_lock);
223:
224: simple_lock(&dev_number_lock);
225: simple_lock(&device->ref_lock);
226: if (--device->ref_count > 0) {
227: simple_unlock(&device->ref_lock);
228: simple_unlock(&dev_number_lock);
229: return;
230: }
231:
232: dev_number_remove(device);
233: simple_unlock(&device->ref_lock);
234: simple_unlock(&dev_number_lock);
235:
1.1.1.2 ! root 236: kmem_cache_free(&dev_hdr_cache, (vm_offset_t)device);
1.1 root 237: }
238:
239: /*
240:
241: */
242: /*
243: * port-to-device lookup routines.
244: */
245: decl_simple_lock_data(,
246: dev_port_lock)
247:
248: /*
249: * Enter a port-to-device mapping.
250: */
251: void
252: dev_port_enter(device)
1.1.1.2 ! root 253: mach_device_t device;
1.1 root 254: {
255: mach_device_reference(device);
1.1.1.2 ! root 256:
1.1 root 257: ipc_kobject_set(device->port,
258: (ipc_kobject_t) &device->dev, IKOT_DEVICE);
259: device->dev.emul_data = device;
260: {
261: extern struct device_emulation_ops mach_device_emulation_ops;
262:
263: device->dev.emul_ops = &mach_device_emulation_ops;
264: }
265: }
266:
267: /*
268: * Remove a port-to-device mapping.
269: */
270: void
271: dev_port_remove(device)
1.1.1.2 ! root 272: mach_device_t device;
1.1 root 273: {
274: ipc_kobject_set(device->port, IKO_NULL, IKOT_NONE);
275: mach_device_deallocate(device);
276: }
277:
278: /*
279: * Lookup a device by its port.
280: * Doesn't consume the naked send right; produces a device reference.
281: */
282: device_t
283: dev_port_lookup(port)
284: ipc_port_t port;
285: {
1.1.1.2 ! root 286: device_t device;
1.1 root 287:
288: if (!IP_VALID(port))
289: return (DEVICE_NULL);
290:
291: ip_lock(port);
292: if (ip_active(port) && (ip_kotype(port) == IKOT_DEVICE)) {
293: device = (device_t) port->ip_kobject;
294: if (device->emul_ops->reference)
295: (*device->emul_ops->reference)(device->emul_data);
296: }
297: else
298: device = DEVICE_NULL;
299:
300: ip_unlock(port);
301: return (device);
302: }
303:
304: /*
305: * Get the port for a device.
306: * Consumes a device reference; produces a naked send right.
307: */
308: ipc_port_t
309: convert_device_to_port(device)
1.1.1.2 ! root 310: device_t device;
1.1 root 311: {
312: if (device == DEVICE_NULL)
313: return IP_NULL;
314:
315: return (*device->emul_ops->dev_to_port) (device->emul_data);
316: }
317:
318: /*
319: * Call a supplied routine on each device, passing it
320: * the port as an argument. If the routine returns TRUE,
321: * stop the search and return TRUE. If none returns TRUE,
322: * return FALSE.
323: */
324: boolean_t
325: dev_map(routine, port)
326: boolean_t (*routine)();
327: mach_port_t port;
328: {
1.1.1.2 ! root 329: int i;
! 330: queue_t q;
! 331: mach_device_t dev, prev_dev;
1.1 root 332:
333: for (i = 0, q = &dev_number_hash_table[0];
334: i < NDEVHASH;
335: i++, q++) {
336: prev_dev = MACH_DEVICE_NULL;
337: simple_lock(&dev_number_lock);
338: queue_iterate(q, dev, mach_device_t, number_chain) {
339: mach_device_reference(dev);
340: simple_unlock(&dev_number_lock);
341: if (prev_dev != MACH_DEVICE_NULL)
342: mach_device_deallocate(prev_dev);
343:
344: if ((*routine)(dev, port)) {
345: /*
346: * Done
347: */
348: mach_device_deallocate(dev);
349: return (TRUE);
350: }
351:
352: simple_lock(&dev_number_lock);
353: prev_dev = dev;
354: }
355: simple_unlock(&dev_number_lock);
356: if (prev_dev != MACH_DEVICE_NULL)
357: mach_device_deallocate(prev_dev);
358: }
359: return (FALSE);
360: }
361:
362: /*
363: * Initialization
364: */
365: void
366: dev_lookup_init()
367: {
1.1.1.2 ! root 368: int i;
1.1 root 369:
370: simple_lock_init(&dev_number_lock);
371:
372: for (i = 0; i < NDEVHASH; i++)
373: queue_init(&dev_number_hash_table[i]);
374:
375: simple_lock_init(&dev_port_lock);
376:
1.1.1.2 ! root 377: kmem_cache_init(&dev_hdr_cache, "mach_device",
! 378: sizeof(struct mach_device), 0, NULL, NULL, NULL, 0);
1.1 root 379: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.