
#ifndef USBIO_H

 /* General USB I/O support */

/* 
 * Argyll Color Correction System
 *
 * Author: Graeme W. Gill
 * Date:   2006/22/4
 *
 * Copyright 2006 - 2013 Graeme W. Gill
 * All rights reserved.
 *
 * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
 * see the License2.txt file for licencing details.
 */

#ifdef ENABLE_USB

#ifdef __cplusplus
	extern "C" {
#endif


#ifdef NATIVE_USB

/* Standard USB protocol defines */
# include "iusb.h"

/* Opaque structure to hide implementation details in icoms */ 

# ifdef NT

/* MSWin native USB context */
struct usb_idevice {
	/* icompath stuff: */
	char *dpath;			/* Device path */
	int nconfig;			/* Number of configurations */
	int config;				/* This config (always 1) */
	int nifce;				/* Number of interfaces */
	usb_ep ep[32];			/* Information about each end point for general usb i/o */
	/* Stuff setup when device is open: */
	HANDLE handle;
};

# endif	/* NT */

# if defined(UNIX) && defined(__APPLE__)

/* OS X structure version wrangling */

/* usb_device_t - for communicating with the device.  */
#if defined (kIOUSBDeviceInterfaceID320)
# define usb_device_t    IOUSBDeviceInterface320
# define DeviceInterfaceID kIOUSBDeviceInterfaceID320
# define DeviceVersion 320
#elif defined (kIOUSBDeviceInterfaceID300)
# define usb_device_t    IOUSBDeviceInterface300
# define DeviceInterfaceID kIOUSBDeviceInterfaceID300
# define DeviceVersion 300
#elif defined (kIOUSBDeviceInterfaceID245)
# define usb_device_t    IOUSBDeviceInterface245
# define DeviceInterfaceID kIOUSBDeviceInterfaceID245
# define DeviceVersion 245
#elif defined (kIOUSBDeviceInterfaceID197)
# define usb_device_t    IOUSBDeviceInterface197
# define DeviceInterfaceID kIOUSBDeviceInterfaceID197
# define DeviceVersion 197
#elif defined (kIOUSBDeviceInterfaceID187)
# define usb_device_t    IOUSBDeviceInterface187
# define DeviceInterfaceID kIOUSBDeviceInterfaceID187
# define DeviceVersion 187
#elif defined (kIOUSBDeviceInterfaceID182)
# define usb_device_t    IOUSBDeviceInterface182
# define DeviceInterfaceID kIOUSBDeviceInterfaceID182
# define DeviceVersion 182
#else
# error "Unknown kIOUSBDeviceInterface version"
#endif

/* usb_interface_t - for communicating with an interface in the device */
#if defined (kIOUSBInterfaceInterfaceID300)
# define usb_interface_t IOUSBInterfaceInterface300
# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300
# define InterfaceVersion 300
#elif defined (kIOUSBInterfaceInterfaceID245)
# define usb_interface_t IOUSBInterfaceInterface245
# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245
# define InterfaceVersion 245
#elif defined (kIOUSBInterfaceInterfaceID220)
# define usb_interface_t IOUSBInterfaceInterface220
# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
# define InterfaceVersion 220
#elif defined (kIOUSBInterfaceInterfaceID197)
# define usb_interface_t IOUSBInterfaceInterface197
# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197
# define InterfaceVersion 197
#elif defined (kIOUSBInterfaceInterfaceID190)
# define usb_interface_t IOUSBInterfaceInterface190
# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190
# define InterfaceVersion 190
#elif defined (kIOUSBInterfaceInterfaceID182)
# define usb_interface_t IOUSBInterfaceInterface182
# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182
# define InterfaceVersion 182
#else
# error "Unknown kIOUSBInterfaceInterfaceID"
#endif

/* OS X native USB context */
struct usb_idevice {
	/* icompath stuff: */
	int lid;					/* Location ID */
	io_object_t ioob;			/* USB io registry object */
	int nconfig;				/* Number of configurations */
	int config;					/* This config (always 1) */
	int nifce;					/* Number of interfaces */
	/* Stuff setup when device is open: */
	usb_device_t **device;		/* OS X USB device we've opened */
	usb_interface_t **interfaces[32];	/* nifce interfaces */
	CFRunLoopSourceRef cfsources[32];	/* Corresponding event sources */
	pthread_t thread;			/* RunLoop thread */
	pthread_mutex_t lock;       /* Protect cfrunloop and cond */
	pthread_cond_t cond;        /* Signal from thread that it's started */
	IOReturn thrv;				/* Thread return value */
	CFRunLoopRef cfrunloop;     /* RunLoop */
	CFRunLoopSourceRef cfsource;/* Device event sources */
};
# endif	/* OS X */

# if defined(UNIX) && !defined(__APPLE__)

/* Linux USB context */
struct usb_idevice {
	/* icompath stuff: */
	char *dpath;			/* Device path */
	int nconfig;			/* Number of configurations */
	int config;				/* This config (always 1) */
	int nifce;				/* Number of interfaces */
	usb_ep ep[32];			/* Information about each end point for general usb i/o */
	/* Stuff setup when device is open: */
	int fd;					/* Device file descriptor */
	pthread_t thread;		/* Reaper thread */
	volatile int shutdown;	/* Flag to tell reaper that we're closing the fd */
	int sd_pipe[2];			/* pipe to signal sutdown */

								/* These are simply to deal with the device going away: */
	volatile int running;		/* Reaper thread is running. Set to 0 on reap failure */
	pthread_mutex_t lock;		/* Protect reqs list */
	struct _usbio_req *reqs;	/* linked list of current reqs */
};
	
# endif	/* Linux */

#else	/* !NATIVE_USB - Using libusb */

# ifdef USE_LIBUSB1

# include "libusb.h"
#  define usb_idevice libusb_device
#  define IUSB_ENDPOINT_DIR_MASK   LIBUSB_ENDPOINT_DIR_MASK
#  define IUSB_ENDPOINT_IN         LIBUSB_ENDPOINT_IN
#  define IUSB_ENDPOINT_OUT        LIBUSB_ENDPOINT_OUT
#  define IUSB_REQ_RECIP_DEVICE    LIBUSB_RECIPIENT_DEVICE
#  define IUSB_REQ_RECIP_INTERFACE LIBUSB_RECIPIENT_INTERFACE
#  define IUSB_REQ_RECIP_ENDPOINT  LIBUSB_RECIPIENT_ENDPOINT
#  define IUSB_REQ_TYPE_STANDARD   LIBUSB_REQUEST_TYPE_STANDARD
#  define IUSB_REQ_TYPE_CLASS      LIBUSB_REQUEST_TYPE_CLASS
#  define IUSB_REQ_TYPE_VENDOR     LIBUSB_REQUEST_TYPE_VENDOR
#  define IUSB_ENDPOINT_TYPE_MASK  LIBUSB_TRANSFER_TYPE_MASK

# else

#  include "usb.h"
#  define usb_idevice usb_device
#  define IUSB_ENDPOINT_DIR_MASK   USB_ENDPOINT_DIR_MASK
#  define IUSB_ENDPOINT_IN         USB_ENDPOINT_IN
#  define IUSB_ENDPOINT_OUT        USB_ENDPOINT_OUT
#  define IUSB_REQ_RECIP_DEVICE    USB_RECIP_DEVICE
#  define IUSB_REQ_RECIP_INTERFACE USB_RECIP_INTERFACE
#  define IUSB_REQ_RECIP_ENDPOINT  USB_RECIP_ENDPOINT
#  define IUSB_REQ_TYPE_STANDARD   USB_TYPE_STANDARD
#  define IUSB_REQ_TYPE_CLASS      USB_TYPE_CLASS
#  define IUSB_REQ_TYPE_VENDOR     USB_TYPE_VENDOR
#  define IUSB_ENDPOINT_TYPE_MASK  USB_ENDPOINT_TYPE_MASK

# endif
#endif

/* - - - - - - - - - - - - - - - - - - - - - - - - - - */

/* Transfer types for communicating to usb implementation */
typedef enum {
	icom_usb_trantype_command    = 0,
	icom_usb_trantype_interrutpt = 1,
	icom_usb_trantype_bulk       = 2
} icom_usb_trantype;

/* - - - - - - - - - - - - - - - - - - - - - - - - - - */

/* Cancelation token. */
struct _usb_cancelt {
	amutex cmtx;
	void *hcancel;		/* Pointer to implementation cancel handle */
};

/* - - - - - - - - - - - - - - - - - - - - - - - - - - */

/* These routines suplement the class code in icoms_nt.c and icoms_ux.c */

/* Add paths to USB connected instruments, to the existing */
/* icompath paths in the icoms structure. */
/* return icom error */
int usb_get_paths(struct _icompaths *p);

void usb_close_port(icoms *p);

/* Set the USB specific icoms methods */
void usb_set_usb_methods(icoms *p);

/* Copy usb_idevice contents from icompaths to icom */
/* return icom error */
int usb_copy_usb_idevice(icoms *d, icompath *s);

/* Cleanup and then free a usb_del_usb_idevice */
void usb_del_usb_idevice(struct usb_idevice *dev);

/* Cleanup any USB specific icoms info */
void usb_del_usb(icoms *p);

/* Install the cleanup signal handlers */
/* (used inside usb_open_port(), hid_open_port() */
void usb_install_signal_handlers(icoms *p);

/* Delete an icoms from our static signal cleanup list */
/* (used inside usb_close_port(), hid_close_port() */
void usb_delete_from_cleanup_list(icoms *p);

#ifdef __cplusplus
	}
#endif

#endif /* ENABLE_USB */

#define USBIO_H
#endif /* USBIO_H */
