/* $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 #include #include #include #include #include #include #include /* * 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 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 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 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 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 * 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%x\n", 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%x\n", 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 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 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; isdd_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 }