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 Software.Distribution@CS.CMU.EDU
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 * HISTORY
28 * $Log: dev_lookup.c,v $
29 * Revision 2.12 93/05/10 21:18:15 rvb
30 * Removed depends on DEV_BSIZE, now it is just a default
31 * for backward compat.
32 * [93/05/06 11:09:37 af]
33 *
34 * Revision 2.11 92/08/03 17:33:06 jfriedl
35 * removed silly prototypes
36 * [92/08/02 jfriedl]
37 *
38 * Revision 2.10 92/05/21 17:08:49 jfriedl
39 * tried prototypes.
40 * [92/05/20 jfriedl]
41 *
42 * Revision 2.9 91/06/25 10:26:31 rpd
43 * Changed the convert_foo_to_bar functions
44 * to use ipc_port_t instead of mach_port_t.
45 * [91/05/29 rpd]
46 *
47 * Revision 2.8 91/05/18 14:29:28 rpd
48 * Fixed device_deallocate to always unlock the reference count.
49 * [91/04/03 rpd]
50 *
51 * Revision 2.7 91/05/14 15:40:44 mrt
52 * Correcting copyright
53 *
54 * Revision 2.6 91/02/05 17:08:25 mrt
55 * Changed to new Mach copyright
56 * [91/01/31 17:27:17 mrt]
57 *
58 * Revision 2.5 90/09/09 14:31:13 rpd
59 * Use decl_simple_lock_data.
60 * [90/08/30 rpd]
61 *
62 * Revision 2.4 90/08/27 21:55:02 dbg
63 * Remove obsolete type names and macros.
64 * [90/07/16 dbg]
65 *
66 * Revision 2.3 90/06/02 14:47:14 rpd
67 * Converted to new IPC.
68 * Fixed device leak in convert_device_to_port.
69 * [90/03/26 21:45:09 rpd]
70 *
71 * Revision 2.2 89/09/08 11:23:12 dbg
72 * Modified to run in kernel context. Moved name search routines
73 * to dev_name.c. Reorganized remaining routines. Added
74 * correct locking.
75 * [89/08/01 dbg]
76 *
77 * 5-Jun-89 Randall Dean (rwd) at Carnegie-Mellon University
78 * Added dev_change_indirect for use by sun autoconf (ms,kbd,fb)
79 *
80 * 12-May-89 David Golub (dbg) at Carnegie-Mellon University
81 * Added search through indirection table for certain devices.
82 *
83 * 12-Apr-89 David Golub (dbg) at Carnegie-Mellon University
84 * Added routine to call a function on each device.
85 *
86 * 3-Mar-89 David Golub (dbg) at Carnegie-Mellon University
87 * Created.
88 *
89 */
90 /*
91 * Author: David B. Golub, Carnegie Mellon University
92 * Date: 3/89
93 */
94
95 #include <mach/port.h>
96 #include <mach/vm_param.h>
97
98 #include <kern/queue.h>
99 #include <kern/zalloc.h>
100
101 #include <device/device_types.h>
102 #include <device/dev_hdr.h>
103 #include <device/conf.h>
104 #include <device/param.h> /* DEV_BSIZE, as default */
105
106 #include <ipc/ipc_port.h>
107 #include <kern/ipc_kobject.h>
108
109
110
111 /*
112 * Device structure routines: reference counting, port->device.
113 */
114
115 /*
116 * Lookup/enter by device number.
117 */
118 #define NDEVHASH 8
119 #define DEV_NUMBER_HASH(dev) ((dev) & (NDEVHASH-1))
120 queue_head_t dev_number_hash_table[NDEVHASH];
121
122 /*
123 * Lock for device-number to device lookup.
124 * Must be held before device-ref_count lock.
125 */
126 decl_simple_lock_data(,
127 dev_number_lock)
128
129 zone_t dev_hdr_zone;
130
131 /*
132 * Enter device in the number lookup table.
133 * The number table lock must be held.
134 */
135 void
136 dev_number_enter(device)
137 register device_t device;
138 {
139 register queue_t q;
140
141 q = &dev_number_hash_table[DEV_NUMBER_HASH(device->dev_number)];
142 queue_enter(q, device, device_t, number_chain);
143 }
144
145 /*
146 * Remove device from the device-number lookup table.
147 * The device-number table lock must be held.
148 */
149 void
150 dev_number_remove(device)
151 register device_t device;
152 {
153 register queue_t q;
154
155 q = &dev_number_hash_table[DEV_NUMBER_HASH(device->dev_number)];
156 queue_remove(q, device, device_t, number_chain);
157 }
158
159 /*
160 * Lookup a device by device operations and minor number.
161 * The number table lock must be held.
162 */
163 device_t
164 dev_number_lookup(ops, devnum)
165 dev_ops_t ops;
166 int devnum;
167 {
168 register queue_t q;
169 register device_t device;
170
171 q = &dev_number_hash_table[DEV_NUMBER_HASH(devnum)];
172 queue_iterate(q, device, device_t, number_chain) {
173 if (device->dev_ops == ops && device->dev_number == devnum) {
174 return (device);
175 }
176 }
177 return (DEVICE_NULL);
178 }
179
180 /*
181 * Look up a device by name, and create the device structure
182 * if it does not exist. Enter it in the dev_number lookup
183 * table.
184 */
185 device_t
186 device_lookup(name)
187 char * name;
188 {
189 dev_ops_t dev_ops;
190 int dev_minor;
191 register device_t device;
192 register device_t new_device;
193
194 /*
195 * Get the device and unit number from the name.
196 */
197 if (!dev_name_lookup(name, &dev_ops, &dev_minor))
198 return (DEVICE_NULL);
199
200 /*
201 * Look up the device in the hash table. If it is
202 * not there, enter it.
203 */
204 new_device = DEVICE_NULL;
205 simple_lock(&dev_number_lock);
206 while ((device = dev_number_lookup(dev_ops, dev_minor))
207 == DEVICE_NULL) {
208 /*
209 * Must unlock to allocate the structure. If
210 * the structure has appeared after we have allocated,
211 * release the new structure.
212 */
213 if (new_device != DEVICE_NULL)
214 break; /* allocated */
215
216 simple_unlock(&dev_number_lock);
217
218 new_device = (device_t) zalloc(dev_hdr_zone);
219 simple_lock_init(&new_device->ref_lock);
220 new_device->ref_count = 1;
221 simple_lock_init(&new_device->lock);
222 new_device->state = DEV_STATE_INIT;
223 new_device->flag = 0;
224 new_device->open_count = 0;
225 new_device->io_in_progress = 0;
226 new_device->io_wait = FALSE;
227 new_device->port = IP_NULL;
228 new_device->dev_ops = dev_ops;
229 new_device->dev_number = dev_minor;
230 new_device->bsize = DEV_BSIZE; /* change later */
231
232 simple_lock(&dev_number_lock);
233 }
234
235 if (device == DEVICE_NULL) {
236 /*
237 * No existing device structure. Insert the
238 * new one.
239 */
240 assert(new_device != DEVICE_NULL);
241 device = new_device;
242
243 dev_number_enter(device);
244 simple_unlock(&dev_number_lock);
245 }
246 else {
247 /*
248 * Have existing device.
249 */
250 device_reference(device);
251 simple_unlock(&dev_number_lock);
252
253 if (new_device != DEVICE_NULL)
254 zfree(dev_hdr_zone, (vm_offset_t)new_device);
255 }
256
257 return (device);
258 }
259
260 /*
261 * Add a reference to the device.
262 */
263 void
264 device_reference(device)
265 register device_t device;
266 {
267 simple_lock(&device->ref_lock);
268 device->ref_count++;
269 simple_unlock(&device->ref_lock);
270 }
271
272 /*
273 * Remove a reference to the device, and deallocate the
274 * structure if no references are left.
275 */
276 void
277 device_deallocate(device)
278 register device_t device;
279 {
280 simple_lock(&device->ref_lock);
281 if (--device->ref_count > 0) {
282 simple_unlock(&device->ref_lock);
283 return;
284 }
285 device->ref_count = 1;
286 simple_unlock(&device->ref_lock);
287
288 simple_lock(&dev_number_lock);
289 simple_lock(&device->ref_lock);
290 if (--device->ref_count > 0) {
291 simple_unlock(&device->ref_lock);
292 simple_unlock(&dev_number_lock);
293 return;
294 }
295
296 dev_number_remove(device);
297 simple_unlock(&device->ref_lock);
298 simple_unlock(&dev_number_lock);
299
300 zfree(dev_hdr_zone, (vm_offset_t)device);
301 }
302
303 /*
304
305 */
306 /*
307 * port-to-device lookup routines.
308 */
309 decl_simple_lock_data(,
310 dev_port_lock)
311
312 /*
313 * Enter a port-to-device mapping.
314 */
315 void
316 dev_port_enter(device)
317 register device_t device;
318 {
319 device_reference(device);
320 ipc_kobject_set(device->port, (ipc_kobject_t) device, IKOT_DEVICE);
321 }
322
323 /*
324 * Remove a port-to-device mapping.
325 */
326 void
327 dev_port_remove(device)
328 register device_t device;
329 {
330 ipc_kobject_set(device->port, IKO_NULL, IKOT_NONE);
331 device_deallocate(device);
332 }
333
334 /*
335 * Lookup a device by its port.
336 * Doesn't consume the naked send right; produces a device reference.
337 */
338 device_t
339 dev_port_lookup(port)
340 ipc_port_t port;
341 {
342 register device_t device;
343
344 if (!IP_VALID(port))
345 return (DEVICE_NULL);
346
347 ip_lock(port);
348 if (ip_active(port) && (ip_kotype(port) == IKOT_DEVICE)) {
349 device = (device_t) port->ip_kobject;
350 device_reference(device);
351 }
352 else
353 device = DEVICE_NULL;
354
355 ip_unlock(port);
356 return (device);
357 }
358
359 /*
360 * Get the port for a device.
361 * Consumes a device reference; produces a naked send right.
362 */
363 ipc_port_t
364 convert_device_to_port(device)
365 register device_t device;
366 {
367 register ipc_port_t port;
368
369 if (device == DEVICE_NULL)
370 return IP_NULL;
371
372 device_lock(device);
373 if (device->state == DEV_STATE_OPEN)
374 port = ipc_port_make_send(device->port);
375 else
376 port = IP_NULL;
377 device_unlock(device);
378
379 device_deallocate(device);
380 return port;
381 }
382
383 /*
384 * Call a supplied routine on each device, passing it
385 * the port as an argument. If the routine returns TRUE,
386 * stop the search and return TRUE. If none returns TRUE,
387 * return FALSE.
388 */
389 boolean_t
390 dev_map(routine, port)
391 boolean_t (*routine)();
392 mach_port_t port;
393 {
394 register int i;
395 register queue_t q;
396 register device_t dev, prev_dev;
397
398 for (i = 0, q = &dev_number_hash_table[0];
399 i < NDEVHASH;
400 i++, q++) {
401 prev_dev = DEVICE_NULL;
402 simple_lock(&dev_number_lock);
403 queue_iterate(q, dev, device_t, number_chain) {
404 device_reference(dev);
405 simple_unlock(&dev_number_lock);
406 if (prev_dev != DEVICE_NULL)
407 device_deallocate(prev_dev);
408
409 if ((*routine)(dev, port)) {
410 /*
411 * Done
412 */
413 device_deallocate(dev);
414 return (TRUE);
415 }
416
417 simple_lock(&dev_number_lock);
418 prev_dev = dev;
419 }
420 simple_unlock(&dev_number_lock);
421 if (prev_dev != DEVICE_NULL)
422 device_deallocate(prev_dev);
423 }
424 return (FALSE);
425 }
426
427 /*
428 * Initialization
429 */
430 #define NDEVICES 256
431
432 void
433 dev_lookup_init()
434 {
435 register int i;
436
437 simple_lock_init(&dev_number_lock);
438
439 for (i = 0; i < NDEVHASH; i++)
440 queue_init(&dev_number_hash_table[i]);
441
442 simple_lock_init(&dev_port_lock);
443
444 dev_hdr_zone = zinit(sizeof(struct device),
445 sizeof(struct device) * NDEVICES,
446 PAGE_SIZE,
447 FALSE,
448 "open device entry");
449 }
Cache object: f1077d09e091e276422fbe05783982c3
|