/* usb-lib/usb/lib/urb-ring.h
 *
 * (c) 2002 Simtec Electronics
 *
 * Ben Dooks
 *
 * Ring-buffer for URBs
 * 
 * $Id: urb-ring.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.
 *
*/

/* note, this code is currently not finished (is not being built for release)
*/

#ifndef __USB_LIB_URB_RING_H
#define __USB_LIB_URB_RING_H "$Id: urb-ring.h,v 1.6 2003/08/07 13:06:57 ben Exp $"

typedef struct usb_urb_ring_entry usb_urb_ring_entry_t;

struct usb_urb_ring_entry {
  usb_urb_ring_entry_t *next;
  usb_buffer_t         *urb;
};

struct usb_urb_ring {
  usb_urb_ring_entry_t *entries;      /* the entries */
  usb_urb_ring_entry_t *nourb;        /* no urbs */
  usb_urb_ring_entry_t *empty;        /* empty entries */
  usb_urb_ring_entry_t *write;        /* current writing */
  usb_urb_ring_entry_t *full_st;      /* start of full entries */
  usb_urb_ring_entry_t *full_end;     /* end of full entries */
  usb_urb_ring_entry_t *inuse;        /* current sending */
};

/* ring bits:
 *
 * entries:
 *  the array of all entries current usable
 *
 * nourb:
 *  list of entries that yet to have an urb assigned to them
 *
 * empty:
 *  the entries that have an urb, but have no data in them yet
 *
 * write:
 *  the entry that is being currently written to
 *
 * full_st:
 *  the first full entry of data
 *
 * full_end:
 *  the last full entry
 *
 * inuse:
 *  buffers that have been given to something else to process
*/

typedef struct usb_urb_ring usb_urb_ring_t;

extern usb_urb_ring_t *urb_ring_alloc(int entries);
extern void            urb_ring_free(usb_urb_ring_t *);

extern int             urb_ring_addurb(usb_buffer_t *);
extern int             urb_ring_add_data(usb_urb_ring_t *, void *, size_t);

#define usb_urb_ring_next(_ur,_it)((_it)+1 % (_ur)->size)
#define usb_urb_ring_nextwr(_ur)((usb_urb_ring_next(_ur, (_ur)->wr_ptr)))

extern int urb_ring_anyqueable(urb_ring_t *ring);

/* get an buffer from the ring to submit to whatever. The ring's read
 * pointer is moved
*/
extern usb_buffer_t *usb_ring_getq(urb_ring_t *ring);

/* return the urb back to the unused queue */
extern void           usb_ring_done(usb_ring_t *ring, usb_buffer_t *buff);

#endif /* __USB_LIB_URB_RING_H */
