/* usb/lib/data-fast.h
 *
 * (c) 2002 Simtec Electronics
 *
 * Ben Dooks
 *
 * fast definitions (macro) for the usb get and set content routines
 *
 * $Id: data-fast.h,v 1.11 2003/08/06 15:56:11 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.
 *
 */

/* format used for the paramters for usb_dcs/usb_dcg:
 *
 * bits 0..15:  offset of the item from zero
 * bits 16..23: the size of the item in bytes
 * bits 24..31: array specifier:
 *              this is the number of items in the array, or zero for no array
 */

#ifndef __USB_LIB_DATA_FAST_H
#define __USB_LIB_DATA_FAST_H "$Id: data-fast.h,v 1.11 2003/08/06 15:56:11 ben Exp $"

/** get unsigned 8bit value from the given pointer
*/
#define get_u8(ptr)  ((unsigned long)(*((unsigned char *)(ptr))))

/** get unsigned 16bit value from the given pointer
*/
#define get_u16(ptr) ((get_u8(ptr) | (get_u8((ptr)+1) << 8)))

/** get unsigned 32bit value from the given pointer
*/
#define get_u32(ptr) ((get_u8(ptr)) | (get_u8((ptr)+1) << 8) | (get_u8((ptr)+2) << 16) | (get_u8((ptr)+3) << 24))

/** convert the arguments into an 'unsigned long' pointing to the item of data
      in question
*/
#define usb_addrof(ds, off, arry) (((unsigned long)(ds)) + ((off) & 0xffff) + ((((off)>>16) & 0xff) * arry))

/** version of usb_data_content_get() without any checks
*/
#define usb_do_dcg(ds,off,arry)((((off) & 0xFF0000) == (0x10000)) ? get_u8(usb_addrof(ds,off,arry)) : (((off) & 0xFF0000) == (0x20000)) ? get_u16(usb_addrof(ds,off,arry)) : get_u32(usb_addrof(ds,off,arry)))

/** fast version of usb_data_content_address()
*/
#define usb_fast_dca(ds, off, arry)((arry > (signed int)((off) >> 24)) ? NULL : (void *)usb_addrof(ds, off, arry))

/** fast version of usb_data_content_get
*/
#define usb_fast_dcg(ds, off, arry)((arry > ((off) >> 24)) ? 0 : usb_do_dcg(ds,off,arry))


#if 0

/* Fast version of usb_data_content_set.
   Using unsigned char *pos; would create the problem that the compiler would
   assign a register for pos
@memo Fast version of usb_data_content_set.
*/
#define usb_fast_dcs(ds, off, arry, val) do { \
  unsigned char *pos = (unsigned char *)(ds) + (off & 0xFFFF); \
  if (arry > ((off >> 24))) continue; \
  pos += ((off)>>16 & 0xff) * arry; \
  switch ((off)>>16 & 0xff) { \
   case 1: pos[0] = (unsigned char)(val); break; \
   case 2: pos[0] = (unsigned char)(val); pos[1] = (unsigned char)((val) >> 8); } \
  } while(0)
#else

/** convert off and arry paramters to a 'real' offset
*/
#define get_off(off,arry)((off & 0xFFFF) + ((off)>>16 & 0xff) * arry)

/** fast version of usb_data_content_set
@memo Fast version of usb_data_content_set.
*/
#define usb_fast_dcs(ds, off, arry, val) do { \
  if (arry > ((off >> 24))) continue; \
  switch ((off)>>16 & 0xff) { \
   case 1: ((unsigned char *)ds)[get_off(off,arry)] = (unsigned char)(val); break; \
   case 2: ((unsigned char *)ds)[get_off(off,arry)] = (unsigned char)(val); \
           ((unsigned char *)ds)[get_off(off,arry)+1] = (unsigned char)((val) >> 8); \
  break;\
   case 4: ((unsigned char *)ds)[get_off(off,arry)] = (unsigned char)(val); \
           ((unsigned char *)ds)[get_off(off,arry)+1] = (unsigned char)((val) >> 8); \
           ((unsigned char *)ds)[get_off(off,arry)+2] = (unsigned char)((val) >> 16); \
           ((unsigned char *)ds)[get_off(off,arry)+3] = (unsigned char)((val) >> 24); \
    } \
  } while(0)
#endif

#endif /* __USB_LIB_DATA_FAST_H */
