devsupport.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:31k
- /* $Id$
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
- * Copyright (C) 2000 by Colin Ngam
- */
- #include <linux/types.h>
- #include <linux/mm.h>
- #include <linux/slab.h>
- #include <asm/sn/sgi.h>
- #include <asm/sn/invent.h>
- #include <asm/sn/hcl.h>
- #include <asm/sn/iobus.h>
- #include <asm/sn/iograph.h>
- /*
- * Interfaces in this file are all platform-independent AND IObus-independent.
- * Be aware that there may be macro equivalents to each of these hiding in
- * header files which supercede these functions.
- */
- /* =====Generic iobus support===== */
- /* String table to hold names of interrupts. */
- #ifdef LATER
- static struct string_table device_desc_string_table;
- #endif
- /* One time initialization for device descriptor support. */
- static void
- device_desc_init(void)
- {
- #ifdef LATER
- string_table_init(&device_desc_string_table);
- #endif
- FIXME("device_desc_init");
- }
- /* Drivers use these interfaces to manage device descriptors */
- static device_desc_t
- device_desc_alloc(void)
- {
- #ifdef LATER
- device_desc_t device_desc;
- device_desc = (device_desc_t)kmem_zalloc(sizeof(struct device_desc_s), 0);
- device_desc->intr_target = GRAPH_VERTEX_NONE;
- ASSERT(device_desc->intr_policy == 0);
- device_desc->intr_swlevel = -1;
- ASSERT(device_desc->intr_name == NULL);
- ASSERT(device_desc->flags == 0);
- ASSERT(!(device_desc->flags & D_IS_ASSOC));
- return(device_desc);
- #else
- FIXME("device_desc_alloc");
- return((device_desc_t)0);
- #endif
- }
- void
- device_desc_free(device_desc_t device_desc)
- {
- #ifdef LATER
- if (!(device_desc->flags & D_IS_ASSOC)) /* sanity */
- kfree(device_desc);
- #endif
- FIXME("device_desc_free");
- }
- device_desc_t
- device_desc_dup(devfs_handle_t dev)
- {
- #ifdef LATER
- device_desc_t orig_device_desc, new_device_desc;
- new_device_desc = device_desc_alloc();
- orig_device_desc = device_desc_default_get(dev);
- if (orig_device_desc)
- *new_device_desc = *orig_device_desc;/* small structure copy */
- else {
- device_driver_t driver;
- ilvl_t pri;
- /*
- * Use the driver's thread priority in
- * case the device thread priority has not
- * been given.
- */
- if (driver = device_driver_getbydev(dev)) {
- pri = device_driver_thread_pri_get(driver);
- device_desc_intr_swlevel_set(new_device_desc,pri);
- }
- }
- new_device_desc->flags &= ~D_IS_ASSOC;
- return(new_device_desc);
- #else
- FIXME("device_desc_dup");
- return((device_desc_t)0);
- #endif
- }
- device_desc_t
- device_desc_default_get(devfs_handle_t dev)
- {
- #ifdef LATER
- graph_error_t rc;
- device_desc_t device_desc;
- rc = hwgraph_info_get_LBL(dev, INFO_LBL_DEVICE_DESC, (arbitrary_info_t *)&device_desc);
- if (rc == GRAPH_SUCCESS)
- return(device_desc);
- else
- return(NULL);
- #else
- FIXME("device_desc_default_get");
- return((device_desc_t)0);
- #endif
- }
- void
- device_desc_default_set(devfs_handle_t dev, device_desc_t new_device_desc)
- {
- #ifdef LATER
- graph_error_t rc;
- device_desc_t old_device_desc = NULL;
- if (new_device_desc) {
- new_device_desc->flags |= D_IS_ASSOC;
- rc = hwgraph_info_add_LBL(dev, INFO_LBL_DEVICE_DESC,
- (arbitrary_info_t)new_device_desc);
- if (rc == GRAPH_DUP) {
- rc = hwgraph_info_replace_LBL(dev, INFO_LBL_DEVICE_DESC,
- (arbitrary_info_t)new_device_desc,
- (arbitrary_info_t *)&old_device_desc);
- ASSERT(rc == GRAPH_SUCCESS);
- }
- hwgraph_info_export_LBL(dev, INFO_LBL_DEVICE_DESC,
- sizeof(struct device_desc_s));
- } else {
- rc = hwgraph_info_remove_LBL(dev, INFO_LBL_DEVICE_DESC,
- (arbitrary_info_t *)&old_device_desc);
- }
- if (old_device_desc) {
- ASSERT(old_device_desc->flags & D_IS_ASSOC);
- old_device_desc->flags &= ~D_IS_ASSOC;
- device_desc_free(old_device_desc);
- }
- #endif
- FIXME("device_desc_default_set");
- }
- devfs_handle_t
- device_desc_intr_target_get(device_desc_t device_desc)
- {
- #ifdef LATER
- return(device_desc->intr_target);
- #else
- FIXME("device_desc_intr_target_get");
- return((devfs_handle_t)0);
- #endif
- }
- int
- device_desc_intr_policy_get(device_desc_t device_desc)
- {
- #ifdef LATER
- return(device_desc->intr_policy);
- #else
- FIXME("device_desc_intr_policy_get");
- return(0);
- #endif
- }
- ilvl_t
- device_desc_intr_swlevel_get(device_desc_t device_desc)
- {
- #ifdef LATER
- return(device_desc->intr_swlevel);
- #else
- FIXME("device_desc_intr_swlevel_get");
- return((ilvl_t)0);
- #endif
- }
- char *
- device_desc_intr_name_get(device_desc_t device_desc)
- {
- #ifdef LATER
- return(device_desc->intr_name);
- #else
- FIXME("device_desc_intr_name_get");
- return(NULL);
- #endif
- }
- int
- device_desc_flags_get(device_desc_t device_desc)
- {
- #ifdef LATER
- return(device_desc->flags);
- #else
- FIXME("device_desc_flags_get");
- return(0);
- #endif
- }
- void
- device_desc_intr_target_set(device_desc_t device_desc, devfs_handle_t target)
- {
- if ( device_desc != (device_desc_t)0 )
- device_desc->intr_target = target;
- }
- void
- device_desc_intr_policy_set(device_desc_t device_desc, int policy)
- {
- if ( device_desc != (device_desc_t)0 )
- device_desc->intr_policy = policy;
- }
- void
- device_desc_intr_swlevel_set(device_desc_t device_desc, ilvl_t swlevel)
- {
- if ( device_desc != (device_desc_t)0 )
- device_desc->intr_swlevel = swlevel;
- }
- void
- device_desc_intr_name_set(device_desc_t device_desc, char *name)
- {
- #ifdef LATER
- if ( device_desc != (device_desc_t)0 )
- device_desc->intr_name = string_table_insert(&device_desc_string_table, name);
- #else
- FIXME("device_desc_intr_name_set");
- #endif
- }
- void
- device_desc_flags_set(device_desc_t device_desc, int flags)
- {
- if ( device_desc != (device_desc_t)0 )
- device_desc->flags = flags;
- }
- /*============= device admin registry routines ===================== */
- /* Linked list of <admin-name,admin-val> pairs */
- typedef struct dev_admin_list_s {
- struct dev_admin_list_s *admin_next; /* next entry in the
- * list
- */
- char *admin_name; /* info label */
- char *admin_val; /* actual info */
- } dev_admin_list_t;
- /* Device/Driver administration registry */
- typedef struct dev_admin_registry_s {
- mrlock_t reg_lock; /* To allow
- * exclusive
- * access
- */
- dev_admin_list_t *reg_first; /* first entry in
- * the list
- */
- dev_admin_list_t **reg_last; /* pointer to the
- * next to last entry
- * in the last which
- * is also the place
- * where the new
- * entry gets
- * inserted
- */
- } dev_admin_registry_t;
- /*
- ** device_driver_s associates a device driver prefix with device switch entries.
- */
- struct device_driver_s {
- struct device_driver_s *dd_next; /* next element on hash chain */
- struct device_driver_s *dd_prev; /* previous element on hash chain */
- char *dd_prefix; /* driver prefix string */
- struct bdevsw *dd_bdevsw; /* driver's bdevsw */
- struct cdevsw *dd_cdevsw; /* driver's cdevsw */
-
- /* driver administration specific data structures need to
- * maintain the list of <driver-paramater,value> pairs
- */
- dev_admin_registry_t dd_dev_admin_registry;
- ilvl_t dd_thread_pri; /* default thread priority for
- * all this driver's
- * threads.
- */
- };
- #define NEW(_p) (_p = kmalloc(sizeof(*_p), GFP_KERNEL))
- #define FREE(_p) (kmem_free(_p))
-
- /*
- * helpful lock macros
- */
- #define DEV_ADMIN_REGISTRY_INITLOCK(lockp,name) mrinit(lockp,name)
- #define DEV_ADMIN_REGISTRY_RDLOCK(lockp) mraccess(lockp)
- #define DEV_ADMIN_REGISTRY_WRLOCK(lockp) mrupdate(lockp)
- #define DEV_ADMIN_REGISTRY_UNLOCK(lockp) mrunlock(lockp)
- /* Initialize the registry
- */
- static void
- dev_admin_registry_init(dev_admin_registry_t *registry)
- {
- #ifdef LATER
- if ( registry != (dev_admin_registry_t *)0 )
- DEV_ADMIN_REGISTRY_INITLOCK(®istry->reg_lock,
- "dev_admin_registry_lock");
- registry->reg_first = NULL;
- registry->reg_last = ®istry->reg_first;
- }
- #else
- FIXME("dev_admin_registry_init");
- #endif
- }
- /*
- * add an <name , value > entry to the dev admin registry.
- * if the name already exists in the registry then change the
- * value iff the new value differs from the old value.
- * if the name doesn't exist a new list entry is created and put
- * at the end.
- */
- static void
- dev_admin_registry_add(dev_admin_registry_t *registry,
- char *name,
- char *val)
- {
- #ifdef LATER
- dev_admin_list_t *reg_entry;
- dev_admin_list_t *scan = 0;
- DEV_ADMIN_REGISTRY_WRLOCK(®istry->reg_lock);
- /* check if the name already exists in the registry */
- scan = registry->reg_first;
- while (scan) {
- if (strcmp(scan->admin_name,name) == 0) {
- /* name is there in the registry */
- if (strcmp(scan->admin_val,val)) {
- /* old value != new value
- * reallocate memory and copy the new value
- */
- FREE(scan->admin_val);
- scan->admin_val =
- (char *)kern_calloc(1,strlen(val)+1);
- strcpy(scan->admin_val,val);
- goto out;
- }
- goto out; /* old value == new value */
- }
- scan = scan->admin_next;
- }
- /* name is not there in the registry.
- * allocate memory for the new registry entry
- */
- NEW(reg_entry);
-
- reg_entry->admin_next = 0;
- reg_entry->admin_name = (char *)kern_calloc(1,strlen(name)+1);
- strcpy(reg_entry->admin_name,name);
- reg_entry->admin_val = (char *)kern_calloc(1,strlen(val)+1);
- strcpy(reg_entry->admin_val,val);
- /* add the entry at the end of the registry */
- *(registry->reg_last) = reg_entry;
- registry->reg_last = ®_entry->admin_next;
- out: DEV_ADMIN_REGISTRY_UNLOCK(®istry->reg_lock);
- #endif
- FIXME("dev_admin_registry_add");
- }
- /*
- * check if there is an info corr. to a particular
- * name starting from the cursor position in the
- * registry
- */
- static char *
- dev_admin_registry_find(dev_admin_registry_t *registry,char *name)
- {
- #ifdef LATER
- dev_admin_list_t *scan = 0;
-
- DEV_ADMIN_REGISTRY_RDLOCK(®istry->reg_lock);
- scan = registry->reg_first;
- while (scan) {
- if (strcmp(scan->admin_name,name) == 0) {
- DEV_ADMIN_REGISTRY_UNLOCK(®istry->reg_lock);
- return scan->admin_val;
- }
- scan = scan->admin_next;
- }
- DEV_ADMIN_REGISTRY_UNLOCK(®istry->reg_lock);
- return 0;
- #else
- FIXME("dev_admin_registry_find");
- return(NULL);
- #endif
- }
- /*============= MAIN DEVICE/ DRIVER ADMINISTRATION INTERFACE================ */
- /*
- * return any labelled info associated with a device.
- * called by any kernel code including device drivers.
- */
- char *
- device_admin_info_get(devfs_handle_t dev_vhdl,
- char *info_lbl)
- {
- #ifdef LATER
- char *info = 0;
- /* return value need not be GRAPH_SUCCESS as the labelled
- * info may not be present
- */
- (void)hwgraph_info_get_LBL(dev_vhdl,info_lbl,
- (arbitrary_info_t *)&info);
-
- return info;
- #else
- FIXME("device_admin_info_get");
- return(NULL);
- #endif
- }
- /*
- * set labelled info associated with a device.
- * called by hwgraph infrastructure . may also be called
- * by device drivers etc.
- */
- int
- device_admin_info_set(devfs_handle_t dev_vhdl,
- char *dev_info_lbl,
- char *dev_info_val)
- {
- #ifdef LATER
- graph_error_t rv;
- arbitrary_info_t old_info;
- /* Handle the labelled info
- * intr_target
- * sw_level
- * in a special way. These are part of device_desc_t
- * Right now this is the only case where we have
- * a set of related device_admin attributes which
- * are grouped together.
- * In case there is a need for another set we need to
- * take a more generic approach to solving this.
- * Basically a registry should be implemented. This
- * registry is initialized with the callbacks for the
- * attributes which need to handled in a special way
- * For example:
- * Consider
- * device_desc
- * intr_target
- * intr_swlevel
- * register "do_intr_target" for intr_target
- * register "do_intr_swlevel" for intr_swlevel.
- * When the device_admin interface layer gets an <attr,val> pair
- * it looks in the registry to see if there is a function registered to
- * handle "attr. If not follow the default path of setting the <attr,val>
- * as labelled information hanging off the vertex.
- * In the above example:
- * "do_intr_target" does what is being done below for the ADMIN_LBL_INTR_TARGET
- * case
- */
- if (!strcmp(dev_info_lbl,ADMIN_LBL_INTR_TARGET) ||
- !strcmp(dev_info_lbl,ADMIN_LBL_INTR_SWLEVEL)) {
- device_desc_t device_desc;
-
- /* Check if there is a default device descriptor
- * information for this vertex. If not dup one .
- */
- if (!(device_desc = device_desc_default_get(dev_vhdl))) {
- device_desc = device_desc_dup(dev_vhdl);
- device_desc_default_set(dev_vhdl,device_desc);
- }
- if (!strcmp(dev_info_lbl,ADMIN_LBL_INTR_TARGET)) {
- /* Check if a target cpu has been specified
- * for this device by a device administration
- * directive
- */
- #ifdef DEBUG
- printf(ADMIN_LBL_INTR_TARGET
- " dev = 0x%x "
- "dev_admin_info = %s"
- " target = 0x%xn",
- dev_vhdl,
- dev_info_lbl,
- hwgraph_path_to_vertex(dev_info_val));
- #endif
- device_desc->intr_target =
- hwgraph_path_to_vertex(dev_info_val);
- } else if (!strcmp(dev_info_lbl,ADMIN_LBL_INTR_SWLEVEL)) {
- /* Check if the ithread priority level has been
- * specified for this device by a device administration
- * directive
- */
- #ifdef DEBUG
- printf(ADMIN_LBL_INTR_SWLEVEL
- " dev = 0x%x "
- "dev_admin_info = %s"
- " sw level = 0x%xn",
- dev_vhdl,
- dev_info_lbl,
- atoi(dev_info_val));
- #endif
- device_desc->intr_swlevel = atoi(dev_info_val);
- }
- }
- if (!dev_info_val)
- rv = hwgraph_info_remove_LBL(dev_vhdl,
- dev_info_lbl,
- &old_info);
- else {
- rv = hwgraph_info_add_LBL(dev_vhdl,
- dev_info_lbl,
- (arbitrary_info_t)dev_info_val);
-
- if (rv == GRAPH_DUP) {
- rv = hwgraph_info_replace_LBL(dev_vhdl,
- dev_info_lbl,
- (arbitrary_info_t)dev_info_val,
- &old_info);
- }
- }
- ASSERT(rv == GRAPH_SUCCESS);
- #endif
- FIXME("device_admin_info_set");
- return 0;
- }
- /*
- * return labelled info associated with a device driver
- * called by kernel code including device drivers
- */
- char *
- device_driver_admin_info_get(char *driver_prefix,
- char *driver_info_lbl)
- {
- #ifdef LATER
- device_driver_t driver;
- driver = device_driver_get(driver_prefix);
- return (dev_admin_registry_find(&driver->dd_dev_admin_registry,
- driver_info_lbl));
- #else
- FIXME("device_driver_admin_info_get");
- return(NULL);
- #endif
- }
- /*
- * set labelled info associated with a device driver.
- * called by hwgraph infrastructure . may also be called
- * from drivers etc.
- */
- int
- device_driver_admin_info_set(char *driver_prefix,
- char *driver_info_lbl,
- char *driver_info_val)
- {
- #ifdef LATER
- device_driver_t driver;
- driver = device_driver_get(driver_prefix);
- dev_admin_registry_add(&driver->dd_dev_admin_registry,
- driver_info_lbl,
- driver_info_val);
- #endif
- FIXME("device_driver_admin_info_set");
- return 0;
- }
- /*================== device / driver admin support routines================*/
- /* static tables created by lboot */
- extern dev_admin_info_t dev_admin_table[];
- extern dev_admin_info_t drv_admin_table[];
- extern int dev_admin_table_size;
- extern int drv_admin_table_size;
- /* Extend the device admin table to allow the kernel startup code to
- * provide some device specific administrative hints
- */
- #define ADMIN_TABLE_CHUNK 100
- static dev_admin_info_t extended_dev_admin_table[ADMIN_TABLE_CHUNK];
- static int extended_dev_admin_table_size = 0;
- static mrlock_t extended_dev_admin_table_lock;
- /* Initialize the extended device admin table */
- void
- device_admin_table_init(void)
- {
- #ifdef LATER
- extended_dev_admin_table_size = 0;
- mrinit(&extended_dev_admin_table_lock,
- "extended_dev_admin_table_lock");
- #endif
- FIXME("device_admin_table_init");
- }
- /* Add <device-name , parameter-name , parameter-value> triple to
- * the extended device administration info table. This is helpful
- * for kernel startup code to put some hints before the hwgraph
- * is setup
- */
- void
- device_admin_table_update(char *name,char *label,char *value)
- {
- #ifdef LATER
- dev_admin_info_t *p;
- mrupdate(&extended_dev_admin_table_lock);
- /* Safety check that we haven't exceeded array limits */
- ASSERT(extended_dev_admin_table_size < ADMIN_TABLE_CHUNK);
- if (extended_dev_admin_table_size == ADMIN_TABLE_CHUNK)
- goto out;
-
- /* Get the pointer to the entry in the table where we are
- * going to put the new information
- */
- p = &extended_dev_admin_table[extended_dev_admin_table_size++];
- /* Allocate memory for the strings and copy them in */
- p->dai_name = (char *)kern_calloc(1,strlen(name)+1);
- strcpy(p->dai_name,name);
- p->dai_param_name = (char *)kern_calloc(1,strlen(label)+1);
- strcpy(p->dai_param_name,label);
- p->dai_param_val = (char *)kern_calloc(1,strlen(value)+1);
- strcpy(p->dai_param_val,value);
- out: mrunlock(&extended_dev_admin_table_lock);
- #endif
- FIXME("device_admin_table_update");
- }
- /* Extend the device driver admin table to allow the kernel startup code to
- * provide some device driver specific administrative hints
- */
- static dev_admin_info_t extended_drv_admin_table[ADMIN_TABLE_CHUNK];
- static int extended_drv_admin_table_size = 0;
- mrlock_t extended_drv_admin_table_lock;
- /* Initialize the extended device driver admin table */
- void
- device_driver_admin_table_init(void)
- {
- #ifdef LATER
- extended_drv_admin_table_size = 0;
- mrinit(&extended_drv_admin_table_lock,
- "extended_drv_admin_table_lock");
- #endif
- FIXME("device_driver_admin_table_init");
- }
- /* Add <device-driver prefix , parameter-name , parameter-value> triple to
- * the extended device administration info table. This is helpful
- * for kernel startup code to put some hints before the hwgraph
- * is setup
- */
- void
- device_driver_admin_table_update(char *name,char *label,char *value)
- {
- #ifdef LATER
- dev_admin_info_t *p;
- mrupdate(&extended_dev_admin_table_lock);
- /* Safety check that we haven't exceeded array limits */
- ASSERT(extended_drv_admin_table_size < ADMIN_TABLE_CHUNK);
- if (extended_drv_admin_table_size == ADMIN_TABLE_CHUNK)
- goto out;
-
- /* Get the pointer to the entry in the table where we are
- * going to put the new information
- */
- p = &extended_drv_admin_table[extended_drv_admin_table_size++];
- /* Allocate memory for the strings and copy them in */
- p->dai_name = (char *)kern_calloc(1,strlen(name)+1);
- strcpy(p->dai_name,name);
- p->dai_param_name = (char *)kern_calloc(1,strlen(label)+1);
- strcpy(p->dai_param_name,label);
- p->dai_param_val = (char *)kern_calloc(1,strlen(value)+1);
- strcpy(p->dai_param_val,value);
- out: mrunlock(&extended_drv_admin_table_lock);
- #endif
- FIXME("device_driver_admin_table_update");
- }
- /*
- * keeps on adding the labelled info for each new (lbl,value) pair
- * that it finds in the static dev admin table ( created by lboot)
- * and the extended dev admin table ( created if at all by the kernel startup
- * code) corresponding to a device in the hardware graph.
- */
- void
- device_admin_info_update(devfs_handle_t dev_vhdl)
- {
- #ifdef LATER
- int i = 0;
- dev_admin_info_t *scan;
- devfs_handle_t scan_vhdl;
-
- /* Check the static device administration info table */
- scan = dev_admin_table;
- while (i < dev_admin_table_size) {
-
- scan_vhdl = hwgraph_path_to_dev(scan->dai_name);
- if (scan_vhdl == dev_vhdl) {
- device_admin_info_set(dev_vhdl,
- scan->dai_param_name,
- scan->dai_param_val);
- }
- if (scan_vhdl != NODEV)
- hwgraph_vertex_unref(scan_vhdl);
- scan++;i++;
- }
- i = 0;
- /* Check the extended device administration info table */
- scan = extended_dev_admin_table;
- while (i < extended_dev_admin_table_size) {
- scan_vhdl = hwgraph_path_to_dev(scan->dai_name);
- if (scan_vhdl == dev_vhdl) {
- device_admin_info_set(dev_vhdl,
- scan->dai_param_name,
- scan->dai_param_val);
- }
- if (scan_vhdl != NODEV)
- hwgraph_vertex_unref(scan_vhdl);
- scan++;i++;
- }
- #endif
- FIXME("device_admin_info_update");
- }
- /* looks up the static drv admin table ( created by the lboot) and the extended
- * drv admin table (created if at all by the kernel startup code)
- * for this driver specific administration info and adds it to the admin info
- * associated with this device driver's object
- */
- void
- device_driver_admin_info_update(device_driver_t driver)
- {
- #ifdef LATER
- int i = 0;
- dev_admin_info_t *scan;
- /* Check the static device driver administration info table */
- scan = drv_admin_table;
- while (i < drv_admin_table_size) {
- if (strcmp(scan->dai_name,driver->dd_prefix) == 0) {
- dev_admin_registry_add(&driver->dd_dev_admin_registry,
- scan->dai_param_name,
- scan->dai_param_val);
- }
- scan++;i++;
- }
- i = 0;
- /* Check the extended device driver administration info table */
- scan = extended_drv_admin_table;
- while (i < extended_drv_admin_table_size) {
- if (strcmp(scan->dai_name,driver->dd_prefix) == 0) {
- dev_admin_registry_add(&driver->dd_dev_admin_registry,
- scan->dai_param_name,
- scan->dai_param_val);
- }
- scan++;i++;
- }
- #endif
- FIXME("device_driver_admin_info_update");
- }
- /* =====Device Driver Support===== */
- /*
- ** Generic device driver support routines for use by kernel modules that
- ** deal with device drivers (but NOT for use by the drivers themselves).
- ** EVERY registered driver currently in the system -- static or loadable --
- ** has an entry in the device_driver_hash table. A pointer to such an entry
- ** serves as a generic device driver handle.
- */
- #define DEVICE_DRIVER_HASH_SIZE 32
- #ifdef LATER
- lock_t device_driver_lock[DEVICE_DRIVER_HASH_SIZE];
- device_driver_t device_driver_hash[DEVICE_DRIVER_HASH_SIZE];
- static struct string_table driver_prefix_string_table;
- #endif
- /*
- ** Initialize device driver infrastructure.
- */
- void
- device_driver_init(void)
- {
- #ifdef LATER
- int i;
- extern void alenlist_init(void);
- extern void hwgraph_init(void);
- extern void device_desc_init(void);
- ASSERT(DEVICE_DRIVER_NONE == NULL);
- alenlist_init();
- hwgraph_init();
- device_desc_init();
- string_table_init(&driver_prefix_string_table);
- for (i=0; i<DEVICE_DRIVER_HASH_SIZE; i++) {
- spin_lock_init(&device_driver_lock[i]);
- device_driver_hash[i] = NULL;
- }
- /* Initialize static drivers from master.c table */
- for (i=0; i<static_devsw_count; i++) {
- device_driver_t driver;
- static_device_driver_desc_t desc;
- int pri;
- desc = &static_device_driver_table[i];
- driver = device_driver_get(desc->sdd_prefix);
- if (!driver)
- driver = device_driver_alloc(desc->sdd_prefix);
- pri = device_driver_sysgen_thread_pri_get(desc->sdd_prefix);
- device_driver_thread_pri_set(driver, pri);
- device_driver_devsw_put(driver, desc->sdd_bdevsw, desc->sdd_cdevsw);
- }
- #endif
- FIXME("device_driver_init");
- }
- /*
- ** Hash a prefix string into a hash table chain.
- */
- static int
- driver_prefix_hash(char *prefix)
- {
- #ifdef LATER
- int accum = 0;
- char nextchar;
- while (nextchar = *prefix++)
- accum = accum ^ nextchar;
- return(accum % DEVICE_DRIVER_HASH_SIZE);
- #else
- FIXME("driver_prefix_hash");
- return(0);
- #endif
- }
- /*
- ** Allocate a driver handle.
- ** Returns the driver handle, or NULL if the driver prefix
- ** already has a handle.
- **
- ** Upper layers prevent races among device_driver_alloc,
- ** device_driver_free, and device_driver_get*.
- */
- device_driver_t
- device_driver_alloc(char *prefix)
- {
- #ifdef LATER
- int which_hash;
- device_driver_t new_driver;
- unsigned long s;
-
- which_hash = driver_prefix_hash(prefix);
- new_driver = kern_calloc(1, sizeof(*new_driver));
- ASSERT(new_driver != NULL);
- new_driver->dd_prev = NULL;
- new_driver->dd_prefix = string_table_insert(&driver_prefix_string_table, prefix);
- new_driver->dd_bdevsw = NULL;
- new_driver->dd_cdevsw = NULL;
- dev_admin_registry_init(&new_driver->dd_dev_admin_registry);
- device_driver_admin_info_update(new_driver);
- s = mutex_spinlock(&device_driver_lock[which_hash]);
- #if DEBUG
- {
- device_driver_t drvscan;
- /* Make sure we haven't already added a driver with this prefix */
- drvscan = device_driver_hash[which_hash];
- while (drvscan &&
- strcmp(drvscan->dd_prefix, prefix)) {
- drvscan = drvscan->dd_next;
- }
- ASSERT(!drvscan);
- }
- #endif /* DEBUG */
- /* Add new_driver to front of hash chain. */
- new_driver->dd_next = device_driver_hash[which_hash];
- if (new_driver->dd_next)
- new_driver->dd_next->dd_prev = new_driver;
- device_driver_hash[which_hash] = new_driver;
- mutex_spinunlock(&device_driver_lock[which_hash], s);
- return(new_driver);
- #else
- FIXME("device_driver_alloc");
- return((device_driver_t)0);
- #endif
- }
- /*
- ** Free a driver handle.
- **
- ** Statically loaded drivers should never device_driver_free.
- ** Dynamically loaded drivers device_driver_free when either an
- ** unloaded driver is unregistered, or when an unregistered driver
- ** is unloaded.
- */
- void
- device_driver_free(device_driver_t driver)
- {
- #ifdef LATER
- int which_hash;
- unsigned long s;
- if (!driver)
- return;
- which_hash = driver_prefix_hash(driver->dd_prefix);
- s = mutex_spinlock(&device_driver_lock[which_hash]);
- #if DEBUG
- {
- device_driver_t drvscan;
- /* Make sure we're dealing with the right list */
- drvscan = device_driver_hash[which_hash];
- while (drvscan && (drvscan != driver))
- drvscan = drvscan->dd_next;
- ASSERT(drvscan);
- }
- #endif /* DEBUG */
- if (driver->dd_next)
- driver->dd_next->dd_prev = driver->dd_prev;
- if (driver->dd_prev)
- driver->dd_prev->dd_next = driver->dd_next;
- else
- device_driver_hash[which_hash] = driver->dd_next;
- mutex_spinunlock(&device_driver_lock[which_hash], s);
- driver->dd_next = NULL; /* sanity */
- driver->dd_prev = NULL; /* sanity */
- driver->dd_prefix = NULL; /* sanity */
- if (driver->dd_bdevsw) {
- driver->dd_bdevsw->d_driver = NULL;
- driver->dd_bdevsw = NULL;
- }
- if (driver->dd_cdevsw) {
- if (driver->dd_cdevsw->d_str) {
- str_free_mux_node(driver);
- }
- driver->dd_cdevsw->d_driver = NULL;
- driver->dd_cdevsw = NULL;
- }
- kern_free(driver);
- #endif
- FIXME("device_driver_free");
- }
- /*
- ** Given a device driver prefix, return a handle to the caller.
- */
- device_driver_t
- device_driver_get(char *prefix)
- {
- #ifdef LATER
- int which_hash;
- device_driver_t drvscan;
- unsigned long s;
- if (prefix == NULL)
- return(NULL);
-
- which_hash = driver_prefix_hash(prefix);
- s = mutex_spinlock(&device_driver_lock[which_hash]);
- drvscan = device_driver_hash[which_hash];
- while (drvscan && strcmp(drvscan->dd_prefix, prefix))
- drvscan = drvscan->dd_next;
- mutex_spinunlock(&device_driver_lock[which_hash], s);
- return(drvscan);
- #else
- FIXME("device_driver_get");
- return((device_driver_t)0);
- #endif
- }
- /*
- ** Given a block or char special file devfs_handle_t, find the
- ** device driver that controls it.
- */
- device_driver_t
- device_driver_getbydev(devfs_handle_t device)
- {
- #ifdef LATER
- struct bdevsw *my_bdevsw;
- struct cdevsw *my_cdevsw;
- my_cdevsw = get_cdevsw(device);
- if (my_cdevsw != NULL)
- return(my_cdevsw->d_driver);
- my_bdevsw = get_bdevsw(device);
- if (my_bdevsw != NULL)
- return(my_bdevsw->d_driver);
- #endif
- FIXME("device_driver_getbydev");
- return((device_driver_t)0);
- }
- /*
- ** Associate a driver with bdevsw/cdevsw pointers.
- **
- ** Statically loaded drivers are permanently and automatically associated
- ** with the proper bdevsw/cdevsw. Dynamically loaded drivers associate
- ** themselves when the driver is registered, and disassociate when the
- ** driver unregisters.
- **
- ** Returns 0 on success, -1 on failure (devsw already associated with driver)
- */
- int
- device_driver_devsw_put(device_driver_t driver,
- struct bdevsw *my_bdevsw,
- struct cdevsw *my_cdevsw)
- {
- #ifdef LATER
- int i;
- if (!driver)
- return(-1);
- /* Trying to re-register data? */
- if (((my_bdevsw != NULL) && (driver->dd_bdevsw != NULL)) ||
- ((my_cdevsw != NULL) && (driver->dd_cdevsw != NULL)))
- return(-1);
- if (my_bdevsw != NULL) {
- driver->dd_bdevsw = my_bdevsw;
- my_bdevsw->d_driver = driver;
- for (i = 0; i < bdevmax; i++) {
- if (driver->dd_bdevsw->d_flags == bdevsw[i].d_flags) {
- bdevsw[i].d_driver = driver;
- break;
- }
- }
- }
- if (my_cdevsw != NULL) {
- driver->dd_cdevsw = my_cdevsw;
- my_cdevsw->d_driver = driver;
- for (i = 0; i < cdevmax; i++) {
- if (driver->dd_cdevsw->d_flags == cdevsw[i].d_flags) {
- cdevsw[i].d_driver = driver;
- break;
- }
- }
- }
- #endif
- FIXME("device_driver_devsw_put");
- return(0);
- }
- /*
- ** Given a driver, return the corresponding bdevsw and cdevsw pointers.
- */
- void
- device_driver_devsw_get( device_driver_t driver,
- struct bdevsw **bdevswp,
- struct cdevsw **cdevswp)
- {
- if (!driver) {
- *bdevswp = NULL;
- *cdevswp = NULL;
- } else {
- *bdevswp = driver->dd_bdevsw;
- *cdevswp = driver->dd_cdevsw;
- }
- }
- /*
- * device_driver_thread_pri_set
- * Given a driver try to set its thread priority.
- * Returns 0 on success , -1 on failure.
- */
- int
- device_driver_thread_pri_set(device_driver_t driver,ilvl_t pri)
- {
- if (!driver)
- return(-1);
- driver->dd_thread_pri = pri;
- return(0);
- }
- /*
- * device_driver_thread_pri_get
- * Given a driver return the driver thread priority.
- * If the driver is NULL return invalid driver thread
- * priority.
- */
- ilvl_t
- device_driver_thread_pri_get(device_driver_t driver)
- {
- if (driver)
- return(driver->dd_thread_pri);
- else
- return(DRIVER_THREAD_PRI_INVALID);
- }
- /*
- ** Given a device driver, return it's handle (prefix).
- */
- void
- device_driver_name_get(device_driver_t driver, char *buffer, int length)
- {
- if (driver == NULL)
- return;
- strncpy(buffer, driver->dd_prefix, length);
- }
- /*
- ** Associate a pointer-sized piece of information with a device.
- */
- void
- device_info_set(devfs_handle_t device, void *info)
- {
- #ifdef LATER
- hwgraph_fastinfo_set(device, (arbitrary_info_t)info);
- #endif
- FIXME("device_info_set");
- }
- /*
- ** Retrieve a pointer-sized piece of information associated with a device.
- */
- void *
- device_info_get(devfs_handle_t device)
- {
- #ifdef LATER
- return((void *)hwgraph_fastinfo_get(device));
- #else
- FIXME("device_info_get");
- return(NULL);
- #endif
- }
- /*
- * Find the thread priority for a device, from the various
- * sysgen files.
- */
- int
- device_driver_sysgen_thread_pri_get(char *dev_prefix)
- {
- #ifdef LATER
- int pri;
- char *pri_s;
- char *class;
- extern default_intr_pri;
- extern disk_intr_pri;
- extern serial_intr_pri;
- extern parallel_intr_pri;
- extern tape_intr_pri;
- extern graphics_intr_pri;
- extern network_intr_pri;
- extern scsi_intr_pri;
- extern audio_intr_pri;
- extern video_intr_pri;
- extern external_intr_pri;
- extern tserialio_intr_pri;
- /* Check if there is a thread priority specified for
- * this driver's thread thru admin hints. If so
- * use that value. Otherwise set it to its default
- * class value, otherwise set it to the default
- * value.
- */
- if (pri_s = device_driver_admin_info_get(dev_prefix,
- ADMIN_LBL_THREAD_PRI)) {
- pri = atoi(pri_s);
- } else if (class = device_driver_admin_info_get(dev_prefix,
- ADMIN_LBL_THREAD_CLASS)) {
- if (strcmp(class, "disk") == 0)
- pri = disk_intr_pri;
- else if (strcmp(class, "serial") == 0)
- pri = serial_intr_pri;
- else if (strcmp(class, "parallel") == 0)
- pri = parallel_intr_pri;
- else if (strcmp(class, "tape") == 0)
- pri = tape_intr_pri;
- else if (strcmp(class, "graphics") == 0)
- pri = graphics_intr_pri;
- else if (strcmp(class, "network") == 0)
- pri = network_intr_pri;
- else if (strcmp(class, "scsi") == 0)
- pri = scsi_intr_pri;
- else if (strcmp(class, "audio") == 0)
- pri = audio_intr_pri;
- else if (strcmp(class, "video") == 0)
- pri = video_intr_pri;
- else if (strcmp(class, "external") == 0)
- pri = external_intr_pri;
- else if (strcmp(class, "tserialio") == 0)
- pri = tserialio_intr_pri;
- else
- pri = default_intr_pri;
- } else
- pri = default_intr_pri;
- if (pri > 255)
- pri = 255;
- else if (pri < 0)
- pri = 0;
- return pri;
- #else
- FIXME("device_driver_sysgen_thread_pri_get");
- return(-1);
- #endif
- }