text: /*
   * gh.c
   *
   * DSP-BIOS Bridge driver support functions for TI OMAP processors.
   *
   * Copyright (C) 2005-2006 Texas Instruments, Inc.
   *
   * This package is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
   * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   */
  
  #include <linux/types.h>
  
  #include <dspbridge/host_os.h>
  #include <dspbridge/gh.h>
  
  struct element {
  	struct element *next;
  	u8 data[1];
  };
  
  struct gh_t_hash_tab {
  	u16 max_bucket;
  	u16 val_size;
  	struct element **buckets;
  	 u16(*hash) (void *, u16);
  	 bool(*match) (void *, void *);
  	void (*delete) (void *);
  };
  
  static void noop(void *p);
  
  /*
   *  ======== gh_create ========
   */
  
  struct gh_t_hash_tab *gh_create(u16 max_bucket, u16 val_size,
  				u16(*hash) (void *, u16), bool(*match) (void *,
  									void *),
  				void (*delete) (void *))
  {
  	struct gh_t_hash_tab *hash_tab;
  	u16 i;
  	hash_tab = kzalloc(sizeof(struct gh_t_hash_tab), GFP_KERNEL);
  	if (hash_tab == NULL)
  		return NULL;
  	hash_tab->max_bucket = max_bucket;
  	hash_tab->val_size = val_size;
  	hash_tab->hash = hash;
  	hash_tab->match = match;
  	hash_tab->delete = delete == NULL ? noop : delete;
  
  	hash_tab->buckets = (struct element **)
  	    kzalloc(sizeof(struct element *) * max_bucket, GFP_KERNEL);
  	if (hash_tab->buckets == NULL) {
  		gh_delete(hash_tab);
  		return NULL;
  	}
  
  	for (i = 0; i < max_bucket; i++)
  		hash_tab->buckets[i] = NULL;
  
  	return hash_tab;
  }
  
  /*
   *  ======== gh_delete ========
   */
  void gh_delete(struct gh_t_hash_tab *hash_tab)
  {
  	struct element *elem, *next;
  	u16 i;
  
  	if (hash_tab != NULL) {
  		if (hash_tab->buckets != NULL) {
  			for (i = 0; i < hash_tab->max_bucket; i++) {
  				for (elem = hash_tab->buckets[i]; elem != NULL;
  				     elem = next) {
  					next = elem->next;
  					(*hash_tab->delete) (elem->data);
  					kfree(elem);
  				}
  			}
  
  			kfree(hash_tab->buckets);
  		}
  
  		kfree(hash_tab);
  	}
  }
  
  /*
   *  ======== gh_exit ========
   */
  
  void gh_exit(void)
  {
  	/* Do nothing */
  }
  
  /*
   *  ======== gh_find ========
   */
  
  void *gh_find(struct gh_t_hash_tab *hash_tab, void *key)
  {
  	struct element *elem;
  
  	elem = hash_tab->buckets[(*hash_tab->hash) (key, hash_tab->max_bucket)];
  
  	for (; elem; elem = elem->next) {
  		if ((*hash_tab->match) (key, elem->data))
  			return elem->data;
  	}
  
  	return NULL;
  }
  
  /*
   *  ======== gh_init ========
   */
  
  void gh_init(void)
  {
  	/* Do nothing */
  }
  
  /*
   *  ======== gh_insert ========
   */
  
  void *gh_insert(struct gh_t_hash_tab *hash_tab, void *key, void *value)
  {
  	struct element *elem;
  	u16 i;
  	char *src, *dst;
  
  	elem = kzalloc(sizeof(struct element) - 1 + hash_tab->val_size,
  			GFP_KERNEL);
  	if (elem != NULL) {
  
  		dst = (char *)elem->data;
  		src = (char *)value;
  		for (i = 0; i < hash_tab->val_size; i++)
  			*dst++ = *src++;
  
  		i = (*hash_tab->hash) (key, hash_tab->max_bucket);
  		elem->next = hash_tab->buckets[i];
  		hash_tab->buckets[i] = elem;
  
  		return elem->data;
  	}
  
  	return NULL;
  }
  
  /*
   *  ======== noop ========
   */
  /* ARGSUSED */
  static void noop(void *p)
  {
  	p = p;			/* stifle compiler warning */
  }
  
  #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
  /**
   * gh_iterate() - This function goes through all the elements in the hash table
   *		looking for the dsp symbols.
   * @hash_tab:	Hash table
   * @callback:	pointer to callback function
   * @user_data:	User data, contains the find_symbol_context pointer
   *
   */
  void gh_iterate(struct gh_t_hash_tab *hash_tab,
  		void (*callback)(void *, void *), void *user_data)
  {
  	struct element *elem;
  	u32 i;
  
  	if (hash_tab && hash_tab->buckets)
  		for (i = 0; i < hash_tab->max_bucket; i++) {
  			elem = hash_tab->buckets[i];
  			while (elem) {
  				callback(&elem->data, user_data);
  				elem = elem->next;
  			}
  		}
  }
  #endif
  