|
|
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.