/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl)

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef PWC_H
#define PWC_H

#include <linux/config.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/spinlock.h>
#include <linux/videodev.h>
#include <linux/wait.h>

#include <asm/semaphore.h>
#include <asm/errno.h>

/* Defines and structures for the Philips webcam */
/* Used for checking memory corruption/pointer validation */
#define PWC_MAGIC 0x89DC10ABUL
#undef PWC_MAGIC

/* Debugging info on/off */
#define PWC_DEBUG 0

#define TRACE_MODULE	0x0001
#define TRACE_PROBE	0x0002
#define TRACE_OPEN	0x0004
#define TRACE_READ	0x0008
#define TRACE_MEMORY	0x0010
#define TRACE_FLOW	0x0020
#define TRACE_SIZE	0x0040
#define TRACE_SEQUENCE	0x1000

#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
#define Info(A...)  printk(KERN_INFO  PWC_NAME " " A)
#define Err(A...)   printk(KERN_ERR   PWC_NAME " " A)


/* Defines for ToUCam cameras */
#define TOUCAM_HEADER_SIZE		8
#define TOUCAM_TRAILER_SIZE		4

/* Version block */
#define PWC_MAJOR	7
#define PWC_MINOR	1
#define PWC_RELEASE 	"7.1"

#if defined(CONFIG_ARM)
  #define PWC_PROCESSOR "ARM"
#endif
#if defined(CONFIG_M686)
  #define PWC_PROCESSOR "PPro"
#endif
#if !defined(PWC_PROCESSOR)
  #define PWC_PROCESSOR "P5"
#endif  

#if defined(__SMP__) || defined(CONFIG_SMP)
#define PWC_SMP "(SMP)"
#else
#define PWC_SMP "(UP)"
#endif

#define PWC_VERSION PWC_RELEASE " " PWC_PROCESSOR " " PWC_SMP
#define PWC_NAME "pwc"

/* Turn certain features on/off */
#define PWC_INT_PIPE 0

/* Ignore errors in the first N frames, to allow for startup delays */
#define FRAME_LOWMARK 5

/* Size and number of buffers for the ISO pipe. */
#define MAX_ISO_BUFS		2
#define ISO_FRAMES_PER_DESC	10
#define ISO_MAX_FRAME_SIZE	960
#define ISO_BUFFER_SIZE 	(ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)

/* Frame buffers: contains compressed or uncompressed video data. */
#define MAX_FRAMES		5
/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */
#define FRAME_SIZE 		(460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE)

/* Absolute maximum number of buffers available for mmap() */
#define MAX_IMAGES 		4

struct pwc_coord
{
	int x, y;		/* guess what */
	int size;		/* size, or offset */
};

/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
struct pwc_iso_buf
{
	void *data;
	int  length;
	int  read;
	purb_t urb;
};

/* intermediate buffers with raw data from the USB cam */
struct pwc_frame_buf
{
   void *data;
   volatile int filled;		/* number of bytes filled */
   struct pwc_frame_buf *next;	/* list */
#if PWC_DEBUG
   int sequence;		/* Sequence number */
#endif
};

struct pwc_device
{
#ifdef PWC_MAGIC
   int magic;
#endif
   /* Pointer to our usb_device */
   struct usb_device *udev;
   
   int type;                    /* type of cam (645, 646, 675, 680, 690) */
   int release;			/* release number */
   int unplugged;		/* set when the plug is pulled */
   int usb_init;		/* set when the cam has been initialized over USB */

   /*** Video data ***/
   int vopen;			/* flag */
   struct video_device *vdev;
   int vendpoint;		/* video isoc endpoint */
   int vcinterface;		/* video control interface */
   int valternate;		/* alternate interface needed */
   int vframes, vsize;		/* frames-per-second & size (see PSZ_*) */
   int vpalette;		/* YUV, RGB24, RGB32, etc */
   int vframe_count;		/* received frames */
   int vframes_dumped; 		/* counter for dumped frames */
   int vframes_error;		/* frames received in error */
   int vmax_packet_size;	/* USB maxpacket size */
   int vlast_packet_size;	/* for frame synchronisation */
   int vcompression;		/* desired compression factor */
   int vbandlength;		/* compressed band length; 0 is uncompressed */
   char vsnapshot;		/* snapshot mode */
   char vsync;			/* used by isoc handler */

   /* The image acquisition requires 3 to 5 steps:
      1. data is gathered in short packets from the USB controller
      2. data is synchronized and packed into a frame buffer
      3. in case data is compressed, decompress it into a separate buffer
      4. data is optionally converted to RGB/YUV 
      5. data is transfered to the user process

      Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... 
      We have in effect a back-to-back-double-buffer system.
    */
   /* 1: isoc */
   struct pwc_iso_buf sbuf[MAX_ISO_BUFS];
   char iso_init;
   
