The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/device/dev_lookup.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.