/* usb/dtlist.h
 *
 * (c) 2002 Simtec Electronics
 *
 * Ben Dooks
 *
 * simple doubly linked list code
 *
 * $Id: dtlist.h,v 1.6 2003/08/07 13:06:57 ben Exp $
 *
 * This Library file is part of the Simtec Electronics USB stack development
 *   suite.
 * Specific licence is granted to use this file by third parties for the
 *   development of USB device drivers.
 *
*/

#ifndef __USB_dtlist_H
#define __USB_dtlist_H "$Id: dtlist.h,v 1.6 2003/08/07 13:06:57 ben Exp $"

struct dtlist_item;

/** dlist head structure
 * @memo head structure for dlist
*/

struct dtlist_head {
  struct dtlist_item *dt_head, *dt_tail;
};


/** dlist item structure (to put in each item in the list)
 * @memo dlist item structure
*/
struct dtlist_item {
  struct dtlist_item   *dt_next;
  struct dtlist_item   *dt_prev;
  void		       *dt_data;
};

typedef struct dtlist_head dtlist_head_t;
typedef struct dtlist_item dtlist_item_t;

#define DTLIST_INIT_HEAD { NULL, NULL }

/** initialise the head structure for an dlist
 * @memo initialise the head structure for an dlist
 * @see dtlist_head
*/

#define dtlist_inithead(_dl) do { (_dl)->dt_head = (_dl)->dt_tail = NULL; } while(0)

/** initialise an dlist item structure
 * @memo initialise an dlist item structure
 * @see dtlist_item
*/

#define dtlist_init(_entry,_item) do { (_entry)->dt_data = (_item); } while(0)

/** add an item to the front of an dlist
 * @memo add an item to the front of an dlist
*/

#define dtlist_add_front(_dl,_it) do { \
    (_it)->dt_prev = NULL; \
    if ((_dl)->dt_head == NULL) { \
      (_it)->dt_next = NULL; \
      (_dl)->dt_head = (_dl)->dt_tail = (_it); \
    } else { \
      (_it)->dt_next = (_dl)->dt_head; \
      (_it)->dt_next->dt_prev = (_it); \
      (_dl)->dt_head = (_it); \
    } \
  } while(0)

#define dtlist_add_end(_dl, _it) do { \
    (_it)->dt_next = NULL; \
    if ((_dl)->dt_head == NULL) { \
      (_dl)->dt_head = (_dl)->dt_tail = (_it); \
      (_it)->dt_prev = NULL; \
    } else { \
      (_it)->dt_prev = (_dl)->dt_tail; \
      (_it)->dt_prev->dt_next = (_it); \
      (_dl)->dt_tail = (_it); \
    } \
  } while(0)
    

/** Return the first item's data from the front of a list
*/

#define dtlist_get_front(_dl) (((_dl)->dt_head) == NULL ? NULL : ((_dl)->dt_head)->dt_data) 

#define dtlist_get_head(_dl) dtlist_get_front(_dl)

#define dtlist_mkchain(_prev,_ent) do { \
  (_prev)->dt_next = _ent; (_ent)->dt_next = NULL; \
  (_ent)->dt_prev = _prev; } while(0)

extern void dtlist_addchain(dtlist_head_t *head,
                            dtlist_item_t *first, dtlist_item_t *last);

/** Is an dlist empty
*/

#define dtlist_empty(_dl) ((_dl)->dt_head == NULL)

#define dtlist_next(_dl) (((_dl)->dt_next) == NULL ? NULL : (_dl)->dt_next->dt_data)

#define dtlist_islast(_dl) ((_dl)->dt_next == NULL)

#define dtlist_first(_dl) ((_dl)->dt_head == NULL ? NULL : (_dl)->dt_head->dt_data)

/** dlist enumeration function.
 *
 * @param _dl the dlist head
 * @param _to the variable to take each item
 * @param _entry the entry field name within the item
 * @param _type type to cast _to to
 * @see dtlist_head
 * @see dtlist_item
*/

#define dtlist_foreach(_dl,_to,_entry,_type) \
  for ((_to) = (_type)dtlist_first(_dl); \
       (_to) != NULL ; \
       (_to) = (_type)dtlist_next(&((_to)->_entry)))

/** remove item from an dlist
 * @param head head of list
 * @param item item to remove
 * @see dtlist_item
 * @see dtlist_head
 */
extern int dtlist_remove(dtlist_head_t *head, dtlist_item_t *item);

/* debug bits */

extern void dtlist_dbg_showlist(dtlist_head_t *head, int count);

#endif