   /* 2: frame */
   struct pwc_frame_buf *fbuf;
   struct pwc_frame_buf *empty_frames, *empty_frames_tail;
   struct pwc_frame_buf *full_frames, *full_frames_tail;
   struct pwc_frame_buf *read_frame;
   struct pwc_frame_buf *fill_frame;
   int frame_size;
   int frame_header_size, frame_trailer_size;
   int drop_frames;
#if PWC_DEBUG
   int sequence;			/* Debugging aid */
#endif
   
   /* 3: decompression */
   struct pwc_decompressor *decompressor;	/* function block with decompression routines */
   void *decompress_data;		/* private data for decompression engine */
   void *decompress_buffer;		/* decompressed data */

   /* 4: image */
   /* We have an 'image' and a 'view', where 'image' is the fixed-size image
      as delivered by the camera, and 'view' is the size requested by the
      program. The camera image is centered in this viewport, laced with 
      a gray or black border. view_min <= image <= view <= view_max;
    */
   int image_mask;			/* bitmask of supported sizes */
   struct pwc_coord view_min, view_max;	/* minimum and maximum sizes */
   struct pwc_coord image, view;	/* image and viewport size */
   struct pwc_coord offset;		/* offset within the viewport */

   void *image_data;			/* total buffer, which is subdivided into ... */
   void *image_ptr[MAX_IMAGES];		/* ...several images... */
   int fill_image;			/* ...which are rotated. */
   int image_read_pos;			/* In case we read data in pieces, keep track of were we are in the imagebuffer */
   int image_used[MAX_IMAGES];		/* For MCAPTURE and SYNC */

   /* Kernel specific structures. These were once moved to the end 
      of the structure and padded with bytes after I found out
      some of these have different sizes in different kernel versions.
      But since this is now a source release, I don't have this problem
      anymore.

      Fortunately none of these structures are needed in the pwcx module.
    */
   struct semaphore modlock;		/* to prevent races in video_open(), etc */
   spinlock_t ptrlock;			/* for manipulating the buffer pointers */

   /*** Misc. data ***/
   wait_queue_head_t frameq;		/* When waiting for a frame to finish... */
   wait_queue_head_t pollq;		/* poll() has it's own waitqueue */
   wait_queue_head_t remove_ok;		/* When we got hot unplugged, we have to avoid a few race conditions */
#if PWC_INT_PIPE
   void *usb_int_handler;		/* for the interrupt endpoint */
#endif   
};

/* Enumeration of image sizes */
#define PSZ_SQCIF	0x00
#define PSZ_QSIF	0x01
#define PSZ_QCIF	0x02
#define PSZ_SIF		0x03
#define PSZ_CIF		0x04
#define PSZ_VGA		0x05
#define PSZ_MAX		6



#ifdef __cplusplus
extern "C" {
#endif

/* Global variables */
extern int pwc_trace;
extern int pwc_preferred_compression;

/** functions in pwc-if.c */
int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);

/** Functions in pwc-misc.c */
/* sizes in pixels */
extern struct pwc_coord pwc_image_sizes[PSZ_MAX];

int pwc_decode_size(struct pwc_device *pdev, int width, int height);
void pwc_construct(struct pwc_device *pdev);

/** Functions in pwc-ctrl.c */
/* Request a certain video mode. Returns < 0 if not possible */
extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
/* Calculate the number of bytes per image (not frame) */
extern void pwc_set_image_buffer_size(struct pwc_device *pdev);

/* Various controls; should be obvious. Value 0..65535, or < 0 on error */
extern int pwc_get_brightness(struct pwc_device *pdev);
extern int pwc_set_brightness(struct pwc_device *pdev, int value);
extern int pwc_get_contrast(struct pwc_device *pdev);
extern int pwc_set_contrast(struct pwc_device *pdev, int value);
extern int pwc_get_gamma(struct pwc_device *pdev);
extern int pwc_set_gamma(struct pwc_device *pdev, int value);
extern int pwc_get_saturation(struct pwc_device *pdev);
extern int pwc_set_saturation(struct pwc_device *pdev, int value);

/* Power down or up the camera; not supported by all models */
extern int pwc_camera_power(struct pwc_device *pdev, int power);

/* Private ioctl()s; see pwc-ioctl.h */
extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);


/** pwc-uncompress.c */
/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
extern int pwc_decompress(struct pwc_device *pdev);

#ifdef __cplusplus
}
#endif


#endif