📄 labelcl.c
字号:
/* labelcl - SGI's Hwgraph Compatibility Layer. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Colin Ngam may be reached by email at cngam@sgi.com*/#include <linux/types.h>#include <linux/slab.h>#include <asm/sn/sgi.h>#include <linux/devfs_fs.h>#include <linux/devfs_fs_kernel.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/labelcl.h>/*** Very simple and dumb string table that supports only find/insert.** In practice, if this table gets too large, we may need a more** efficient data structure. Also note that currently there is no ** way to delete an item once it's added. Therefore, name collision ** will return an error.*/struct string_table label_string_table;/* * string_table_init - Initialize the given string table. */voidstring_table_init(struct string_table *string_table){ string_table->string_table_head = NULL; string_table->string_table_generation = 0; /* * We nedd to initialize locks here! */ return;}/* * string_table_destroy - Destroy the given string table. */voidstring_table_destroy(struct string_table *string_table){ struct string_table_item *item, *next_item; item = string_table->string_table_head; while (item) { next_item = item->next; STRTBL_FREE(item); item = next_item; } /* * We need to destroy whatever lock we have here */ return;}/* * string_table_insert - Insert an entry in the string table .. duplicate * names are not allowed. */char *string_table_insert(struct string_table *string_table, char *name){ struct string_table_item *item, *new_item = NULL, *last_item = NULL;again: /* * Need to lock the table .. */ item = string_table->string_table_head; last_item = NULL; while (item) { if (!strcmp(item->string, name)) { /* * If we allocated space for the string and the found that * someone else already entered it into the string table, * free the space we just allocated. */ if (new_item) STRTBL_FREE(new_item); /* * Search optimization: move the found item to the head * of the list. */ if (last_item != NULL) { last_item->next = item->next; item->next = string_table->string_table_head; string_table->string_table_head = item; } goto out; } last_item = item; item=item->next; } /* * name was not found, so add it to the string table. */ if (new_item == NULL) { long old_generation = string_table->string_table_generation; new_item = STRTBL_ALLOC(strlen(name)); strcpy(new_item->string, name); /* * While we allocated memory for the new string, someone else * changed the string table. */ if (old_generation != string_table->string_table_generation) { goto again; } } else { /* At this we only have the string table lock in access mode. * Promote the access lock to an update lock for the string * table insertion below. */ long old_generation = string_table->string_table_generation; /* * After we did the unlock and wer waiting for update * lock someone could have potentially updated * the string table. Check the generation number * for this case. If it is the case we have to * try all over again. */ if (old_generation != string_table->string_table_generation) { goto again; } } /* * At this point, we're committed to adding new_item to the string table. */ new_item->next = string_table->string_table_head; item = string_table->string_table_head = new_item; string_table->string_table_generation++;out: /* * Need to unlock here. */ return(item->string);}/* * labelcl_info_create - Creates the data structure that will hold the * device private information asscoiated with a devfs entry. * The pointer to this structure is what gets stored in the devfs * (void * info). */labelcl_info_t *labelcl_info_create(){ labelcl_info_t *new = NULL; /* Initial allocation does not include any area for labels */ if ( ( new = (labelcl_info_t *)kmalloc (sizeof(labelcl_info_t), GFP_KERNEL) ) == NULL ) return NULL; memset (new, 0, sizeof(labelcl_info_t)); new->hwcl_magic = LABELCL_MAGIC; return( new);}/* * labelcl_info_destroy - Frees the data structure that holds the * device private information asscoiated with a devfs entry. This * data structure was created by device_info_create(). * * The caller is responsible for nulling the (void *info) in the * corresponding devfs entry. */intlabelcl_info_destroy(labelcl_info_t *labelcl_info){ if (labelcl_info == NULL) return(0); /* Free the label list */ if (labelcl_info->label_list) kfree(labelcl_info->label_list); /* Now free the label info area */ labelcl_info->hwcl_magic = 0; kfree(labelcl_info); return(0);}/* * labelcl_info_add_LBL - Adds a new label entry in the labelcl info * structure. * * Error is returned if we find another label with the same name. */intlabelcl_info_add_LBL(devfs_handle_t de, char *info_name, arb_info_desc_t info_desc, arbitrary_info_t info){ labelcl_info_t *labelcl_info = NULL; int num_labels; int new_label_list_size; label_info_t *old_label_list, *new_label_list = NULL; char *name; int i; if (de == NULL) return(-1); labelcl_info = devfs_get_info(de); if (labelcl_info == NULL) return(-1); if (labelcl_info->hwcl_magic != LABELCL_MAGIC) return(-1); if (info_name == NULL) return(-1); if (strlen(info_name) >= LABEL_LENGTH_MAX) return(-1); name = string_table_insert(&label_string_table, info_name); num_labels = labelcl_info->num_labels; new_label_list_size = sizeof(label_info_t) * (num_labels+1); /* * Create a new label info area. */ if (new_label_list_size != 0) { new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL); if (new_label_list == NULL) return(-1); } /* * At this point, we are committed to adding the labelled info, * if there isn't already information there with the same name. */ old_label_list = labelcl_info->label_list; /* * Look for matching info name. */ for (i=0; i<num_labels; i++) { if (!strcmp(info_name, old_label_list[i].name)) { /* Not allowed to add duplicate labelled info names. */ kfree(new_label_list); printk("labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, de); return(-1); } new_label_list[i] = old_label_list[i]; /* structure copy */ } new_label_list[num_labels].name = name; new_label_list[num_labels].desc = info_desc; new_label_list[num_labels].info = info; labelcl_info->num_labels = num_labels+1; labelcl_info->label_list = new_label_list; if (old_label_list != NULL) kfree(old_label_list); return(0);}/* * labelcl_info_remove_LBL - Remove a label entry. */intlabelcl_info_remove_LBL(devfs_handle_t de, char *info_name, arb_info_desc_t *info_desc, arbitrary_info_t *info){ labelcl_info_t *labelcl_info = NULL; int num_labels; int new_label_list_size; label_info_t *old_label_list, *new_label_list = NULL; arb_info_desc_t label_desc_found; arbitrary_info_t label_info_found; int i; if (de == NULL) return(-1); labelcl_info = devfs_get_info(de); if (labelcl_info == NULL) return(-1); if (labelcl_info->hwcl_magic != LABELCL_MAGIC) return(-1); num_labels = labelcl_info->num_labels; if (num_labels == 0) { return(-1); } /* * Create a new info area. */ new_label_list_size = sizeof(label_info_t) * (num_labels-1); if (new_label_list_size) { new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL); if (new_label_list == NULL) return(-1); } /* * At this point, we are committed to removing the labelled info, * if it still exists. */ old_label_list = labelcl_info->label_list; /* * Find matching info name. */ for (i=0; i<num_labels; i++) { if (!strcmp(info_name, old_label_list[i].name)) { label_desc_found = old_label_list[i].desc; label_info_found = old_label_list[i].info; goto found; } if (i < num_labels-1) /* avoid walking off the end of the new vertex */ new_label_list[i] = old_label_list[i]; /* structure copy */ } /* The named info doesn't exist. */ if (new_label_list) kfree(new_label_list); return(-1);found: /* Finish up rest of labelled info */ for (i=i+1; i<num_labels; i++) new_label_list[i-1] = old_label_list[i]; /* structure copy */ labelcl_info->num_labels = num_labels+1; labelcl_info->label_list = new_label_list; kfree(old_label_list); if (info != NULL) *info = label_info_found; if (info_desc != NULL) *info_desc = label_desc_found; return(0);}/* * labelcl_info_replace_LBL - Replace an existing label entry with the * given new information. * * Label entry must exist. */intlabelcl_info_replace_LBL(devfs_handle_t de, char *info_name, arb_info_desc_t info_desc, arbitrary_info_t info, arb_info_desc_t *old_info_desc, arbitrary_info_t *old_info){ labelcl_info_t *labelcl_info = NULL; int num_labels; label_info_t *label_list; int i; if (de == NULL) return(-1); labelcl_info = devfs_get_info(de); if (labelcl_info == NULL) return(-1); if (labelcl_info->hwcl_magic != LABELCL_MAGIC) return(-1); num_labels = labelcl_info->num_labels; if (num_labels == 0) { return(-1); } if (info_name == NULL) return(-1); label_list = labelcl_info->label_list; /* * Verify that information under info_name already exists. */ for (i=0; i<num_labels; i++) if (!strcmp(info_name, label_list[i].name)) { if (old_info != NULL) *old_info = label_list[i].info; if (old_info_desc != NULL) *old_info_desc = label_list[i].desc; label_list[i].info = info; label_list[i].desc = info_desc; return(0); } return(-1);}/* * labelcl_info_get_LBL - Retrieve and return the information for the * given label entry. */intlabelcl_info_get_LBL(devfs_handle_t de, char *info_name, arb_info_desc_t *info_desc, arbitrary_info_t *info){ labelcl_info_t *labelcl_info = NULL; int num_labels; label_info_t *label_list; int i; if (de == NULL) return(-1); labelcl_info = devfs_get_info(de); if (labelcl_info == NULL) return(-1); if (labelcl_info->hwcl_magic != LABELCL_MAGIC) return(-1); num_labels = labelcl_info->num_labels; if (num_labels == 0) { return(-1); } label_list = labelcl_info->label_list; /* * Find information under info_name. */ for (i=0; i<num_labels; i++) if (!strcmp(info_name, label_list[i].name)) { if (info != NULL) *info = label_list[i].info; if (info_desc != NULL) *info_desc = label_list[i].desc; return(0); } return(-1);}/* * labelcl_info_get_next_LBL - returns the next label entry on the list. */intlabelcl_info_get_next_LBL(devfs_handle_t de, char *buffer, arb_info_desc_t *info_descp, arbitrary_info_t *infop, labelcl_info_place_t *placeptr){ labelcl_info_t *labelcl_info = NULL; uint which_info; label_info_t *label_list; if ((buffer == NULL) && (infop == NULL)) return(-1); if (placeptr == NULL) return(-1); if (de == NULL) return(-1); labelcl_info = devfs_get_info(de); if (labelcl_info == NULL) return(-1); if (labelcl_info->hwcl_magic != LABELCL_MAGIC) return(-1); which_info = *placeptr; if (which_info >= labelcl_info->num_labels) { return(-1); } label_list = (label_info_t *) labelcl_info->label_list; if (buffer != NULL) strcpy(buffer, label_list[which_info].name); if (infop) *infop = label_list[which_info].info; if (info_descp) *info_descp = label_list[which_info].desc; *placeptr = which_info + 1; return(0);}intlabelcl_info_replace_IDX(devfs_handle_t de, int index, arbitrary_info_t info, arbitrary_info_t *old_info){ arbitrary_info_t *info_list_IDX; labelcl_info_t *labelcl_info = NULL; if (de == NULL) { printk(KERN_ALERT "labelcl: NULL devfs handle given.\n"); return(-1); } labelcl_info = devfs_get_info(de); if (labelcl_info == NULL) { printk(KERN_ALERT "labelcl: Entry does not have info pointer.\n"); return(-1); } if (labelcl_info->hwcl_magic != LABELCL_MAGIC) return(-1); if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) ) return(-1); /* * Replace information at the appropriate index in this vertex with * the new info. */ info_list_IDX = labelcl_info->IDX_list; if (old_info != NULL) *old_info = info_list_IDX[index]; info_list_IDX[index] = info; return(0);}/* * labelcl_info_connectpt_set - Sets the connectpt. */intlabelcl_info_connectpt_set(struct devfs_entry *de, struct devfs_entry *connect_de){ arbitrary_info_t old_info; int rv; rv = labelcl_info_replace_IDX(de, HWGRAPH_CONNECTPT, (arbitrary_info_t) connect_de, &old_info); if (rv) { return(rv); } return(0);}/* * labelcl_info_get_IDX - Returns the information pointed at by index. * */intlabelcl_info_get_IDX(devfs_handle_t de, int index, arbitrary_info_t *info){ arbitrary_info_t *info_list_IDX; labelcl_info_t *labelcl_info = NULL; if (de == NULL) return(-1); labelcl_info = devfs_get_info(de); if (labelcl_info == NULL) return(-1); if (labelcl_info->hwcl_magic != LABELCL_MAGIC) return(-1); if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) ) return(-1); /* * Return information at the appropriate index in this vertex. */ info_list_IDX = labelcl_info->IDX_list; if (info != NULL) *info = info_list_IDX[index]; return(0);}/* * labelcl_info_connectpt_get - Retrieve the connect point for a device entry. */struct devfs_entry *labelcl_info_connectpt_get(struct devfs_entry *de){ int rv; arbitrary_info_t info; rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info); if (rv) return(NULL); return((struct devfs_entry *)info);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -