--- hrt.c 2008-07-13 13:15:07.000000000 -0400 +++ hrt.base.c 2008-07-13 13:14:39.000000000 -0400 @@ -1,29 +1,29 @@ /* * hrt.c * - * last updated - 7 July 2008 + * last updated - 18 June 2007 * - * Peng Chen/ Chi Zhang/ Dawei Su + * Jie Chen/ Ke Chen/ Sai This is a device driver for the PixelSmart512-8 (greyscale) and Video Gala (color) framegrabbers. + For more information on these devices, see http://www.pixelsmart.com. This driver is produced as a course project for the 'linux kernel programming' course at the Florida State University, as a term project submitted by the team - comprising of Peng Chen, Chi Zhang, Dawei Su, in the summer of 2008. + comprising of Jie Chen, Ke Chen, Sai, in the summer of 2007. - This driver carries forward the work done by other teams in the last 4 years - by Jie Chen, Ke Chen, Sai, Atulya Mahajan, Sean Toh,Brett W. Thompson, - Gilberto Morejon, Veena Adityan, Arthi Gokarn and Alex Rudnick, Ryan Walega - and Daniel Beech, under the guidance of Dr Ted Baker. + This driver carries forward the work done by other teams in the last 3 years + by Atulya Mahajan, Sean Toh,Brett W. Thompson, Gilberto Morejon, Veena Adityan, + Arthi Gokarn and Alex Rudnick, Ryan Walega And Daniel Beech, under the guidance of Dr Ted Baker. This driver supports the following features 1. Completely Support for the greyscale as well as color frame grabber cards 2. Completely Support for interrupt driven I/O 3. Completely Support for streaming I/O from color/grey scale devices 4. Automatic detection of the type of device present - 5. Completely ported to 2.6.25 Linux Kernel based on Video for Linux 2 std + 5. Completely ported to 2.6.21.1 Linux Kernel Note: This was tested and ran under the Fedora distro. This code was purposly left 'dirty' with printk's to help others who wish to pursue this @@ -35,34 +35,42 @@ #define __KERNEL__ #endif -#include +/* #include tpb */ #include /* udelay */ +#include /* error codes */ +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include #include + +/* #include tpb */ +#include + #include -#include -#include + +#include +#include +#include + +#include + +/* After 2.6.18, to use the v4l2, we should include this head file */ #include #include "hrt.h" -//#include -//#include /* error codes */ -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include + +#ifndef HAVE_V4L2 +# error Sorry, this module requires v4l2. You should patch your kernel with v4l2 or you could download the non-v4l2 dependent module hrtmem.c. +#endif /*#define HRT_DEBUG*/ @@ -79,60 +87,22 @@ #else #define hrt_parm(name, pstr, type, perm) module_param(name, type, perm) #endif - -static int testing_isa_mode = 1; -static int major_number = 82; +int testing_isa_mode = 1; +int cleanup_context = 0; +static +int major_number = 82; hrt_parm(major_number, "i", int, 0); -static unsigned int vid_limit = 16; -module_param(vid_limit,int,0644); -MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); - -/* Minor number, or -1 for first free */ -static int video_minor = -1; -static int video_nr = -1; - -/* Don't put V4L2_CAP_STREAMING in capabilities; recommended for xawtv */ -static unsigned int disable_streaming = 0; - -module_param(video_minor, int, 0); - -module_param(disable_streaming, int, 0); - - -MODULE_AUTHOR("Peng Chen, Chi Zhang, Dawei Su, Ted Baker, Brett W. Thompson, Gilberto Morejon, Veena Adityan, Arthi Gokarn, Alex Rudnick, Sean Toh, Atulya Mahajan"); -MODULE_DESCRIPTION("Driver for HRT Pixelsmart 512-8-PCI"); -MODULE_LICENSE("GPL"); - -/* values for field hrt_dev->state */ -#define HRT_UNINITIALIZED_STATE 1 -#define HRT_INITIALIZING_STATE 2 -#define HRT_CLOSED_STATE 4 -#define HRT_OPEN_STATE 8 -#define HRT_FINALIZING_STATE 16 - -/* values for field hrt_dev->mode */ -#define HRT_DUAL_PORTED_MODE 1 -#define HRT_COLOR_MODE 2 -#define HRT_STREAMING_MODE 4 -#define HRT_IRQ_MODE 8 -#define HRT_ISA_MODE 16 - -/* values for global hrt_module_state */ - -#define HRT_MODULE_UNINITIALIZED_STATE 1 -#define HRT_MODULE_INITIALIZING_STATE 2 -#define HRT_MODULE_INITIALIZED_STATE 4 -#define HRT_MODULE_FINALIZING_STATE 8 - #ifndef HRT_MAX_DEVICES -#define HRT_MAX_DEVICES 4 +#define HRT_MAX_DEVICES 4 #endif #ifndef HRT_IO_SIZE #define HRT_IO_SIZE 0x4000 #endif + + /********************************************************************/ /** * hrt_ctls - controls the user can set via V4L ioctl's @@ -180,435 +150,283 @@ /* Number of registers on the board- checked in i2c_init() */ #define HRT_SAA7110_MAXREG 0x34 + +/********************************************************************/ +/** + * struct stream_buffer - represents a single buffer for streaming + */ +struct stream_buffer { + struct v4l2_buffer vidbuf; /* For the V4L ioctl's */ + int fields_grabbed; /* Two-bit pair of flags indicating which fields + have been grabbed (i.e., 00 = no fields, + 11 = both) */ + struct list_head node; /* Connection into queues */ + int requested; /* Set by REQBUF ioctl */ + unsigned char *vaddress; /* This is the pointer to the vmalloc()'d + memory into which the actual frame goes */ + int vma_refcount; /* Reference count */ +}; + + /********************************************************************/ -struct hrt_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; -}; - -static struct hrt_fmt formats[] = { - { - .name = "15 bpp RGB packed, le", - .fourcc = V4L2_PIX_FMT_RGB555, - .depth = 16, - }, { - .name = "8 bpp, grey packed", - .fourcc = V4L2_PIX_FMT_GREY, - .depth = 8, - } -}; - -/* buffer for one video frame */ -struct hrt_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - struct hrt_fmt *fmt; - unsigned int fields_grabbed; -}; +/** + * struct stream_buffer_queue - FIFO of stream_buffer structs + */ +struct stream_buffer_queue { + struct stream_buffer *streambuf; /* Pointer to node data */ + struct list_head head; /* Start of the queue */ + rwlock_t lock; /* Lock to protect the queue */ + int length; /* How many nodes are on the queue */ +}; /********************************************************************/ /** * HRT device descriptor */ -static LIST_HEAD(hrt_devlist); - -struct hrt_dev { - struct list_head hrt_devlist; - int users; /* see how many readers */ - struct mutex lock; - struct list_head capture; /* link all video capture buffers */ - int registered; - int num; - int state; - unsigned long virt_addr; - unsigned long phys_addr; - spinlock_t spinlock; - int is_locked; - wait_queue_head_t wait_queue; - struct timer_list timer; - struct tasklet_struct tasklet; - int timer_active; /* timer_active != 0 iff timer or irq is active */ - int tasklet_active; - int irq; /* irq != 0 if board supports interrupts, - < 0 if handler not installed - > 0 if handler is installed */ - volatile int irq_count; - volatile int i2c_bits; /* last values written to i2c */ - char saa7110_registers[HRT_SAA7110_MAXREG+1]; - int mode; - int rows, cols, bytes_per_pixel; - int win_row, win_col, win_width, win_height; - int field; /* current field being digitized */ - int field_changes; /* how many field changes we are waiting for */ - int is_frozen; /* the device is either frozen or being frozen */ - unsigned int field_id; /* tracking the field being read */ - unsigned char *localbuf; /* storing the frame currently read from the device */ - int streaming_state; - /* We allow the user to make the view upside down too ! - * came out of compulsion actually since we have the cameras installed - * upside down ! - * the following variable determines what sort of output we return to the user - * set using an ioctl - */ - int upside_down; - - /* Following structure used for registering with V4L */ - struct video_device *video_dev; +typedef struct { + /* Added By Ryan Walega & Daniel Beech */ + int registered; + int num; + int state; + /* minor device number, index in hrt_devices[] */ + unsigned long virt_addr; + unsigned long phys_addr; + /* cannot be opened again until released */ + + /* spinlock and is_locked control access to the device */ + spinlock_t spinlock; + int is_locked; + wait_queue_head_t wait_queue; + struct timer_list timer; + struct tasklet_struct tasklet; + int timer_active; + int tasklet_active; + /* timer_active != 0 iff timer or irq is active */ + int irq; + /* irq != 0 if board supports interrupts + = -irq if handler not installed + = irq if handler is installed */ + volatile + int irq_count; + volatile + int i2c_bits; + /* last values written to i2c */ + char saa7110_registers[HRT_SAA7110_MAXREG+1]; + /* video data format, and dependent values */ + int mode; + int rows, cols, bytes_per_pixel; + int win_row, win_col, win_width, win_height; + /* current field being digitized */ + int field; + /* how many field changes we are waiting for */ + int field_changes; + /* the device is either frozen or being frozen */ + int is_frozen; + + /* Local buffer for storing the frame currently read from the device */ + /* Added june 8,2005 - atulya/sean */ + unsigned char *framedata; + /* Variable to keep track of the field being read inside the current frame */ + unsigned int field_id; + /* Semaphore for the device structure */ + struct semaphore sem; + /* Local buffer used for manipulation of the data returned + * by the color device. + * ONLY used by the color device + */ + unsigned char *localbuf; + /* Flag for streaming mode */ + int streaming; + /* Number of buffers for streaming */ + int numbufs; + /* Array of buffers */ + struct stream_buffer *streambufs; + /* List of queued buffers */ + struct stream_buffer_queue capture_list; + /* List of filled buffers */ + struct stream_buffer_queue done_list; + int stream_buffers_mapped; + struct stream_buffer stream_buf[MAX_CAPTURE_BUFFERS]; + int stream_buffers_requested; + + /* Variable used to keep track of our state while streaming + * added 13 June 2005 - Atulya/Sean + */ + int streaming_state; + + /* We allow the user to make the view upside down too ! + * came out of compulsion actually since we have the cameras installed + * upside down ! + * the following variable determines what sort of output we return to the user + * set using an ioctl + */ + int upside_down; + + /* Following structure used for registering with V4L */ + struct video_device video_dev; + struct v4l2_format clientfmt; + struct v4l2_captureparm capture; - /* Bytes per raster line. 640 for grey scale card - * and 2*640 = 1280 for the color card - */ - unsigned int bytesperline; - /* Memory size of the entire frame - * = 512 X 480 X 1 bytes per pixel= 240 KB for grey scale card - * = 640 X 480 X 2 bytes per pixel= 600 KB for color card - */ - unsigned int framesize; - /* Current region of interest - * fields = width,height,starty,startx - */ - struct subwindow *win; + /* Bytes per raster line. 640 for grey scale card + * and 2*640 = 1280 for the color card + */ + unsigned int bytesperline; + /* Memory size of the entire frame + * = 512 X 480 X 1 bytes per pixel= 240 KB for grey scale card + * = 640 X 480 X 2 bytes per pixel= 600 KB for color card + */ + unsigned int framesize; + /* Current region of interest + * fields = width,height,starty,startx + */ + struct subwindow *win; #ifdef CONFIG_PCI - /* structure to represent a pci device */ - struct pci_dev *pci_dev; + /* structure to represent a pci device */ + struct pci_dev *pci_dev; #endif -}; +} hrt_t; /******************************************************************** *************** basic file operations (fops) ******************** */ int hrt_open (struct inode *inode, struct file *file); -int hrt_close (struct inode *inode, struct file *file); +int hrt_release(struct inode *inode, struct file *file); int hrt_read (struct file *file, char *buf, size_t count, loff_t * ppos); -int hrt_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +int hrt_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); int hrt_mmap (struct file *file, struct vm_area_struct *vma); unsigned int hrt_poll (struct file *file, poll_table *wait); -//static int hrt_do_private_ioctl(struct hrt_dev *hrtdev, unsigned int cmd, unsigned long arg); +static int hrt_do_private_ioctl(hrt_t *hrtdev, unsigned int cmd, + unsigned long arg); /********************************************************************/ static struct file_operations hrt_fops = { - .owner = THIS_MODULE, - .open = hrt_open, - .release = hrt_close, - .read = hrt_read, - .ioctl = hrt_ioctl, - .mmap = hrt_mmap, - .llseek = no_llseek, - .poll = hrt_poll, + .owner = THIS_MODULE, + .open = hrt_open, + .release = hrt_release, + .read = hrt_read, + .ioctl = hrt_ioctl, + .mmap = hrt_mmap, + .llseek = no_llseek, + .poll = hrt_poll, + }; +/********************************************************************/ +/* XXX: Get an actual official number from kraxel@bytesex.org + (see /usr/src/linux/include/linux/videodev.h) */ +#define VID_HARDWARE_HRT 36 +/* AddED BY RYAN WALEGA */ +//void grabber_release(void); static void grabber_release(struct video_device *vfd){ } +/********************************************************************/ +static struct video_device videodev_template = { + .owner = THIS_MODULE, + .name = "HRT Pixelsmart (PS512-8-PCI)", + .type = HRT_VID_TYPE, + .hardware = VID_HARDWARE_HRT, + .fops = &hrt_fops, + .release = grabber_release, +}; +/********************************************************************/ /** - * struct hrt_fh - contains data to be stored per file handle - * - * Private data for a device is not just the hrt_dev structure - * but also the subwindow structure that represents the subwindow + * struct hrt_per_file - contains data to be stored per file handle + * + * Private data for a device is not just the hrt_t structure + * but also the subwindow structure that represents the subwindow * of the entire frame being displayed */ -struct hrt_fh { - struct subwindow win; - struct hrt_dev *dev; - struct hrt_fmt *fmt; - struct videobuf_queue vb_vidq; - enum v4l2_buf_type type; +struct hrt_per_file { + struct subwindow win; + hrt_t *hrtdev; }; - /********************************************************************/ -static int hrt_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - return videobuf_reqbufs(&fh->vb_vidq, p); -} - -static int hrt_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - return 0; -} - -static int hrt_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - return videobuf_querybuf(&fh->vb_vidq, p); -} - -static int hrt_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - return videobuf_qbuf(&fh->vb_vidq, p); -} - -static int hrt_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - return videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK); -} - -static int hrt_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - return videobuf_streamon(&fh->vb_vidq); -} - -static int hrt_streamoff(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - return videobuf_streamoff(&fh->vb_vidq); -} - -static int hrt_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strcpy(cap->driver, "hrt"); - strncpy(cap->card, "PS 512-8-PCI", sizeof(cap->card)); - cap->version = KERNEL_VERSION(0, 0, 2); - - if (disable_streaming) { - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; - } else { - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - } - return 0; -} - -static int hrt_enum_fmt_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - struct hrt_dev *dev = fh->dev; - int index=f->index; - enum v4l2_buf_type type = f->type; - - memset(f, 0, sizeof(*f)); - f->index = index; - f->type = type; - if(dev->mode & HRT_COLOR_MODE){ - f->pixelformat = V4L2_PIX_FMT_RGB555; //check this one - strcpy(f->description, "Color"); - } - else{ - f->pixelformat = V4L2_PIX_FMT_GREY; - strcpy(f->description, "Grey"); - } - - return 0; -} - -static int hrt_s_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - return 0; -} -static int hrt_g_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - struct hrt_dev *dev = fh->dev; - - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - - if(dev->mode & HRT_COLOR_MODE) - f->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB555; - else - f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; - - mutex_lock(&dev->lock); - - f->fmt.pix.width = dev->win->width; - f->fmt.pix.height = dev->win->height; - - f->fmt.pix.bytesperline = dev->bytesperline; - f->fmt.pix.sizeimage = dev->framesize; - - mutex_unlock(&dev->lock); - - printk("pix.width (%d), pic.height (%d)", - f->fmt.pix.width, f->fmt.pix.height); - printk("pix.bytesperline (%d), pic.sizeimage (%d)", - f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); - return 0; - } else { - return -EINVAL; - } -} -static int hrt_g_crop(struct file *file, void *priv, - struct v4l2_crop *win) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - struct hrt_dev *dev = fh->dev; - - mutex_lock(&dev->lock); - - win->c.height = dev->win->height; - win->c.width = dev->win->width; - win->c.top = dev->win->starty; - win->c.left = dev->win->startx; - - mutex_unlock(&dev->lock); - - return 0; -} - -static int hrt_s_crop(struct file *file, void *priv, - struct v4l2_crop *win) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - struct hrt_dev *dev = fh->dev; - - mutex_lock(&dev->lock); - - dev->win->height = win->c.height; - dev->win->width = win->c.width; - dev->win->starty = win->c.top; - dev->win->startx = win->c.left; - - mutex_unlock(&dev->lock); - - return 0; -} - -static int hrt_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - struct hrt_dev *dev = fh->dev; - int i; - for (i = 0; i < ARRAY_SIZE(hrt_ctls); i++) - if (hrt_ctls[i].id == c->id) - break; - - /* Didn't find the id */ - if (i == ARRAY_SIZE(hrt_ctls)) { - return -EINVAL; - } - - mutex_lock(&dev->lock); - *c = hrt_ctls[i]; - mutex_unlock(&dev->lock); - - return 0; -} - -static int hrt_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct hrt_fh *fh = (struct hrt_fh*)priv; - struct hrt_dev *dev = fh->dev; - int i; - - for (i = 0; i < ARRAY_SIZE(hrt_ctls); i++) - if (hrt_ctls[i].id == c->id) - break; +/* Minor number, or -1 for first free */ +static int video_minor = -1; - if (i == sizeof(hrt_ctls)) - return -EINVAL; +/* Don't put V4L2_CAP_STREAMING in capabilities; recommended for xawtv */ +static unsigned int disable_streaming = 0; - if (c->id == V4L2_CID_BRIGHTNESS) { - c->value = dev->saa7110_registers[HRT_BRIGHTNESS_REG]; - } else if (c->id == V4L2_CID_CONTRAST) { - c->value = dev->saa7110_registers[HRT_BRIGHTNESS_REG]; - } else { - return -EINVAL; - } +module_param(video_minor, int, 0); - return 0; -} +module_param(disable_streaming, int, 0); -static int hrt_s_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - return 0; -} -static int hrt_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - unsigned int n; +MODULE_AUTHOR("Brett W. Thompson, Gilberto Morejon, Veena Adityan, Arthi Gokarn, Alex Rudnick, Sean Toh, Atulya Mahajan"); +MODULE_DESCRIPTION("Driver for HRT Pixelsmart 512-8-PCI"); +MODULE_LICENSE("GPL"); - /* Only one input */ - if (inp->index > 0) - return -EINVAL; - n = inp->index; - memset(inp, 0, sizeof(*inp)); - inp->index = n; - inp->type = V4L2_INPUT_TYPE_CAMERA; - sprintf(inp->name, "NTSC Camera"); +/********************************************************************/ +/** + * dprintk, hrt_printk - thin wrappers around printk() + */ +#define dprintk(fmt, arg...) { printk("hrt: " fmt, ## arg); } +#define hrt_printk(fmt, arg...) { printk(KERN_ALERT "hrt: " fmt, ## arg); } +/********************************************************************/ - return 0; -} +/* values for field hrt_t->state */ +#define HRT_UNINITIALIZED_STATE 1 +#define HRT_INITIALIZING_STATE 2 +#define HRT_CLOSED_STATE 4 +#define HRT_OPEN_STATE 8 +#define HRT_FINALIZING_STATE 16 + +/* values for field hrt_t->mode */ +#define HRT_DUAL_PORTED_MODE 1 +#define HRT_COLOR_MODE 2 +#define HRT_STREAMING_MODE 4 +#define HRT_IRQ_MODE 8 +#define HRT_ISA_MODE 16 -static int hrt_g_parm(struct file *file, void *priv, - struct v4l2_streamparm * parm) +/* values for global hrt_module_state */ -{ - struct v4l2_standard s; +#define HRT_MODULE_UNINITIALIZED_STATE 1 +#define HRT_MODULE_INITIALIZING_STATE 2 +#define HRT_MODULE_INITIALIZED_STATE 4 +#define HRT_MODULE_FINALIZING_STATE 8 +/********************************************************************/ - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - memset(parm, 0, sizeof(*parm)); - v4l2_video_std_construct(&s, V4L2_STD_NTSC, "NTSC"); - parm->parm.capture.timeperframe = s.frameperiod; - return 0; -} -/********************************************************************/ -static struct video_device hrt_template = { - .owner = THIS_MODULE, - .name = "HRT Pixelsmart PS512-8-PCI", - .type = HRT_VID_TYPE, - .fops = &hrt_fops, - .release = grabber_release, - .vidioc_querycap = hrt_querycap, - .vidioc_enum_fmt_cap = hrt_enum_fmt_cap, - .vidioc_s_fmt_cap = hrt_s_fmt_cap, - .vidioc_g_fmt_cap = hrt_g_fmt_cap, - .vidioc_g_crop = hrt_g_crop, - .vidioc_s_crop = hrt_s_crop, - .vidioc_reqbufs = hrt_reqbufs, - .vidioc_querybuf = hrt_querybuf, - .vidioc_qbuf = hrt_qbuf, - .vidioc_dqbuf = hrt_dqbuf, - .vidioc_enum_input = hrt_enum_input, - .vidioc_queryctrl = hrt_queryctrl, - .vidioc_g_ctrl = hrt_g_ctrl, - .vidioc_s_ctrl = hrt_s_ctrl, - .vidioc_streamon = hrt_streamon, - .vidioc_streamoff = hrt_streamoff, - .vidioc_g_parm = hrt_g_parm, - .vidioc_try_fmt_cap = hrt_try_fmt_cap, - .tvnorms = V4L2_STD_525_60, - .current_norm = V4L2_STD_NTSC_M, -}; - int hrt_module_state = HRT_MODULE_UNINITIALIZED_STATE; int hrt_nonpci_devices = 0; /* number of non-pci devices detected */ /* non-pci devices have lower numbers */ -/*device number*/ int hrt_num_devices = 0; /* total number of devices detected */ #define HRT_IS_PCI(X) ((X) >= hrt_nonpci_devices) -struct hrt_dev *hrt_devices[HRT_MAX_DEVICES]; +/* ??? consider dynamically allocating the device + objects as they are probed and detected, and + using a linked list here instead of an array */ + +hrt_t hrt_devices[HRT_MAX_DEVICES]; + +/* Flag to change semantics of mmap() upon the IOC_HRT_NEXT_MMAP_IS_DIRECT + ioctl */ +static unsigned int next_mmap_is_direct = 0; +struct hrt_per_file *per_file_init( hrt_t *hrtdev); + + +/* Veena and Arthi's streaming functions */ +int mmap_request_buffers(hrt_t *dev, + struct v4l2_requestbuffers *req); +int hrt_streamon(hrt_t *hrtdev, __u32 type); +void hrt_streamoff(hrt_t *hrtdev, __u32 type); +int hrt_dequeuebuffer(hrt_t *hrtdev, + struct v4l2_buffer *buf); +int hrt_queuebuffer(hrt_t *hrtdev, + struct v4l2_buffer *buf); + + #ifdef HRT_DEBUG /****************************** @@ -641,25 +459,25 @@ int hrt_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data) { - int n, i; - int ips, tps, rps; - char *org_buf = buf; - - ips = 0; - tps = 0; - rps = 0; - - /* dont excede count bytes when writing to buf */ - /* just write to buf as a normal ptr to a file */ - - write_buf("dev HZ/10 int timer read int/s timer/s read/s\n"); - for (i=0; iirq_count, - ips, tps, rps); - } - *eof = 1; - return buf - org_buf; + int n, i; + int ips, tps, rps; + char *org_buf = buf; + + ips = 0; + tps = 0; + rps = 0; + + /* dont excede count bytes when writing to buf */ + /* just write to buf as a normal ptr to a file */ + + write_buf("dev HZ/10 int timer read int/s timer/s read/s\n"); + for (i=0; ii2c_bits |= HRT_I2C_SDA; - else dev->i2c_bits &= ~HRT_I2C_SDA; - iowrite8(dev->i2c_bits, (void *) I2C_CONTROL(addr)); - wmb(); + if (high) dev->i2c_bits |= HRT_I2C_SDA; + else dev->i2c_bits &= ~HRT_I2C_SDA; + iowrite8(dev->i2c_bits, (void *) I2C_CONTROL(addr)); + wmb(); } /********************************************************************/ @@ -799,43 +617,137 @@ * scl = set clock bit on I2C bus * to the value given by parameter high */ -static inline void hrt_scl(struct hrt_dev *dev, unsigned long addr, int high) +static inline +void hrt_scl(hrt_t *dev, unsigned long addr, int high) +{ + if (high) dev->i2c_bits |= HRT_I2C_SCL; + else dev->i2c_bits &= ~HRT_I2C_SCL; + iowrite8(dev->i2c_bits, (void *) I2C_CONTROL(addr)); + wmb(); +} + +/********************************************************************/ +/** + * Queue manipulation functions (basically wrappers for the Linux + * linked list functions) + */ +void queue_add_tail(struct stream_buffer *streambuf, + struct stream_buffer_queue *q) +{ + unsigned long flags; + + if (streambuf == NULL || q == NULL) return; + + write_lock_irqsave(&q->lock, flags); + list_add_tail(&streambuf->node, &q->head); + q->length++; + write_unlock_irqrestore(&q->lock, flags); +} + +/********************************************************************/ +void queue_del(struct stream_buffer *streambuf, + struct stream_buffer_queue *q) +{ + unsigned long flags; + + if (q == NULL) return; + + write_lock_irqsave(&q->lock, flags); + list_del(&streambuf->node); + q->length--; + write_unlock_irqrestore(&q->lock, flags); +} + +/********************************************************************/ +struct stream_buffer *queue_peek_head(struct stream_buffer_queue *q) +{ + unsigned long flags; + struct stream_buffer *streambuf; + + if (q == NULL) return NULL; + + read_lock_irqsave(&q->lock, flags); + streambuf = list_entry(q->head.next, struct stream_buffer, node); + read_unlock_irqrestore(&q->lock, flags); + + return streambuf; +} + +/********************************************************************/ +struct stream_buffer *queue_del_head(struct stream_buffer_queue *q) +{ + unsigned long flags; + struct stream_buffer *streambuf; + + if (q == NULL) return NULL; + if (!q->length) return NULL; + + read_lock_irqsave(&q->lock, flags); + streambuf = list_entry(q->head.next, struct stream_buffer, node); + list_del(&streambuf->node); + q->length--; + read_unlock_irqrestore(&q->lock, flags); + return streambuf; +} + +/********************************************************************/ +/** + * hrt_streamoff - called by the STREAMOFF ioctl. + * Used to turn off the streaming read from the device + */ +void hrt_streamoff(hrt_t *hrtdev, __u32 type) { - if (high) dev->i2c_bits |= HRT_I2C_SCL; - else dev->i2c_bits &= ~HRT_I2C_SCL; - iowrite8(dev->i2c_bits, (void *) I2C_CONTROL(addr)); - wmb(); -} -/********************************************************************* -* We did not use it for hardware data copy, -* since it is hardware dependent. -* Maybe, you can try readl -*********************************************************************/ -static inline void * datacpy(void * to, const void * from, size_t n) -{ -int d0, d1, d2; -__asm__ __volatile__( - "rep ; movsl\n\t" - "testb $2,%b4\n\t" - "je 1f\n\t" - "movsw\n" - "1:\ttestb $1,%b4\n\t" - "je 2f\n\t" - "movsb\n" - "2:" - : "=&c" (d0), "=&D" (d1), "=&S" (d2) - :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) - : "memory"); -return (to); + int i = 0; + struct stream_buffer *buf; + /* Cant turn streaming off if it isnt on !! */ + if (!hrtdev->streaming) { + hrt_printk("STREAMOFF - Not in streaming mode\n"); + return; + } + /* We can only have the following type specified + * anything else is an error + */ + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + hrt_printk("STREAMOFF - Wrong buffer type\n"); + return; + } + /* Set the 'streaming' variable to 0 + * indicates that we are no more in streaming mode + * used by the timer handler to determine what to do + */ + hrtdev->streaming = 0; + + /* Added 13 June 2005 - Atulya/Sean */ + hrtdev->streaming_state = 0; + + hrtdev->upside_down = 0; + + /* Wait till the queue is empty */ + while ((buf = queue_del_head(&hrtdev->done_list))) { + buf->vidbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; + i++; + } + + while (queue_del_head(&hrtdev->capture_list)); + hrt_printk("Streaming is turned off\n"); } -#if 0 + + + /********************************************************************/ /** * hrt_do_private_ioctl - handle private ioctl's on device */ -static int hrt_do_private_ioctl(struct hrt_dev *hrtdev, unsigned int cmd, +static int hrt_do_private_ioctl(hrt_t *hrtdev, unsigned int cmd, unsigned long arg) { + if (cmd == IOC_HRT_NEXT_MMAP_IS_DIRECT) { + /* The next mmap() that's called on /dev/video + will map the device's memory directly- this is + for userspace drivers */ + next_mmap_is_direct = 1; + return 0; + } /*else if (cmd == IOC_HRT_SET_I2CREG) { struct i2c_regval r; @@ -855,7 +767,7 @@ } */ /* Set the region of interest - subwindow */ - if (cmd == IOC_HRT_SET_ROI) { + else if (cmd == IOC_HRT_SET_ROI) { struct subwindow win; if (copy_from_user(&win, (void *) arg, sizeof(win))) { @@ -896,7 +808,7 @@ /* /\* First byte is the length of the array *\/ */ /* if (copy_from_user(&len, (void *) arg, 1)) */ /* return -EFAULT; */ - /* printk("size of array = %d\n", len); */ + /* dprintk("size of array = %d\n", len); */ /* buf = vmalloc(len + 1); */ /* if (copy_from_user(buf, (void *) arg, len)) { */ @@ -914,49 +826,94 @@ return -EINVAL; } -#endif + + /********************************************************************/ -/* - * sda_scl = set data and clock bits on I2C bus - * to the values given by parameters sda_high and scl_high +/** + * hrt_direct_mmap - provides direct access to the card's memory */ -static inline -void hrt_sda_scl(struct hrt_dev *dev, - unsigned long addr, int sda_high, int scl_high) +static int hrt_direct_mmap(struct file *file, struct vm_area_struct *vma) { - if (sda_high) dev->i2c_bits |= HRT_I2C_SDA; - else dev->i2c_bits &= ~HRT_I2C_SDA; - if (scl_high) dev->i2c_bits |= HRT_I2C_SCL; - else dev->i2c_bits &= ~HRT_I2C_SCL; - iowrite8(dev->i2c_bits, (void *) I2C_CONTROL(addr)); - wmb(); + struct hrt_per_file *per_file = file->private_data; + hrt_t *hrtdev = per_file->hrtdev; + vma->vm_flags |= (VM_IO | VM_RESERVED); + /* Just map the pages directly */ + if (remap_pfn_range(vma, + vma->vm_start, hrtdev->phys_addr, vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; } - -/********************************************************************/ -/* - * sda_read = read data bit from I2C control register - */ -static inline -int hrt_sda_read(unsigned long addr) -{ char c = ioread8((void *) I2C_CONTROL(addr)); return (c & HRT_I2C_SDA); } /********************************************************************/ -/* - * hrt_i2c_start = start I2C data transmission +/** + * mmap_stream_buffer_from_offset - get a buffer via the specified offset */ -static inline -void hrt_i2c_start(struct hrt_dev *dev, unsigned long addr) -{ - hrt_sda_scl(dev, addr, 0, 0); - hrt_i2c_delay(); - hrt_sda(dev, addr, 1); - hrt_i2c_delay(); - hrt_scl(dev, addr, 1); - hrt_i2c_delay(); - hrt_sda(dev, addr, 0); - hrt_i2c_delay(); - hrt_scl(dev, addr, 0); +static struct stream_buffer *mmap_stream_buffer_from_offset(hrt_t *dev, + unsigned long offset) +{ + int i; + offset *= PAGE_SIZE; + for (i = 0; i < MAX_CAPTURE_BUFFERS; ++i) { + if (offset == dev->stream_buf[i].vidbuf.m.offset) { + hrt_printk("mmap_stream_buffer_from_offset: offset found at : 0x%lx", offset); + return &dev->stream_buf[i]; + } + } + hrt_printk("mmap_stream_buffer_from_offset: NOTHING found."); + return NULL; +} + +/* + * + * Dr Baker's I2C routines follow + * + */ + +/********************************************************************/ +/* + * sda_scl = set data and clock bits on I2C bus + * to the values given by parameters sda_high and scl_high + */ +static inline +void hrt_sda_scl(hrt_t *dev, + unsigned long addr, int sda_high, int scl_high) +{ + if (sda_high) dev->i2c_bits |= HRT_I2C_SDA; + else dev->i2c_bits &= ~HRT_I2C_SDA; + if (scl_high) dev->i2c_bits |= HRT_I2C_SCL; + else dev->i2c_bits &= ~HRT_I2C_SCL; + iowrite8(dev->i2c_bits, (void *) I2C_CONTROL(addr)); + wmb(); +} + +/********************************************************************/ +/* + * sda_read = read data bit from I2C control register + */ +static inline +int hrt_sda_read(unsigned long addr) +{ char c = ioread8((void *) I2C_CONTROL(addr)); return (c & HRT_I2C_SDA); } + + +/********************************************************************/ +/* + * hrt_i2c_start = start I2C data transmission + */ +static inline +void hrt_i2c_start(hrt_t *dev, unsigned long addr) +{ + hrt_sda_scl(dev, addr, 0, 0); + hrt_i2c_delay(); + hrt_sda(dev, addr, 1); + hrt_i2c_delay(); + hrt_scl(dev, addr, 1); + hrt_i2c_delay(); + hrt_sda(dev, addr, 0); + hrt_i2c_delay(); + hrt_scl(dev, addr, 0); } /********************************************************************/ @@ -964,16 +921,16 @@ * hrt_i2c_stop = end I2C data transmission */ static inline -void hrt_i2c_stop(struct hrt_dev *dev, unsigned long addr) +void hrt_i2c_stop(hrt_t *dev, unsigned long addr) { - hrt_sda_scl(dev, addr, 0, 0); - hrt_i2c_delay(); - hrt_scl(dev, addr, 1); - hrt_i2c_delay(); - hrt_sda(dev, addr, 1); - hrt_i2c_delay(); - hrt_scl(dev, addr, 0); - hrt_scl(dev, addr, 1); + hrt_sda_scl(dev, addr, 0, 0); + hrt_i2c_delay(); + hrt_scl(dev, addr, 1); + hrt_i2c_delay(); + hrt_sda(dev, addr, 1); + hrt_i2c_delay(); + hrt_scl(dev, addr, 0); + hrt_scl(dev, addr, 1); } /********************************************************************/ @@ -981,26 +938,26 @@ * hrt_i2c_send_bit */ static -int hrt_i2c_send_bit(struct hrt_dev *dev, +int hrt_i2c_send_bit(hrt_t *dev, unsigned long addr, unsigned char bit) { - unsigned long timeout; - if (bit) hrt_sda(dev, addr, 1); - else hrt_sda(dev, addr, 0); - hrt_i2c_delay(); - iowrite8(dev->i2c_bits | 0x04, (void *) I2C_CONTROL(addr)); - wmb(); - hrt_i2c_delay(); - if (I2C_BUSY(addr)) { - timeout = jiffies + HZ/10; - while (I2C_BUSY(addr)) { - if (jiffies > timeout) { - HRT_ERROR_MSG("i2c bus timeout"); - return -1; - } - } - } - return 0; + unsigned long timeout; + if (bit) hrt_sda(dev, addr, 1); + else hrt_sda(dev, addr, 0); + hrt_i2c_delay(); + iowrite8(dev->i2c_bits | 0x04, (void *) I2C_CONTROL(addr)); + wmb(); + hrt_i2c_delay(); + if (I2C_BUSY(addr)) { + timeout = jiffies + HZ/10; + while (I2C_BUSY(addr)) { + if (jiffies > timeout) { + HRT_ERROR_MSG("i2c bus timeout"); + return -1; + } + } + } + return 0; } /********************************************************************/ @@ -1008,28 +965,28 @@ * hrt_i2c_send_byte */ static -int hrt_i2c_send_byte(struct hrt_dev *dev, unsigned long addr, unsigned char data) +int hrt_i2c_send_byte(hrt_t *dev, unsigned long addr, unsigned char data) { - char bitpos, bit; - for(bitpos = 0; bitpos < 8; bitpos++) { - bit = (data & 0x80) >> 7; - data <<= 1; - if(hrt_i2c_send_bit(dev, addr, bit)) goto failure; - } - hrt_i2c_delay(); - hrt_sda_scl(dev, addr, 1, 0); - hrt_scl(dev, addr, 1); /* leave clock high */ - udelay(10); - if (hrt_sda_read(addr)) { - HRT_ERROR_MSG("no i2c ack"); - goto failure; - } - hrt_sda_scl(dev, addr, 1, 0); - return 0; + char bitpos, bit; + for(bitpos = 0; bitpos < 8; bitpos++) { + bit = (data & 0x80) >> 7; + data <<= 1; + if(hrt_i2c_send_bit(dev, addr, bit)) goto failure; + } + hrt_i2c_delay(); + hrt_sda_scl(dev, addr, 1, 0); + hrt_scl(dev, addr, 1); /* leave clock high */ + udelay(10); + if (hrt_sda_read(addr)) { + HRT_ERROR_MSG("no i2c ack"); + goto failure; + } + hrt_sda_scl(dev, addr, 1, 0); + return 0; failure: - hrt_sda_scl(dev, addr, 1, 0); - hrt_i2c_stop(dev, addr); - return -1; + hrt_sda_scl(dev, addr, 1, 0); + hrt_i2c_stop(dev, addr); + return -1; } /********************************************************************/ @@ -1044,186 +1001,89 @@ * are sorted in increasing order of register number, but the sequence may * have gaps and need not be in order. */ -int hrt_i2c_init_registers(struct hrt_dev *dev, const char *sequence) +int hrt_i2c_init_registers(hrt_t *dev, const char *sequence) { - unsigned long addr; - int i, len, cur_reg; - - len = (int) (*sequence++); - addr = dev->virt_addr; - - if (len <= 2) { - HRT_ERROR_MSG("invalid register initialization sequence"); - return -1; - } - - hrt_i2c_start(dev, addr); - - /* here we select the A/D Device on the i2c bus - * that should pay attention to the following bytes */ - if (hrt_i2c_send_byte(dev, dev->virt_addr, HRT_AD_DEVICE_ID)) { - HRT_ERROR_MSG("send_byte failed"); - return -1; - } - - /* start at the first register and increment along the way */ - if (hrt_i2c_send_byte(dev, dev->virt_addr, cur_reg = sequence[0])) { - HRT_ERROR_MSG("send_byte failed(2)"); - return -1; - } - - for(i = 0; i < len; i += 2, sequence += 2) { - char reg = sequence[0]; - char data = sequence[1]; - if (reg > HRT_SAA7110_MAXREG) { - HRT_ERROR_MSG("register %02X out of range!", reg); - return -1; - } - if (reg != cur_reg) { - - /* we're going to an entirely different register */ - hrt_i2c_stop(dev, addr); - hrt_i2c_start(dev, addr); - - /* select the chip/device on the bus */ - if (hrt_i2c_send_byte(dev, dev->virt_addr, HRT_AD_DEVICE_ID)) { - HRT_ERROR_MSG("send_byte failed(3)"); - return -1; - } - - /* select the register */ - if (hrt_i2c_send_byte(dev, dev->virt_addr, cur_reg = reg)) { - HRT_ERROR_MSG("send_byte failed(4)"); - return -1; - } - } - - if (hrt_i2c_send_byte(dev, dev->virt_addr, data)) { - HRT_ERROR_MSG("send_byte failed(5)"); - return -1; - } - dev->saa7110_registers[cur_reg++] = data; - } - /* free the i2c bus */ - hrt_i2c_stop(dev, addr); - return 0; -} + unsigned long addr; + int i, len, cur_reg; -/********************************************************************/ -int hrt_i2c_init_device(struct hrt_dev *dev) -{ - int result = 0; - HRT_DEBUG_MSG(2, "hrt_i2c_init_device entered" - " (virt_addr = %08X, addr = %08X)", - (unsigned) dev->virt_addr, - (unsigned) dev->phys_addr); - - result = hrt_i2c_init_registers(dev, saa7110_default_init_regs); - if (result) { - HRT_ERROR_MSG("hrt_i2c_init_registers failed %d", result); - return result; - } - HRT_DEBUG_MSG(2, "hrt_i2c_init_device returning %d", result); - return result; -} + len = (int) (*sequence++); + addr = dev->virt_addr; -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) -{ - struct hrt_fh *fh = vq->priv_data; - - *size = fh->win.width*fh->win.height*fh->win.depth; - - if (0 == *count) - *count = 32; - while (*size * *count > vid_limit * 1024 * 1024) - (*count)--; - - return 0; -} + if (len <= 2) { + HRT_ERROR_MSG("invalid register initialization sequence"); + return -1; + } -static void free_buffer(struct videobuf_queue *vq, struct hrt_buffer *buf) -{ - if (in_interrupt()) - BUG(); - - videobuf_waiton(&buf->vb, 0, 0); - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -#define norm_maxw() 640 -#define norm_maxh() 480 -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct hrt_fh *fh = vq->priv_data; - struct hrt_buffer *buf = container_of(vb, struct hrt_buffer, vb); - int rc; - - BUG_ON(NULL == fh->fmt); - if (fh->win.width < 48 || fh->win.width > norm_maxw() || - fh->win.height < 32 || fh->win.height > norm_maxh()) - return -EINVAL; - buf->vb.size = fh->win.width*fh->win.height*fh->win.depth; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != fh->fmt || - buf->vb.width != fh->win.width || - buf->vb.height != fh->win.height || - buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->win.width; - buf->vb.height = fh->win.height; - buf->vb.field = field; - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; - - return 0; - -fail: - free_buffer(vq, buf); - return rc; -} + hrt_i2c_start(dev, addr); + /* here we select the A/D Device on the i2c bus + * that should pay attention to the following bytes */ + if (hrt_i2c_send_byte(dev, dev->virt_addr, HRT_AD_DEVICE_ID)) { + HRT_ERROR_MSG("send_byte failed"); + return -1; + } -static void -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct hrt_buffer *buf = container_of(vb,struct hrt_buffer,vb); - struct hrt_fh *fh = vq->priv_data; - struct hrt_dev *dev = fh->dev; - - buf->vb.state = VIDEOBUF_QUEUED; - buf->fields_grabbed = 0; - list_add_tail(&buf->vb.queue, &dev->capture); + /* start at the first register and increment along the way */ + if (hrt_i2c_send_byte(dev, dev->virt_addr, cur_reg = sequence[0])) { + HRT_ERROR_MSG("send_byte failed(2)"); + return -1; + } + + for(i = 0; i < len; i += 2, sequence += 2) { + char reg = sequence[0]; + char data = sequence[1]; + if (reg > HRT_SAA7110_MAXREG) { + HRT_ERROR_MSG("register %02X out of range!", reg); + return -1; + } + if (reg != cur_reg) { + + /* we're going to an entirely different register */ + hrt_i2c_stop(dev, addr); + hrt_i2c_start(dev, addr); + + /* select the chip/device on the bus */ + if (hrt_i2c_send_byte(dev, dev->virt_addr, HRT_AD_DEVICE_ID)) { + HRT_ERROR_MSG("send_byte failed(3)"); + return -1; + } + + /* select the register */ + if (hrt_i2c_send_byte(dev, dev->virt_addr, cur_reg = reg)) { + HRT_ERROR_MSG("send_byte failed(4)"); + return -1; + } + } + + if (hrt_i2c_send_byte(dev, dev->virt_addr, data)) { + HRT_ERROR_MSG("send_byte failed(5)"); + return -1; + } + dev->saa7110_registers[cur_reg++] = data; + } + /* free the i2c bus */ + hrt_i2c_stop(dev, addr); + return 0; } -static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) +/********************************************************************/ +int hrt_i2c_init_device(hrt_t *dev) { - struct hrt_buffer *buf = container_of(vb,struct hrt_buffer,vb); - - free_buffer(vq,buf); + int result = 0; + HRT_DEBUG_MSG(2, "hrt_i2c_init_device entered" + " (virt_addr = %08X, addr = %08X)", + (unsigned) dev->virt_addr, + (unsigned) dev->phys_addr); + + result = hrt_i2c_init_registers(dev, saa7110_default_init_regs); + if (result) { + HRT_ERROR_MSG("hrt_i2c_init_registers failed %d", result); + return result; + } + HRT_DEBUG_MSG(2, "hrt_i2c_init_device returning %d", result); + return result; } -static struct videobuf_queue_ops hrt_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; /******************************************************************** * @@ -1254,159 +1114,204 @@ * GreyScale requires 1 byte per pixel * Color requires 2 bytes per pixel */ -void grab_field(struct hrt_dev *hrtdev, unsigned char *framedata, +void grab_field( hrt_t *hrtdev, unsigned char *framedata, int parity) { - int i,j,k; - /* Length of the line; used here only by the grey scale implementation */ - int linelen; - /* Coordinates of the sub window */ - int win_width, win_height, win_col, win_row; - win_width = hrtdev->win->width; - win_height = hrtdev->win->height; - win_row = hrtdev->win->starty; - win_col = hrtdev->win->startx; - - printk(KERN_ALERT "win_width = %d\n", win_width); - printk(KERN_ALERT "win_height = %d\n", win_height); - printk(KERN_ALERT "win_row = %d\n", win_row); - printk(KERN_ALERT "win_col = %d\n", win_col); - - - if( (hrtdev->mode & HRT_COLOR_MODE) ){ - linelen = hrtdev->win->width; - - /* For the color case we split up work into three cases - * Case 1 : window completely to the left of the 512 pixel boundary - * Case 2 : window crossing the 512 pixel boundary - * Case 3 : window completely to the right of the 512 pixel boundary - * last 128 pixels of the row - */ - - for (i = (!parity) + win_row; i < win_height; i += 2) { - /* Write the address of the required line into the register */ - iowrite16(i, (void*)hrtdev->virt_addr + HRT_Y_LOW_REG); - wmb(); - /* color card - number of bytes required = 2 X win_width */ - memset(hrtdev->localbuf, 0, 2*win_width); - - /* Case 1 */ - if ( (win_col + win_width) < 512){ - printk(KERN_ALERT "IM IN CASE 1\n"); - - /* Get the first win_width MSBs */ - memcpy(hrtdev->localbuf, (void *)hrtdev->virt_addr + win_col, win_width); - /* Get the first win_width LSBs */ - memcpy(hrtdev->localbuf + win_width, - (void *)hrtdev->virt_addr + 512 + win_col, win_width); - - } - - /* Case 2 - * This one gets messy, but this is correct - * and works fine ! - * all this for efficiency ! - * */ - else if ( ((win_col +win_width) >= 512) && (win_col < 512) ){ - //printk(KERN_ALERT "IM IN CASE 2\n"); - /* Get the first (512 - win_col) MSBs */ - memcpy(hrtdev->localbuf, - (void *)hrtdev->virt_addr + win_col ,512 - win_col); - /* Get the last (win_width - 512 + win_col) MSBs */ - memcpy(hrtdev->localbuf+ 512 - win_col, - (void *)hrtdev->virt_addr + 1024, win_width -512 +win_col); - /* Get the first (512 - win_col) LSBs */ - memcpy(hrtdev->localbuf + win_width , - (void *)hrtdev->virt_addr + 512 + win_col, 512 - win_col); - /* Get the last (win_width - 512 + win_col) LSBs */ - memcpy(hrtdev->localbuf + win_width +512 - win_col, - (void *)hrtdev->virt_addr + 1536, - win_width - 512 + win_col); - } - - /* Case 3 */ - else if ( ((win_col +win_width) >= 512) && (win_col >= 512) ){ - printk(KERN_ALERT "IM IN CASE 3\n"); - /* Get the first win_width MSBs */ - memcpy(hrtdev->localbuf, - (void *)hrtdev->virt_addr + win_col + 1024, win_width); - /* Get the first win_width MSBs */ - memcpy(hrtdev->localbuf + win_width, - (void *)hrtdev->virt_addr + 1536 + win_col, win_width); - } - /* At this point for all three cases we have all the bytes - * stored in the form of all MSBs followed by all LSBs - * Now copy into the framedata buffer one MSB followed - * by the corresponding LSB - */ - for (k = 0; k < win_width; k++) { - j = k; - if (!(hrtdev->upside_down) ){ - framedata[(i*2*win_width) + 2*k] = hrtdev->localbuf[j]; - framedata[(i*2*win_width) + 2*k+1] = hrtdev->localbuf[j+win_width]; - } else { - framedata[((win_height-i+win_row-parity)*2*win_width) + 2*k] - = hrtdev->localbuf[j]; - framedata[((win_height-i+win_row-parity)*2*win_width) + 2*k+1] - = hrtdev->localbuf[j+win_width]; - } - } - } - } - else { - /* GRAY MODE */ - linelen = hrtdev->win->width - hrtdev->win->startx; - - printk(KERN_ALERT "\n------> GREY SCALE MODE <-----\n"); - - if (hrtdev->upside_down == 1) { - - for (i = (!parity) + hrtdev->win->starty; i < hrtdev->win->height; i += 2) { - iowrite16(i, (void *)hrtdev->virt_addr + HRT_Y_LOW_REG); - wmb(); - /* Copy into the 'framedata' the desired part of the current line, - * at the correct location inside the buffer - */ - memcpy_fromio(framedata + (hrtdev->win->height - i - parity - hrtdev->win->starty) * linelen, - (void *)hrtdev->virt_addr + hrtdev->win->starty, linelen); - - // memset ( (void *)hrtdev->virt_addr + hrtdev->win->starty ,0, linelen); - } - } - else { - for (i = (!parity) + hrtdev->win->starty; i < hrtdev->win->height; i += 2) { - iowrite16(i, (void *)hrtdev->virt_addr + HRT_Y_LOW_REG); - wmb(); - /* Copy into the 'framedata' the desired part of the current line, - * at the correct location inside the buffer - */ - memcpy_fromio(framedata + (i * linelen), - (void *)hrtdev->virt_addr + hrtdev->win->starty, linelen); - - // memset ( (void *)hrtdev->virt_addr + hrtdev->win->starty,0, linelen); - } - } - } + int i,j,k; + /* Length of the line; used here only by the grey scale implementation */ + int linelen; + /* Coordinates of the sub window */ + int win_width, win_height, win_col, win_row; + win_width = hrtdev->win->width; + win_height = hrtdev->win->height; + win_row = hrtdev->win->starty; + win_col = hrtdev->win->startx; + printk(KERN_ALERT "win_width = %d\n", win_width); + printk(KERN_ALERT "win_height = %d\n", win_height); + printk(KERN_ALERT "win_row = %d\n", win_row); + printk(KERN_ALERT "win_col = %d\n", win_col); + + + if( (hrtdev->mode & HRT_COLOR_MODE) ){ + printk(KERN_ALERT "win_width = %d\n", win_width); + printk(KERN_ALERT "win_height = %d\n", win_height); + printk(KERN_ALERT "win_row = %d\n", win_row); + printk(KERN_ALERT "win_col = %d\n", win_col); + linelen = hrtdev->win->width; + /* For the color case we split up work into three cases + * Case 1 : window completely to the left of the 512 pixel boundary + * Case 2 : window crossing the 512 pixel boundary + * Case 3 : window completely to the right of the 512 pixel boundary + last 128 pixels of the row + */ + + + + for (i = (!parity) + win_row; i < win_height; i += 2) { + /* Write the address of the required line into the register */ + iowrite16(i, (void*)hrtdev->virt_addr + HRT_Y_LOW_REG); + wmb(); + /* color card - number of bytes required = 2 X win_width */ + memset(hrtdev->localbuf, 0, 2*win_width); + + /* Case 1 */ + if ( (win_col + win_width) < 512){ + printk(KERN_ALERT "IM IN CASE 1\n"); + /* Get the first win_width MSBs */ + memcpy(hrtdev->localbuf, (void *)hrtdev->virt_addr + win_col, win_width); + /* Get the first win_width LSBs */ + memcpy(hrtdev->localbuf + win_width, (void *)hrtdev->virt_addr + 512 + win_col, win_width); + } + + /* Case 2 + * This one gets messy, but this is correct + * and works fine ! + * all this for efficiency ! + * */ + else if ( ((win_col +win_width) >= 512) && (win_col < 512) ){ + //printk(KERN_ALERT "IM IN CASE 2\n"); + /* Get the first (512 - win_col) MSBs */ + memcpy(hrtdev->localbuf, (void *)hrtdev->virt_addr + win_col , + 512 - win_col); + /* Get the last (win_width - 512 + win_col) MSBs */ + memcpy(hrtdev->localbuf+ 512 - win_col, (void *)hrtdev->virt_addr + 1024, + win_width -512 +win_col); + /* Get the first (512 - win_col) LSBs */ + memcpy(hrtdev->localbuf + win_width , (void *)hrtdev->virt_addr + 512 + win_col, + 512 - win_col); + /* Get the last (win_width - 512 + win_col) LSBs */ + memcpy(hrtdev->localbuf + win_width +512 - win_col, (void *)hrtdev->virt_addr + 1536, + win_width - 512 + win_col); + } + + /* Case 3 */ + else if ( ((win_col +win_width) >= 512) && (win_col >= 512) ){ + + printk(KERN_ALERT "IM IN CASE 3\n"); + /* Get the first win_width MSBs */ + memcpy(hrtdev->localbuf, (void *)hrtdev->virt_addr + win_col + 1024, win_width); + /* Get the first win_width MSBs */ + memcpy(hrtdev->localbuf + win_width, (void *)hrtdev->virt_addr + 1536 + win_col, win_width); + } + /* At this point for all three cases we have all the bytes + * stored in the form of all MSBs followed by all LSBs + * Now copy into the framedata buffer one MSB followed + * by the corresponding LSB + * + * However the destination for the copy is differant for the case of streaming I/O + * as compared to the regular reads. + * For streaming, we want to copy into the buffer that was passed as a parameter to + * this function + * But for the read operation we need to copy into the device's frame sized buffer 'framedata' + * + * Neat !!! + * + */ + if (!hrtdev->streaming) { + /* This is for the blocking read based display */ + for (k = 0; k < win_width; k++) { + j = k; + if ( !(hrtdev->upside_down) ){ + hrtdev->framedata[(i*2*win_width) + 2*k] = hrtdev->localbuf[j]; + hrtdev->framedata[(i*2*win_width) + 2*k+1] = hrtdev->localbuf[j+win_width]; + } + else { + /* If the user wishes to see the image upside down then this code + * makes that happen. In our case we as user wanted to have that functionality + * since our camera was mounted upside down. So implemented this feature !! + */ + hrtdev->framedata[((win_height-i+win_row-parity)*2*win_width) + 2*k] = hrtdev->localbuf[j]; + hrtdev->framedata[((win_height-i+win_row-parity)*2*win_width) + 2*k+1] = hrtdev->localbuf[j+win_width]; + } + } + } + else { + /* This is for the streaming I/O */ + for (k = 0; k < win_width; k++) { + j = k; + if ( !(hrtdev->upside_down) ){ + framedata[(i*2*win_width) + 2*k] = hrtdev->localbuf[j]; + framedata[(i*2*win_width) + 2*k+1] = hrtdev->localbuf[j+win_width]; + } + else { + /* If the user wishes to see the image upside down then this code + * makes that happen. In our case we as user wanted to have that functionality + * since our camera was mounted upside down. So implemented this feature !! + */ + framedata[((win_height-i+win_row-parity)*2*win_width) + 2*k] = hrtdev->localbuf[j]; + framedata[((win_height-i+win_row-parity)*2*win_width) + 2*k+1] = hrtdev->localbuf[j+win_width]; + } + } + } + } + } + + + + + + else { /* Out of the color mode. This one is for gray scale */ + /* Following takes care of the sub window coordinates */ + linelen = hrtdev->win->width - hrtdev->win->startx; + /* Since this is just a single field that we are writing into the buffer + * we write each line of this field into an alternate line of the buffer. + * Interleaving. + */ + + printk(KERN_ALERT "\nDAN---------------> I AM GREY SCALE MODE <-----------------\n"); + if (hrtdev->upside_down == 1) { + + for (i = (!parity) + hrtdev->win->starty; i < hrtdev->win->height; i += 2) { + iowrite16(i, (void *)hrtdev->virt_addr + HRT_Y_LOW_REG); + wmb(); + /* Copy into the 'framedata' the desired part of the current line, + * at the correct location inside the buffer + */ + memcpy_fromio(framedata + (hrtdev->win->height - i - parity - hrtdev->win->starty) * linelen, + (void *)hrtdev->virt_addr + hrtdev->win->starty, + linelen); + memset ( (void *)hrtdev->virt_addr + hrtdev->win->starty ,0, linelen); + + + } + } + else { + for (i = (!parity) + hrtdev->win->starty; i < hrtdev->win->height; i += 2) { + iowrite16(i, (void *)hrtdev->virt_addr + HRT_Y_LOW_REG); + wmb(); + /* Copy into the 'framedata' the desired part of the current line, + * at the correct location inside the buffer + */ + memcpy_fromio(framedata + (i * linelen), + (void *)hrtdev->virt_addr + hrtdev->win->starty, + linelen); + + memset ( (void *)hrtdev->virt_addr + hrtdev->win->starty,0, linelen); + } + } + + } + } /********************************************************************/ static inline -void hrt_irq_enable(struct hrt_dev *dev) +void hrt_irq_enable(hrt_t *dev) { - int val; - val = ioread8((void *)(dev->virt_addr + HRT_IRQ_ENABLE)); - val |= 0x1; - iowrite8(val, (void *) (dev->virt_addr + HRT_IRQ_ENABLE)); + int val; + val = ioread8((void *)(dev->virt_addr + HRT_IRQ_ENABLE)); + val |= 0x1; + iowrite8(val, (void *) (dev->virt_addr + HRT_IRQ_ENABLE)); } /********************************************************************/ static inline -void hrt_irq_disable(struct hrt_dev *dev) +void hrt_irq_disable(hrt_t *dev) { - int val; - val = ioread8((void *)(dev->virt_addr + HRT_IRQ_ENABLE)); - val &= ~0x1; - iowrite8(val, (void *) (dev->virt_addr + HRT_IRQ_ENABLE)); + int val; + val = ioread8((void *)(dev->virt_addr + HRT_IRQ_ENABLE)); + val &= ~0x1; + iowrite8(val, (void *) (dev->virt_addr + HRT_IRQ_ENABLE)); } /******************************************************************** @@ -1414,10 +1319,10 @@ */ void hrt_tasklet(unsigned long); -void hrt_timer_init(struct hrt_dev* dev); -void hrt_timer_cleanup(struct hrt_dev* dev); -int hrt_timer_activate(struct hrt_dev* dev); -void hrt_timer_deactivate(struct hrt_dev* dev); +void hrt_timer_init(hrt_t* dev); +void hrt_timer_cleanup(hrt_t* dev); +int hrt_timer_activate(hrt_t* dev); +void hrt_timer_deactivate(hrt_t* dev); /******************************************************************** @@ -1426,88 +1331,126 @@ * Cleanup the device - called from the module cleanup routine */ -void hrt_cleanup(struct hrt_dev* dev) +void hrt_cleanup(hrt_t* dev) { - HRT_DEBUG_MSG(1, "shutting down hrt device %d at 0x%lx", - dev->num, dev->phys_addr); - - HRT_MODULE_CHECK (HRT_MODULE_FINALIZING_STATE | - HRT_MODULE_INITIALIZING_STATE, "1"); - - HRT_CHECK (dev, HRT_INITIALIZING_STATE - | HRT_CLOSED_STATE | HRT_FINALIZING_STATE, "2"); - - dev->state = HRT_FINALIZING_STATE; - - /* restore device to an inactive state */ - hrt_freeze_next(dev); - - /* deactivate and remove interrupt handler or timer */ - hrt_timer_cleanup (dev); - - if (dev->phys_addr) { - HRT_DEBUG_MSG(2, "release_mem_region 0x%lx, 0x%lx", - (unsigned long)dev, (unsigned long) dev->phys_addr); - - release_mem_region(dev->phys_addr, HRT_IO_SIZE); - - dev->phys_addr = 0; - - } - if (dev->virt_addr) { - HRT_DEBUG_MSG(2, "iounmap %lx", (unsigned long) dev->virt_addr); - - iounmap((void *)dev->virt_addr); /* problem might be here dan */ - - dev->virt_addr = 0; - } - + HRT_DEBUG_MSG(1, "shutting down hrt device %d at 0x%lx", + dev->num, dev->phys_addr); + HRT_MODULE_CHECK (HRT_MODULE_FINALIZING_STATE | + HRT_MODULE_INITIALIZING_STATE, "1"); + HRT_CHECK (dev, HRT_INITIALIZING_STATE + | HRT_CLOSED_STATE | HRT_FINALIZING_STATE, "2"); + dev->state = HRT_FINALIZING_STATE; + + /* restore device to an inactive state */ + hrt_freeze_next(dev); + + /* deactivate and remove interrupt handler or timer */ + hrt_timer_cleanup (dev); + + if (dev->phys_addr) { + HRT_DEBUG_MSG(2, "release_mem_region 0x%lx, 0x%lx", + (unsigned long)dev, (unsigned long) dev->phys_addr); + release_mem_region(dev->phys_addr, HRT_IO_SIZE); + dev->phys_addr = 0; + } + if (dev->virt_addr) { + HRT_DEBUG_MSG(2, "iounmap %lx", (unsigned long) dev->virt_addr); + printk (KERN_ALERT "DAN ---> unmapping virtual memory for device \n"); + iounmap((void *)dev->virt_addr); /* problem might be here dan */ + dev->virt_addr = 0; + } + + /* possible problem2 dan */ #ifdef CONFIG_PCI - if (dev->pci_dev) { - - pci_disable_device(dev->pci_dev); - - dev->pci_dev = NULL; - } + printk(KERN_ALERT "DAN --- > DISABLING THE PCI DEVICE\n"); + + if (dev->pci_dev) { + printk(KERN_ALERT "DAN --- > INSIDE THE IF --> DISABLING THE PCI DEVICE\n"); + pci_disable_device(dev->pci_dev); + dev->pci_dev = NULL; + } #endif - if (dev->registered == 1) { - - video_unregister_device(dev->video_dev); - - video_device_release(dev->video_dev); - - /* set the per-device state variable to indicate we are not registered any more */ - dev->registered =0; - } -#if 0 - /* De-allocate frame buffer */ - if (dev->framedata) { - - vfree(dev->framedata); - - dev->framedata = NULL; - } -#endif - /* Deallocate the smaller local buffer */ - if (dev->localbuf) { - - kfree(dev->localbuf); - - dev->localbuf = NULL; - } - - /* Set the device state to uninitialised - * now that it is all cleaned up - */ - dev->state = HRT_UNINITIALIZED_STATE; - if((dev->hrt_devlist.prev!=NULL) && (dev->hrt_devlist.next!=NULL)) { - printk("del device %d\n",dev->num); - list_del(&dev->hrt_devlist); - } - - kfree(dev); - dev = NULL; + if (dev->registered == 1) + { + printk(KERN_ALERT "TRYING TO KILL ISA DEVICE \n"); + video_unregister_device(&dev->video_dev); + /* set the per-device state variable to indicate we are not registered any more */ + dev->registered =0; + } + + /* De-allocate frame buffer */ + if (dev->framedata) { + vfree(dev->framedata); + dev->framedata = NULL; + } + /* Deallocate the smaller local buffer */ + if (dev->localbuf) { + kfree(dev->localbuf); + dev->localbuf = NULL; + } + + /* Set the device state to uninitialised + * now that it is all cleaned up + */ + dev->state = HRT_UNINITIALIZED_STATE; + +} + +/******************************************************************** + * hrt_lock_init + * + * Initialises the spin lock used in the module + */ +void hrt_lock_init(hrt_t * dev) { + spin_lock_init(&dev->spinlock); + dev->is_locked = 0; +} + +/******************************************************************** + * hrt_trylock + * + * Does nothing. Just checks the spinlock. + */ +int hrt_trylock(hrt_t * dev) { + spin_lock(&dev->spinlock); + if (dev->is_locked) { + spin_unlock(&dev->spinlock); + return 1; + } + dev->is_locked = 1; + spin_unlock(&dev->spinlock); + return 0; +} + +/******************************************************************** + * hrt_lock + * + * lock the device + */ +void hrt_lock(hrt_t * dev) { + unsigned long flags; + spin_lock_irqsave(&dev->spinlock, flags); + if (dev->is_locked) { + HRT_ERROR_MSG("locking an already-locked device"); + } + dev->is_locked = 1; + spin_unlock_irqrestore(&dev->spinlock, flags); +} + +/******************************************************************** + * hrt_unlock + * + * Unlock the device + */ +void hrt_unlock(hrt_t * dev) { + spin_lock(&dev->spinlock); + if (!dev->is_locked) { + HRT_ERROR_MSG("unlocking unlocked device"); + } + dev->is_locked = 0; + spin_unlock(&dev->spinlock); } + /******************************************************************** * hrt_init * @@ -1516,400 +1459,421 @@ */ int hrt_init(unsigned long phys_address, struct pci_dev * pci_dev) { - struct hrt_dev * dev; - struct video_device *vfd; - int ret, i, result; - char *bus, *color, *ported; - unsigned int old_control, old_y_high, old_y_low; - unsigned char val1, val2; - unsigned long virt_address; - - HRT_DEBUG_MSG(1, "probing device at 0x%lx", phys_address); - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (NULL == dev) - return -ENODEV; - - /* put the device in the unregistered state */ - dev->registered = 0; - - dev->state = HRT_INITIALIZING_STATE; - dev->num = hrt_num_devices; - dev->users = 0; - - spin_lock_init(&dev->spinlock); - - tasklet_init(&dev->tasklet, hrt_tasklet, (unsigned long) dev); - - dev->tasklet_active = 1; - - /* reserve the I/O address space for this device */ - if (!request_mem_region(phys_address, HRT_IO_SIZE, "hrt")) { - HRT_ERROR_MSG("I/O memory at %lx already in use", - (unsigned long) phys_address); - kfree(dev); - dev = NULL; - return -EBUSY; - } - - dev->phys_addr = phys_address; - - /* map the device's I/O space into kernel memory */ - virt_address = (unsigned long)ioremap_nocache(phys_address, HRT_IO_SIZE); - - if (!virt_address) { - HRT_ERROR_MSG("couldn't remap io memory!!"); - hrt_cleanup(dev); - return -ENODEV; - } - - dev->virt_addr = virt_address; - + hrt_t * dev = &hrt_devices[hrt_num_devices]; + int i, result; + char *bus, *color, *ported; + unsigned int old_control, old_y_high, old_y_low; + unsigned char val1, val2; + unsigned long virt_address; + + HRT_DEBUG_MSG(1, "probing device at 0x%lx", phys_address); + + memset(dev, 0, sizeof(hrt_t)); + + dev = &hrt_devices[hrt_num_devices]; + + /* put the device in the unregistered state */ + dev->registered = 0; + + printk(KERN_ALERT "RYAN: $$$$$ DEV->MODE = %d\n", dev->mode); + dev->state = HRT_INITIALIZING_STATE; + dev->num = hrt_num_devices; + hrt_lock_init (dev); + + tasklet_init(&dev->tasklet, hrt_tasklet, (unsigned long) dev); + dev->tasklet_active = 1; + + /* reserve the I/O address space for this device */ + if (!request_mem_region(phys_address, HRT_IO_SIZE, "hrt")) { + HRT_ERROR_MSG("I/O memory at %lx already in use", + (unsigned long) phys_address); + // hrt_cleanup(dev); + return -EBUSY; + } + dev->phys_addr = phys_address; + + /* map the device's I/O space into kernel memory */ + virt_address = (unsigned long) + ioremap_nocache(phys_address, HRT_IO_SIZE); + if (!virt_address) { + HRT_ERROR_MSG("couldn't remap io memory!!"); + hrt_cleanup(dev); + return -ENODEV; + } + dev->virt_addr = virt_address; + #ifdef CONFIG_PCI - /* pci-specific processing */ - if (pci_dev) { - pci_set_drvdata (pci_dev, dev); - dev->pci_dev = pci_dev; - dev->irq = -pci_dev->irq; - - dev->mode &= ~HRT_ISA_MODE; - /* make certain IRQ is disabled before enabling - device, or else we may get an IRQ we are not - prepared to handle? */ - hrt_irq_disable(dev); - - if (pci_enable_device(pci_dev)) { - HRT_ERROR_MSG("pci_enable_device failed"); - - hrt_cleanup(dev); - - return -EIO; - } - } + /* pci-specific processing */ + if (pci_dev) { + pci_set_drvdata (pci_dev, dev); + dev->pci_dev = pci_dev; + dev->irq = -pci_dev->irq; + + printk(KERN_ALERT "RYAN: @@@@@ MODE = %d\n", dev->mode); + dev->mode &= ~HRT_ISA_MODE; + printk(KERN_ALERT "RYAN: @@@@@ ISA_MODE = %d\n", HRT_ISA_MODE); + printk(KERN_ALERT "RYAN: @@@@@ MODE &= ~HRT_ISA_MODE = %d\n", dev->mode); + /* make certain IRQ is disabled before enabling + device, or else we may get an IRQ we are not + prepared to handle? */ + hrt_irq_disable(dev); + if (pci_enable_device(pci_dev)) { + HRT_ERROR_MSG("pci_enable_device failed"); + hrt_cleanup(dev); + return -EIO; + } + } #endif - /* find out whether there is an hrt device at this - address, and which type of device it is */ - - /* save the values we are about to modify */ - old_control = ioread8((void *)(HRT_CONTROL_REG + virt_address)); - old_y_low = ioread8((void *)(HRT_Y_LOW_REG + virt_address)); - old_y_high = ioread8((void *)(HRT_Y_HIGH_REG + virt_address)); - - /* freeze the frame grabbing, immediately */ - iowrite8(0x5B, (void *) (HRT_CONTROL_REG + virt_address)); - - /* complement pixel (0,0) */ - iowrite16(0, (void *) (HRT_Y_LOW_REG + virt_address)); - iowrite16(0, (void *) (HRT_Y_HIGH_REG + virt_address)); - val1 = ioread8((void *) virt_address); - iowrite8(~val1, (void *) virt_address); - - /* write old value of pixel (0,0) to (1,0) */ - iowrite16(1, (void *) (HRT_Y_LOW_REG + virt_address)); - iowrite8(val1, (void *) virt_address); - - /* read the value at the previous raster/row */ - iowrite16(0, (void *) (HRT_Y_LOW_REG + virt_address)); - val2 = ioread8((void *) virt_address); - - if (val2 != (unsigned char)~val1) { - HRT_DEBUG_MSG(1, "no hrt device at address 0x%lx", - virt_address); - /* restore the old values, and hope we did no - damage to some other device at this address; - this is pretty poor, since if there is - another device at that address the effects - of these writes could be harmful; - ideally, there should be a way to - identify the devices that only uses read - operations */ - iowrite8(val1, (void *) virt_address); - iowrite8(old_y_low, (void *) (HRT_Y_LOW_REG + virt_address)); - iowrite8(old_y_high, (void *) (HRT_Y_HIGH_REG + virt_address)); - iowrite8(old_control, (void *) (HRT_CONTROL_REG + virt_address)); - - hrt_cleanup(dev); - - return -ENODEV; - } - - /* test whether we have a color or greyscale card: - the color frame buffer has line of 2048 = 0x400 - pixels; greyscale has only 512 pixels/line, so - the memory mapped row of frame buffer memory - should wrap around at 0x200 and 0x400 on a greyscale card - but should be good through 0x400 on a color card. */ - - iowrite8(HRT_FREEZE_IMM_CMD, (void *) (HRT_CONTROL_REG + virt_address)); - iowrite16(0, (void *) (HRT_Y_LOW_REG + virt_address)); - iowrite16(0, (void *) (HRT_Y_HIGH_REG + virt_address)); - val1 = ioread8((void *)(0x400 + virt_address)); - iowrite8(~val1, (void *) (0x400 + virt_address)); - /* in case greyscale addresses wrap around, - refresh the value at offset zero */ - iowrite8(val1, (void *) (virt_address)); - val2 = ioread8((void *)(0x400 + virt_address)); - if (val2 == (unsigned char) ~val1) { - dev->mode |= HRT_COLOR_MODE; - /* infer the frame geometry from the device type */ - HRT_DEBUG_MSG(1, "COLOR device detected"); - dev->cols = 640; - dev->rows = 480; - dev->bytes_per_pixel = 2; - } else { - HRT_DEBUG_MSG(1, "GREYSCALE device detected"); - dev->cols = 512; /* is for NTSC, 512 for PAL */ - dev->rows = 480; - dev->bytes_per_pixel = 1; - } - - /* try to initialize the device */ - result = hrt_i2c_init_device(dev); - if (result) { - HRT_ERROR_MSG("hrt_i2c_init_device %d failed",result); - hrt_cleanup(dev); - return -ENODEV; - } - - hrt_go_live(dev); /* delete this once driver is debugged */ - - /* find out whether the device has dual-ported memory*/ - while (ioread8((void *)(dev->virt_addr + HRT_CONTROL_REG)) & 0x40) { - printk( "waiting on dual port check\n"); - schedule(); - } + /* find out whether there is an hrt device at this + address, and which type of device it is */ - /* try to overwrite the line with ones */ - for (i = 0; i < 512; i++) { - iowrite8(255, (void *) (dev->virt_addr + i)); - } - - /* freeze the image */ - hrt_freeze_immediate(dev); - - /* write zeros to horizontal raster line 500, - a line that the A/D unit does not modify */ - iowrite16(0, (void *) (dev->virt_addr + HRT_Y_HIGH_REG)); - iowrite16(500, (void *) (dev->virt_addr + HRT_Y_LOW_REG)); - for (i = 0; i < 512; i++) { - iowrite8(0, (void *)(dev->virt_addr + i)); - } - - /* set capturing mode */ - hrt_go_live(dev); - - /* try to overwrite the line with ones */ - for (i = 0; i < 512; i++) { - iowrite8(255, (void *) (dev->virt_addr + i)); - } - - /* freeze the image */ - hrt_freeze_immediate(dev); - - /* read back the line; - if some of the pixels are still zero the memory is - not dual ported */ - result = 1; - for (i = 0; i < 512; i++) { - if (!ioread8((void *)(dev->virt_addr + i))) result = 0; - } - if (result) { - HRT_DEBUG_MSG(1, "seems to be dual ported"); - dev->mode |= HRT_DUAL_PORTED_MODE; - } + /* save the values we are about to modify */ + old_control = ioread8((void *)(HRT_CONTROL_REG + virt_address)); + old_y_low = ioread8((void *)(HRT_Y_LOW_REG + virt_address)); + old_y_high = ioread8((void *)(HRT_Y_HIGH_REG + virt_address)); + + /* freeze the frame grabbing, immediately */ + iowrite8(0x5B, (void *) (HRT_CONTROL_REG + virt_address)); + + /* complement pixel (0,0) */ + iowrite16(0, (void *) (HRT_Y_LOW_REG + virt_address)); + iowrite16(0, (void *) (HRT_Y_HIGH_REG + virt_address)); + val1 = ioread8((void *) virt_address); + iowrite8(~val1, (void *) virt_address); + + /* write old value of pixel (0,0) to (1,0) */ + iowrite16(1, (void *) (HRT_Y_LOW_REG + virt_address)); + iowrite8(val1, (void *) virt_address); + + /* read the value at the previous raster/row */ + iowrite16(0, (void *) (HRT_Y_LOW_REG + virt_address)); + val2 = ioread8((void *) virt_address); + + if (val2 != (unsigned char)~val1) { + HRT_DEBUG_MSG(1, "no hrt device at address 0x%lx", + virt_address); + /* restore the old values, and hope we did no + damage to some other device at this address; + this is pretty poor, since if there is + another device at that address the effects + of these writes could be harmful; + ideally, there should be a way to + identify the devices that only uses read + operations */ + iowrite8(val1, (void *) virt_address); + iowrite8(old_y_low, (void *) (HRT_Y_LOW_REG + virt_address)); + iowrite8(old_y_high, (void *) (HRT_Y_HIGH_REG + virt_address)); + iowrite8(old_control, (void *) (HRT_CONTROL_REG + virt_address)); + + hrt_cleanup(dev); + return -ENODEV; + } + + /* test whether we have a color or greyscale card: + the color frame buffer has line of 2048 = 0x400 + pixels; greyscale has only 512 pixels/line, so + the memory mapped row of frame buffer memory + should wrap around at 0x200 and 0x400 on a greyscale card + but should be good through 0x400 on a color card. */ + + iowrite8(HRT_FREEZE_IMM_CMD, (void *) (HRT_CONTROL_REG + virt_address)); + iowrite16(0, (void *) (HRT_Y_LOW_REG + virt_address)); + iowrite16(0, (void *) (HRT_Y_HIGH_REG + virt_address)); + val1 = ioread8((void *)(0x400 + virt_address)); + printk(KERN_ALERT "RYAN: #### VAL1 = %d \n", val1); + iowrite8(~val1, (void *) (0x400 + virt_address)); + /* in case greyscale addresses wrap around, + refresh the value at offset zero */ + iowrite8(val1, (void *) (virt_address)); + val2 = ioread8((void *)(0x400 + virt_address)); + printk(KERN_ALERT "RYAN: #### VAL2 = %d \n", val2); + if (val2 == (unsigned char) ~val1) { + printk(KERN_ALERT "RYAN: ------I AM IN VAL2---- \n"); + printk(KERN_ALERT "RYAN: #### DEV->MODE = %d \n", dev->mode); + printk(KERN_ALERT "RYAN: #### HRT_COLOR_MODE = %d\n", HRT_COLOR_MODE); + dev->mode |= HRT_COLOR_MODE; +printk(KERN_ALERT "RYAN: #### DEV->MODE |=HRT_COLOR_MODE = %d \n", dev->mode); + /* infer the frame geometry from the device type */ + HRT_DEBUG_MSG(1, "COLOR device detected"); + dev->rows = 399; + dev->cols = 512; + dev->bytes_per_pixel = 2; + } else { + HRT_DEBUG_MSG(1, "GREYSCALE device detected"); + dev->cols = 512; /* is for NTSC, 512 for PAL */ + dev->rows = 480; + dev->bytes_per_pixel = 1; + } + + /* try to initialize the device */ + result = hrt_i2c_init_device(dev); + if (result) { + HRT_ERROR_MSG("hrt_i2c_init_device %d failed",result); + hrt_cleanup(dev); + return -ENODEV; + } + + hrt_go_live(dev); /* delete this once driver is debugged */ + + /* find out whether the device has dual-ported memory*/ + while (ioread8((void *)(dev->virt_addr + HRT_CONTROL_REG)) & 0x40) { + hrt_printk( "waiting on dual port check\n"); + schedule(); + } + + /* try to overwrite the line with ones */ + for (i = 0; i < 512; i++) { + iowrite8(255, (void *) (dev->virt_addr + i)); + } + + /* freeze the image */ + hrt_freeze_immediate(dev); + + /* write zeros to horizontal raster line 500, + a line that the A/D unit does not modify */ + iowrite16(0, (void *) (dev->virt_addr + HRT_Y_HIGH_REG)); + iowrite16(500, (void *) (dev->virt_addr + HRT_Y_LOW_REG)); + for (i = 0; i < 512; i++) { + iowrite8(0, (void *)(dev->virt_addr + i)); + } + + /* set capturing mode */ + hrt_go_live(dev); + + /* try to overwrite the line with ones */ + for (i = 0; i < 512; i++) { + iowrite8(255, (void *) (dev->virt_addr + i)); + } + + /* freeze the image */ + hrt_freeze_immediate(dev); + + /* read back the line; + if some of the pixels are still zero the memory is + not dual ported */ + result = 1; + for (i = 0; i < 512; i++) { + if (!ioread8((void *)(dev->virt_addr + i))) result = 0; + } + if (result) { + HRT_DEBUG_MSG(1, "seems to be dual ported"); + dev->mode |= HRT_DUAL_PORTED_MODE; + } + printk(KERN_ALERT "Dan after dual ported message \n"); + //printk(KERN_ALERT "RYAN: !!!! Dev->mode = %d\n",dev->mode); + //printk(KERN_ALERT "RYAN: !!!! HRT_ISA_MODE = %d\n",HRT_ISA_MODE); - if(testing_isa_mode == 1){ - dev->mode |= HRT_ISA_MODE; - } - - if(testing_isa_mode != 1){ - - printk(KERN_ALERT "I AM CONFIG PCI\n"); - - if ((pci_dev->device == HRT_DEVICE_ID_COLOR) != - ((dev->mode & HRT_COLOR_MODE) == HRT_COLOR_MODE)) { - - HRT_ERROR_MSG("PCI and probed types don't match"); - - hrt_cleanup(dev); - - return -ENODEV; - } - } - - /* discover whether this device supports interrupts */ - hrt_timer_init(dev); - - if (dev->mode & HRT_IRQ_MODE) { - /* BASIC IDEA - * Enable the device for 20 ms - * and count the number of interrupts generated - * a non zero value means that this device supports - * IRQs - */ - dev->irq_count = 0; - - hrt_irq_enable(dev); - - hrt_go_live(dev); - - mdelay(20); - - hrt_freeze_immediate(dev); - - hrt_irq_disable(dev); - - if (dev->irq_count) { - HRT_DEBUG_MSG(1, "counted %d irqs in 20 ms", - dev->irq_count); - HRT_ERROR_MSG("devices supports IRQs"); - } else { - HRT_DEBUG_MSG(1, "no irqs in 20 ms"); - if(dev->irq > 0) - free_irq(dev->irq, dev); - dev->irq = 0; - dev->mode &= ~HRT_IRQ_MODE; - hrt_timer_init(dev); - } - } + if(testing_isa_mode == 1){ + dev->mode |= HRT_ISA_MODE; + } + //printk(KERN_ALERT "RYAN: !!!! Dev->mode |=ISA_MODE = %d\n",dev->mode); + //printk(KERN_ALERT "Dan after dev->mode or \n"); - /* describe this device for the log */ - if (dev->mode & HRT_ISA_MODE) bus = "ISA"; - else bus = "PCI"; - - if (dev->mode & HRT_COLOR_MODE) color = "COLOR"; - else color = "GREYSCALE"; - - if (dev->mode & HRT_DUAL_PORTED_MODE) ported = "DUAL"; - else ported = "SINGLE"; - - HRT_ERROR_MSG("found device %d at 0x%lx", - dev->num, dev->phys_addr); - HRT_ERROR_MSG("%s %s with %s-ported memory", - bus, color, ported); - if (dev->mode & HRT_IRQ_MODE) - HRT_ERROR_MSG("using IRQ %d", dev->irq); - - init_waitqueue_head(&dev->wait_queue); - - /* Read the field bit and assign to the field_id variable */ - dev->field_id = ioread8((void *)dev->virt_addr + HRT_CONTROL_REG) & 1; - - /* Initialize the semaphore */ - mutex_init(&dev->lock); - - /* set default window size - to cover the entire frame buffer */ - HRT_DEBUG_MSG(1, "setting width, cols = %d", dev->cols); - - dev->win_row = 0; - dev->win_width = dev->cols; - dev->win_col = 0; - dev->win_height = dev->rows; - dev->field = -1; - dev->state = HRT_CLOSED_STATE; - - - /* Make the lists used for streaming empty */ - INIT_LIST_HEAD(&dev->capture); - - /* Register with V4L */ - vfd = video_device_alloc(); - if (NULL == vfd) { - hrt_cleanup(dev); - return -ENODEV; - } - - *vfd = hrt_template; - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); - if (ret < 0) { - printk(KERN_ERR "Unable to register video device\n"); - /* Failure in the device registration - * Cleanup before exiting - */ - hrt_cleanup(dev); - return -ENODEV; - } - - snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", - hrt_template.name, vfd->minor); - - if (video_nr >= 0) - video_nr++; - - dev->video_dev = vfd; - /* set the device status to registered */ - dev->registered = 1; - - /* Set private data (to access through struct file) */ - dev->video_dev->priv = dev; - - /* Set the constants depending on - * whether the device supports color - * or grey scale - */ - - if(dev->mode & HRT_COLOR_MODE){ - dev->bytesperline = HRT_COLOR_BYTES_PER_LINE; - dev->framesize = HRT_COLOR_FRAMESIZE; - } - else{ - dev->bytesperline = HRT_GRAY_BYTES_PER_LINE; - dev->framesize = HRT_GRAY_FRAMESIZE; - } - - /* Allocate the frame buffer */ - if (dev->mode & HRT_COLOR_MODE) { - dev->localbuf = (unsigned char *) kmalloc(sizeof(char) * 1664, GFP_KERNEL); - - if (dev->localbuf == NULL) { - printk(KERN_ERR "Unable to allocate memory\n"); - hrt_cleanup(dev); - return -ENOMEM; - } - } - else { - dev->localbuf = NULL; - } - - dev->streaming_state = 0; - dev->upside_down = 0; - - /* Read the field bit and assign to the field_id */ - dev->field_id = hrt_get_field(dev); - list_add_tail(&dev->hrt_devlist, &hrt_devlist); - hrt_devices[hrt_num_devices] = dev; - hrt_num_devices++; - - /* Make the device go-live */ - hrt_go_live(dev); - - return 0; + + if(testing_isa_mode != 1){ + printk(KERN_ALERT "I AM CONFIG PCI\n"); + + if ((pci_dev->device == HRT_DEVICE_ID_COLOR) != + ((dev->mode & HRT_COLOR_MODE) == HRT_COLOR_MODE)) + HRT_ERROR_MSG("PCI and probed types don't match"); + } + + printk(KERN_ALERT "Dan before to dicover interrupts device\n"); + + /* discover whether this device supports interrupts */ + hrt_timer_init(dev); + printk(KERN_ALERT "Dan after hrt_timer_init device\n"); + + if (dev->mode & HRT_IRQ_MODE) { + printk(KERN_ALERT "Dan Trying to discover interrupts\n"); + /* BASIC IDEA + * Enable the device for 20 ms + * and count the number of interrupts generated + * a non zero value means that this device supports + * IRQs + */ + dev->irq_count = 0; + printk(KERN_ALERT "Dan before to enable device\n"); + hrt_irq_enable(dev); + printk(KERN_ALERT "Dan after to enable device\n"); + printk(KERN_ALERT "Dan Trying to go live\n"); + + hrt_go_live(dev); + printk(KERN_ALERT "Dan after to go live\n"); + + mdelay(20); + printk(KERN_ALERT "Dan Trying to freeze device\n"); + + hrt_freeze_immediate(dev); + printk(KERN_ALERT "Dan After to enable device\n"); + + hrt_irq_disable(dev); + if (dev->irq_count) { + HRT_DEBUG_MSG(1, "counted %d irqs in 20 ms", + dev->irq_count); + HRT_ERROR_MSG("devices supports IRQs"); + } else { + HRT_DEBUG_MSG(1, "no irqs in 20 ms"); + dev->irq = 0; + dev->mode &= ~HRT_IRQ_MODE; + } + } + + /* describe this device for the log */ + if (dev->mode & HRT_ISA_MODE) bus = "ISA"; + else bus = "PCI"; + if (dev->mode & HRT_COLOR_MODE) color = "COLOR"; + else color = "GREYSCALE"; + if (dev->mode & HRT_DUAL_PORTED_MODE) ported = "DUAL"; + else ported = "SINGLE"; + HRT_ERROR_MSG("found device %d at 0x%lx", + dev->num, dev->phys_addr); + HRT_ERROR_MSG("%s %s with %s-ported memory", + bus, color, ported); + if (dev->mode & HRT_IRQ_MODE) + HRT_ERROR_MSG("using IRQ %d", dev->irq); + + init_waitqueue_head(&dev->wait_queue); + + /* Read the field bit and assign to the field_id variable */ + dev->field_id = ioread8((void *)dev->virt_addr + HRT_CONTROL_REG) & 1; + /* Initialize the semaphore */ + init_MUTEX(&dev->sem); + + /* set default window size + to cover the entire frame buffer */ + HRT_DEBUG_MSG(1, "setting width, cols = %d", dev->cols); + dev->win_row = 0; + dev->win_width = dev->cols; + dev->win_col = 0; + dev->win_height = dev->rows; + dev->field = -1; + hrt_num_devices++; + dev->state = HRT_CLOSED_STATE; + + + /* Make the lists used for streaming empty */ + /* Added 2005.06.11 Sean/ Atulya + begin */ + + INIT_LIST_HEAD(&dev->capture_list.head); + INIT_LIST_HEAD(&dev->done_list.head); + + dev->capture_list.length = dev->done_list.length = 0; + + /* Initialize the spinlocks to protect the lists */ + dev->capture_list.lock = RW_LOCK_UNLOCKED; + dev->done_list.lock = RW_LOCK_UNLOCKED; + + /* Register with V4L */ + dev->video_dev = videodev_template; + /* Register the video driver */ + printk(KERN_ALERT "RYAN: Before video_register_device\n"); + if (video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, + video_minor) < 0) { + hrt_printk(KERN_ERR "Unable to register video device\n"); + /* Failure in the device registration + * Cleanup before exiting + */ + hrt_cleanup(dev); + return -ENODEV; + } + printk(KERN_ALERT "RYAN: After video_register_device...Must have registered???\n"); + /* set the device status to registered */ + dev->registered = 1; + + /* Set private data (to access through struct file) */ + dev->video_dev.priv = dev; + + /* Set the constants depending on + * whether the device supports color + * or grey scale + */ + + printk(KERN_ALERT "RYAN: @@@@ DEV->MODE = %d\n", dev->mode); + printk(KERN_ALERT "RYAN: @@@@ COLOR_MODE = %d\n", HRT_COLOR_MODE); + if(dev->mode & HRT_COLOR_MODE){ + printk(KERN_ALERT "RYAN: IM INSIDE COLOR MODE\n"); + dev->bytesperline = HRT_COLOR_BYTES_PER_LINE; + dev->framesize = HRT_COLOR_FRAMESIZE; + } + else{ + printk(KERN_ALERT "RYAN: IM INSIDE GRAYSCALE MODE\n"); + + dev->bytesperline = HRT_GRAY_BYTES_PER_LINE; + dev->framesize = HRT_GRAY_FRAMESIZE; + } + + /* Added 2005.06.11 Sean/ Atulya + end */ + + /* Allocate the frame buffer */ + if (dev->mode & HRT_COLOR_MODE) { + dev->framedata = (unsigned char *) vmalloc(HRT_COLOR_FRAMESIZE); + dev->localbuf = (unsigned char *) kmalloc(sizeof(char) * 1664, GFP_KERNEL); + /* Added 2005.06.11 Sean/ Atulya + begin */ + if ((dev->framedata == NULL) || (dev->localbuf == NULL)) { + hrt_printk(KERN_ERR "Unable to allocate memory\n"); + //video_unregister_device(&dev->video_dev); + hrt_cleanup(dev); + return -ENOMEM; + } + /* Added 2005.06.11 Sean/ Atulya + end */ + } + else { + dev->framedata = (unsigned char *) vmalloc(HRT_GRAY_FRAMESIZE); + dev->localbuf = NULL; + /* Added 2005.06.11 Sean/ Atulya + begin */ + if (dev->framedata == NULL) { + hrt_printk(KERN_ERR "Unable to allocate memory\n"); + //video_unregister_device(&dev->video_dev); + hrt_cleanup(dev); + return -ENOMEM; + } + /* Added 2005.06.11 Sean/ Atulya + end */ + } + + /* The device opens in the non streaming mode by default */ + dev->streaming = 0; + + /* Added 13 June 2005 */ + dev->streaming_state = 0; + + dev->upside_down = 0; + + /* Read the field bit and assign to the field_id */ + dev->field_id = hrt_get_field(dev); + + /* Make the device go-live */ + hrt_go_live(dev); + printk(KERN_ALERT "RYAN: Returning from HRT_INIT w 0 \n"); + return 0; } /********************************************************************/ int hrt_isa_init(void) { - int i; - for (i = 0; i < ARRAY_SIZE(hrt_addresses); i++) - hrt_init(hrt_addresses[i], NULL); - - hrt_nonpci_devices = hrt_num_devices; - - return 0; + int i; + for (i = 0; i < ARRAY_SIZE(hrt_addresses); i++) + hrt_init(hrt_addresses[i], NULL); + hrt_nonpci_devices = hrt_num_devices; + return 0; } /********************************************************************/ void hrt_isa_cleanup(void) { - int i; - for (i=0; ivirt_addr + HRT_CONTROL_REG)) & 0x4; - rmb(); - return r; + int r = ioread8((void *)(dev->virt_addr + HRT_CONTROL_REG)) & 0x4; + rmb(); + return r; } /********************************************************************/ -irqreturn_t hrt_irq_handler(int irq, void* dev_id) -{ - struct hrt_dev *dev = dev_id; - if (!hrt_irq_pending(dev)) goto none; - /* acknowledge the interrupt */ - - hrt_irq_disable(dev); - dev->irq_count++; - /* do not try to do any I/O on the device here, - or else risk race with last scheduled tasklet - */ - tasklet_schedule(&dev->tasklet); - /* enable the next interrupt */ - hrt_irq_enable(dev); +irqreturn_t hrt_irq_handler(int irq, void* dev_id, struct pt_regs* regs) +{ + hrt_t* dev = dev_id; + if (!hrt_irq_pending(dev)) goto none; + /* acknowledge the interrupt */ + + hrt_irq_disable(dev); + dev->irq_count++; + /* do not try to do any I/O on the device here, + or else risk race with last scheduled tasklet + */ + tasklet_schedule(&dev->tasklet); + /* enable the next interrupt */ + hrt_irq_enable(dev); #ifdef IRQ_HANDLED - return IRQ_HANDLED; + return IRQ_HANDLED; #endif - -none: + none: #ifdef IRQ_NONE - return IRQ_NONE; + return IRQ_NONE; #endif } -/******************************************************************** - * hrt_timer_handler - * - * Runs every HZ/100 jiffies - * Core of the driver's functionality in the case where - * we do not have interrupts running on the card. - * - * If we are in the blocking read mode, then this timer - * notifies the reader about field changes, and wakes up - * the reader when a new frame becomes available + +/********************************************************************/ +/** + * streaming_fieldchange_color * - * If we are in the streaming I/O mode, then the timer + * Invoked for performing the data reads when streaming + * is in progress + * Called by the timer handler when it determines that + * a complete frame is available for reading into the buffer + * + */ +static inline void streaming_fieldchange_color(hrt_t *hrtdev) +{ + struct stream_buffer *streambuf; + + /* Capture list is empty */ + if (!hrtdev->capture_list.length) { + return; + } + + streambuf = queue_peek_head(&hrtdev->capture_list); + + /* Sanity checks- don't want to do anything bad + in interrupt mode */ + if (streambuf == NULL) { + hrt_printk("streambuf is NULL!\n"); + return; + } + if (streambuf->vaddress == NULL) { + hrt_printk("vaddress is NULL!\n"); + return; + } + if (hrtdev->framedata == NULL) { + hrt_printk("framedata is NULL!\n"); + return; + } + + /* Depending on the device being color or grey scale + * the buffer would have differant sizes + * clear the entire buffer before writing into it + * + * But only if it is empty ! + */ + if (streambuf->fields_grabbed == 0 ){ + if (hrtdev->mode & HRT_COLOR_MODE) + memset(streambuf->vaddress, 0, HRT_COLOR_FRAMESIZE); + else + memset(streambuf->vaddress, 0, HRT_GRAY_FRAMESIZE); + } + + /* Grab the current field and increment the fields_grabbed variable */ + grab_field(hrtdev, streambuf->vaddress,hrtdev->field_id); + streambuf->fields_grabbed++; + + if(streambuf->fields_grabbed > 2){ + /* We have a complete frame */ + streambuf->vidbuf.flags |= + V4L2_BUF_FLAG_DONE | + V4L2_BUF_FLAG_KEYFRAME; + /* Move the buffer to the done queue */ + queue_del(streambuf, &hrtdev->capture_list); + queue_add_tail(streambuf, &hrtdev->done_list); + hrtdev->field_id = !hrtdev->field_id; + /* Set streaming_state to 0 to repeat the streaming read cycle */ + hrtdev->streaming_state = 0; + /* Set fields_grabbed to 0 */ + streambuf->fields_grabbed = 0; + /* wake up the user to notify abt the data being available */ + wake_up(&hrtdev->wait_queue); + } +} + +/********************************************************************/ +/** + * streaming_fieldchange_irq + * + * This function used for streaming if we have IRQs running + * Assumes that every interrupt we know that the field has changed + * So faster than using the timer based mechanism + */ +static inline void streaming_fieldchange_irq(hrt_t *hrtdev) +{ + struct stream_buffer *streambuf; + + /* Capture list is empty */ + if (!hrtdev->capture_list.length) { + return; + } + + streambuf = queue_peek_head(&hrtdev->capture_list); + + /* Sanity checks- don't want to do anything bad + in interrupt mode */ + if (streambuf == NULL) { + hrt_printk("streambuf is NULL!\n"); + return; + } + + if (streambuf->vaddress == NULL) { + hrt_printk("vaddress is NULL!\n"); + return; + } + + if (hrtdev->framedata == NULL) { + hrt_printk("framedata is NULL!\n"); + return; + } + + /* Now that we have checked everything + * and all buffers seem to be fine + * extract the current field from the device + * and copy to the buffer + */ + grab_field(hrtdev, streambuf->vaddress, + !hrtdev->field_id); + + streambuf->fields_grabbed++; + + /* We have a complete frame */ + if (streambuf->fields_grabbed > 1) { + streambuf->fields_grabbed = 0; + streambuf->vidbuf.flags |= + V4L2_BUF_FLAG_DONE | + V4L2_BUF_FLAG_KEYFRAME; + + /* Move the buffer to the done queue */ + queue_del(streambuf, &hrtdev->capture_list); + queue_add_tail(streambuf, &hrtdev->done_list); + /* notify the wait queue that a frame is available + * for display to the user + */ + wake_up(&hrtdev->wait_queue); + } + hrt_printk("streaming_fieldchange ... complete\n"); +} + + +/********************************************************************/ +/** + * streaming_fieldchange + * + * if streaming is on, this function is called + * from timer_func when the field_id changes + */ +static inline void streaming_fieldchange(hrt_t *hrtdev) +{ + struct stream_buffer *streambuf; + + /* Capture list is empty */ + if (!hrtdev->capture_list.length) { + return; + } + + streambuf = queue_peek_head(&hrtdev->capture_list); + + /* Sanity checks- don't want to do anything bad + in interrupt mode */ + if (streambuf == NULL) { + hrt_printk("streambuf is NULL!\n"); + return; + } + + if (streambuf->vaddress == NULL) { + hrt_printk("vaddress is NULL!\n"); + return; + } + + if (hrtdev->framedata == NULL) { + hrt_printk("framedata is NULL!\n"); + return; + } + + /* Now that we have checked everything + * and all buffers seem to be fine + * extract the current field from the device + * and copy to the buffer + */ + grab_field(hrtdev, streambuf->vaddress, + !hrtdev->field_id); + + streambuf->fields_grabbed |= (!hrtdev->field_id) + 1; + + /* We have a complete frame */ + if (streambuf->fields_grabbed == 3) { + streambuf->fields_grabbed = 0; + streambuf->vidbuf.flags |= + V4L2_BUF_FLAG_DONE | + V4L2_BUF_FLAG_KEYFRAME; + + /* Move the buffer to the done queue */ + queue_del(streambuf, &hrtdev->capture_list); + queue_add_tail(streambuf, &hrtdev->done_list); + /* notify the wait queue that a frame is available + * for display to the user + */ + wake_up(&hrtdev->wait_queue); + } +} + + +/******************************************************************** + * hrt_timer_handler + * + * Runs every HZ/100 jiffies + * Core of the driver's functionality in the case where + * we do not have interrupts running on the card. + * + * If we are in the blocking read mode, then this timer + * notifies the reader about field changes, and wakes up + * the reader when a new frame becomes available + * + * If we are in the streaming I/O mode, then the timer * performs checks on the device field changes * and invokes the streaming_fieldchange or the streaming_fieldchange_color * function based on the device's mode. */ void hrt_timer_handler(unsigned long data) { - struct hrt_dev* dev = (struct hrt_dev*)data; - if(dev->timer_active){ - tasklet_schedule(&dev->tasklet); - /* Schedule the timer to go off in another (HZ/100) jiffies */ - dev->timer.expires = jiffies + (HZ/100); - add_timer(&dev->timer); - } + hrt_t* dev = (hrt_t*)data; + if(dev->timer_active){ + tasklet_schedule(&dev->tasklet); + /* Schedule the timer to go off in another (HZ/100) jiffies */ + dev->timer.expires = jiffies + (HZ/100); + add_timer(&dev->timer); + } } /******************************************************************** @@ -1981,24 +2144,24 @@ * * Initialises the IRQs, if the device supports interrupts */ -void hrt_irq_init(struct hrt_dev* dev) +void hrt_irq_init(hrt_t* dev) { - HRT_DEBUG_MSG(2, "hrt_irq_init"); - dev->irq_count = 0; - if (dev->irq == 0) return; - if ((dev->irq > 0) || (dev->mode & HRT_IRQ_MODE)) { - HRT_ERROR_MSG("irq handler already installed"); - return; - } - hrt_irq_disable(dev); /* insurance */ - if (request_irq(-dev->irq, hrt_irq_handler, - IRQF_SHARED, "hrt", (void*)dev)) { - HRT_ERROR_MSG("unable to reserve IRQ"); - dev->irq = 0; - } else { - dev->irq = -dev->irq; - dev->mode |= HRT_IRQ_MODE; - } + HRT_DEBUG_MSG(2, "hrt_irq_init"); + dev->irq_count = 0; + if (dev->irq == 0) return; + if ((dev->irq > 0) || (dev->mode & HRT_IRQ_MODE)) { + HRT_ERROR_MSG("irq handler already installed"); + return; + } + hrt_irq_disable(dev); /* insurance */ + if (request_irq(-dev->irq, hrt_irq_handler, + SA_SHIRQ, "hrt", (void*)dev)) { + HRT_ERROR_MSG("unable to reserve IRQ"); + dev->irq = 0; + } else { + dev->irq = -dev->irq; + dev->mode |= HRT_IRQ_MODE; + } } /******************************************************************** @@ -2006,14 +2169,14 @@ * * Cleanup the IRQs */ -void hrt_irq_cleanup(struct hrt_dev* dev) +void hrt_irq_cleanup(hrt_t* dev) { - HRT_DEBUG_MSG(2, "hrt_irq_cleanup"); - hrt_irq_disable(dev); /* insurance */ - if (dev->mode & HRT_IRQ_MODE) { - free_irq(dev->irq, dev); - dev->mode &= ~HRT_IRQ_MODE; - } + HRT_DEBUG_MSG(2, "hrt_irq_cleanup"); + hrt_irq_disable(dev); /* insurance */ + if (dev->mode & HRT_IRQ_MODE) { + free_irq(dev->irq, dev); + dev->mode &= ~HRT_IRQ_MODE; + } } /******************************************************************* @@ -2022,26 +2185,31 @@ * If the device supports interrupts then initialise IRQs * else initialise the timer */ -void hrt_timer_init(struct hrt_dev* dev) +void hrt_timer_init(hrt_t* dev) { - HRT_DEBUG_MSG(1, "hrt_timer_init"); - HRT_CHECK(dev, HRT_INITIALIZING_STATE, "4"); - if (dev->timer_active) { - HRT_ERROR_MSG("irq or timer already active"); - } - - hrt_irq_init(dev); - - if (!(dev->mode & HRT_IRQ_MODE)) { - if (dev->timer.function) { - HRT_ERROR_MSG("timer already initialized"); - return; - } - HRT_DEBUG_MSG(1, "installing timer\n"); - init_timer(&dev->timer); - dev->timer.function = hrt_timer_handler; - dev->timer.data = (unsigned long)dev; - } + HRT_DEBUG_MSG(1, "hrt_timer_init"); + HRT_CHECK(dev, HRT_INITIALIZING_STATE, "4"); + if (dev->timer_active) { + HRT_ERROR_MSG("irq or timer already active"); + /* Commented by Sean & Atulya 2005.06.15 + debugging irg + return; + */ + } + + /* Added 15 june 2005, to add the functionality to use interrupts */ + hrt_irq_init(dev); + + if (!(dev->mode & HRT_IRQ_MODE)) { + if (dev->timer.function) { + HRT_ERROR_MSG("timer already initialized"); + return; + } + HRT_DEBUG_MSG(1, "installing timer\n"); + init_timer(&dev->timer); + dev->timer.function = hrt_timer_handler; + dev->timer.data = (unsigned long)dev; + } } /******************************************************************** @@ -2049,16 +2217,17 @@ * * Cleanup the timer / IRQ */ -void hrt_timer_cleanup(struct hrt_dev* dev) +void hrt_timer_cleanup(hrt_t* dev) { - HRT_DEBUG_MSG(1, "hrt_timer_cleanup"); - HRT_CHECK(dev, HRT_FINALIZING_STATE, "3"); - hrt_timer_deactivate (dev); - - tasklet_kill(&dev->tasklet); - - hrt_irq_cleanup(dev); - dev->timer.function = NULL; + HRT_DEBUG_MSG(1, "hrt_timer_cleanup"); + HRT_CHECK(dev, HRT_FINALIZING_STATE, "3"); + hrt_timer_deactivate (dev); + /* Added by Sean/ Atulya 2005.06.15 + --- begin --- */ + tasklet_kill(&dev->tasklet); + /* --- end --- */ + hrt_irq_cleanup(dev); + dev->timer.function = NULL; } /******************************************************************** @@ -2067,22 +2236,23 @@ * If timer is running then deactivate it else disable the irqs. * The tasklet runs in both cases. So disable the tasklet */ -void hrt_timer_deactivate(struct hrt_dev* dev) +void hrt_timer_deactivate(hrt_t* dev) { - HRT_DEBUG_MSG(1, "hrt_timer_deactivate"); - if (dev->timer_active) { - dev->timer_active = 0; - if (dev->mode & HRT_IRQ_MODE){ - hrt_irq_disable(dev); - } - else - del_timer_sync(&dev->timer); - - if (dev->tasklet_active) { - dev->tasklet_active = 0; - tasklet_disable(&dev->tasklet); - } - } + HRT_DEBUG_MSG(1, "hrt_timer_deactivate"); + if (dev->timer_active) { + dev->timer_active = 0; + if (dev->mode & HRT_IRQ_MODE){ + hrt_irq_disable(dev); + } + else + del_timer_sync(&dev->timer); + + // Added 15 june 2005 + if (dev->tasklet_active) { + dev->tasklet_active = 0; + tasklet_disable(&dev->tasklet); + } + } } /********************************************************************/ @@ -2093,185 +2263,294 @@ * from the device. */ -int hrt_timer_activate(struct hrt_dev* dev) +int hrt_timer_activate(hrt_t* dev) { - int result = 0; - HRT_DEBUG_MSG(1, "hrt_timer_activate"); - - if (dev->timer_active) { - HRT_ERROR_MSG("irq or timer already active"); - return 0; - } - dev->timer_active = 1; - if (dev->mode & HRT_IRQ_MODE) { - HRT_DEBUG_MSG(1, "enabling irq"); - if (!dev->tasklet_active) { - dev->tasklet_active = 1; - tasklet_enable(&dev->tasklet); - } - hrt_irq_enable(dev); - } else { - if (!dev->timer.function) { - HRT_ERROR_MSG("timer not initialized"); - return -1; - } - printk("Enabling the tasklet inside the timer_activate\n"); - if (!dev->tasklet_active) { - dev->tasklet_active = 1; - tasklet_enable(&dev->tasklet); - } - dev->timer.expires = jiffies + HZ/100; - add_timer(&dev->timer); - } - return result; + int result = 0; + HRT_DEBUG_MSG(1, "hrt_timer_activate"); + + if (dev->timer_active) { + HRT_ERROR_MSG("irq or timer already active"); + return 0; + } + dev->timer_active = 1; + if (dev->mode & HRT_IRQ_MODE) { + HRT_DEBUG_MSG(1, "enabling irq"); + if (!dev->tasklet_active) { + dev->tasklet_active = 1; + tasklet_enable(&dev->tasklet); + } + hrt_irq_enable(dev); + } else { + if (!dev->timer.function) { + HRT_ERROR_MSG("timer not initialized"); + return -1; + } + printk("Enabling the tasklet inside the timer_activate\n"); + if (!dev->tasklet_active) { + dev->tasklet_active = 1; + tasklet_enable(&dev->tasklet); + } + dev->timer.expires = jiffies + HZ/100; + add_timer(&dev->timer); + } + return result; } /******************************************************************** * hrt_tasklet * - * The tasklet is the core of the module in both IRQ and Timer 'mode' - * finally the tasklet performs the required function + * The tasklet is the core of the module + * In both IRQ and Timer 'mode' finally the tasklet + * performs the required function * - * For the irq mode we know that every invocation we have a field change + * For the irq mode we know that every invocation we have + * a field change * But for the timer mode, we check every time to see if the * field_id has changed + * */ void hrt_tasklet(unsigned long data) { - int new_field; - struct hrt_dev* dev = (struct hrt_dev*)data; - struct hrt_buffer *item = NULL; - void *vbuf =NULL; - unsigned long flags; - - - if (dev->state != HRT_OPEN_STATE) return; - if (!spin_trylock_irqsave(&dev->spinlock,flags)) - return; - - /* Get the current value of the field bit */ - new_field = hrt_get_field (dev); - if (dev->field_id == -1) { - /* just started; don't know previous state */ - dev->field_id = new_field; - goto done; - } - if (list_empty(&dev->capture)) - goto done; - - /* SINGLE PORTED */ - if ((dev->mode & HRT_COLOR_MODE) || !(dev->mode & HRT_DUAL_PORTED_MODE)){ - /* if we are in the color mode, we follow differant states: - * State 0 : device goes live; state changes to 1. - * State 1 : detect 2 field changes; issue freeze_next command; - * move to state 2. - * State 2 : detect 2 field changes; call the streaming_framechange function - * to read the current frame move back to state 0 - */ - if (dev->streaming_state == 0){ /* State 0 */ - printk("State 0\n"); - if(dev->is_frozen){ - hrt_go_live(dev); - } - if (new_field == 1) { - dev->streaming_state = 1; - dev->field_changes = 2; - } - } else if (dev->streaming_state == 1){ /* State 1 */ - printk("State 1 dev->field_changes = %d\n", dev->field_changes); - new_field = hrt_get_field(dev); - if (new_field != dev->field_id){ - dev->field_id = new_field; - if(dev->field_changes > 0) dev->field_changes--; - if (dev->field_changes == 0){ - dev->streaming_state = 2; - dev->field_changes = 2; - printk("HRT_FREEZE_NEXT\n"); - hrt_freeze_next(dev); - } - } - } else if (dev->streaming_state == 2){ /* State 2 */ - printk("State 2 dev->field_changes = %d\n", dev->field_changes); - new_field = hrt_get_field(dev); - if (new_field != dev->field_id || - ((new_field == dev->field_id) && (dev->mode & HRT_IRQ_MODE))){ - dev->field_id = new_field; - item = list_entry(dev->capture.next, struct hrt_buffer, vb.queue); - /* The next is to obtain the buffer address of a videobuf_buffer. - * The data buffer of the videobuf_buffer is allocated by - * invoking __videobuf_iolock via calling buffer_prepare by - * ether videobuf_qbuf or read operation */ - vbuf = videobuf_to_vmalloc(&item->vb); - if(vbuf != NULL) { /*grab a complete video frame from the device*/ - grab_field(dev, (unsigned char *) vbuf, dev->field_id); - grab_field(dev, (unsigned char *) vbuf, !dev->field_id); - } else { - printk("buffer pointer invalid\n"); - goto done; - } - printk("after grab\n"); - item->vb.state = VIDEOBUF_DONE; - list_del(&item->vb.queue); - wake_up(&item->vb.done); - dev->streaming_state = 0; - } /* field change */ - else { - /* no field change and no interrupt */ - /* do nothing */ - } - } /* state 2 */ - } /* color and single port mode */ - else { - /* DUAL PORTED - * - * This one not as complicated as the color function - * Just read the current available field - * whenever there is a field change - */ - if((new_field == dev->field_id) && !(dev->mode & HRT_IRQ_MODE)) { - printk("Keep waiting field id change\n"); - goto done; - } else if (new_field != dev->field_id) { - dev->field_id = new_field; - } else if ((new_field == dev->field_id) && (dev->mode & HRT_IRQ_MODE)) { - dev->field_id = !new_field; - } - - item = list_entry(dev->capture.next, struct hrt_buffer, vb.queue); - vbuf = videobuf_to_vmalloc(&item->vb); - - if(vbuf == NULL) { - printk("buffer pointer invalid\n"); - goto done; - } - - if(dev->field_id == 1) { - grab_field(dev, (unsigned char *) vbuf, !dev->field_id); - item->fields_grabbed = 0x1; - printk("grab field %d\n",!dev->field_id); - } - else if ((dev->field_id == 0) && (item->fields_grabbed == 0x1)) { - grab_field(dev, (unsigned char *) vbuf, !dev->field_id); - item->fields_grabbed |= 0x2; - printk("grab field %d\n",!dev->field_id); - } - else { - item->fields_grabbed = 0; - printk("Fail to grab one frame: reset...\n"); - } - /* We have a complete frame */ - if (item->fields_grabbed == 0x3) { - item->fields_grabbed = 0; - item->vb.state = VIDEOBUF_DONE; - list_del(&item->vb.queue); - wake_up(&item->vb.done); - } - } - -done: - spin_unlock_irqrestore(&dev->spinlock,flags); + int new_field; + hrt_t* dev = (hrt_t*)data; + + if (dev->state != HRT_OPEN_STATE) return; + + if (hrt_trylock (dev)) { /* device is busy */ + return; + } + + /* Get the current value of the field bit */ + new_field = hrt_get_field (dev); + + if (dev->field_id == -1) { + /* just started; don't know previous state */ + dev->field_id = new_field; + goto done; + } + + /* We need to do something only if the field bit has changed from + * the last value. This would indicate that the field has changed + * from what we read in the last timer execution. + * + * So now we need to take some action if we detect the field change + */ + + + /* CASE 1 - NO IRQs. TIMER RUNNING EVERY HZ/100 JIFFIES */ + if (!(dev->mode & HRT_IRQ_MODE)) { + if (dev->streaming) { + /* If we have streaming running, then call the function + * responsible for updating the streaming display + * + * Differant implementations of streaming + * for color and grey scale follow + */ + if ((dev->mode & HRT_COLOR_MODE) || !(dev->mode & HRT_DUAL_PORTED_MODE)){ + /* if we are in the color mode, we follow differant states + * + * State 0 + * + * device goes live + * state changes to 1 + * + * State 1 + * + * detect 2 field changes + * issue freeze_next command + * move to state 2 + * + * State 2 + * + * detect 2 field changes + * call the streaming_framechange function + * to read the current frame + * move back to state 0 + */ + if (dev->streaming_state == 0){ + hrt_printk("State 0\n"); + if(dev->is_frozen){ + hrt_printk("HRT_GO_LIVE\n"); + hrt_go_live(dev); + } + else + hrt_printk ("THIS IS AN ERROR\n"); + dev->streaming_state = 1; + dev->field_changes = 2; + } + else if (dev->streaming_state == 1){ + hrt_printk("State 1 dev->field_changes = %d\n", dev->field_changes); + new_field = hrt_get_field(dev); + if (new_field != dev->field_id){ + dev->field_id = new_field; + if(dev->field_changes > 0) dev->field_changes--; + if (dev->field_changes == 0){ + dev->streaming_state = 2; + dev->field_changes = 2; + hrt_printk("HRT_FREEZE_NEXT\n"); + hrt_freeze_next(dev); + } + } + } + else if (dev->streaming_state == 2){ + hrt_printk("State 2 dev->field_changes = %d\n", dev->field_changes); + new_field = hrt_get_field(dev); + if (new_field != dev->field_id){ + dev->field_id = new_field; + if(dev->field_changes > 0) dev->field_changes--; + if (dev->field_changes == 0){ + dev->streaming_state = 0; + streaming_fieldchange_color(dev); + } + } + } + } + else { + /* Streaming + Grey scale mode + * + * This one not as complicated as the color function + * Just read the current available field + * whenever there is a field change + */ + if (new_field != dev->field_id) { + dev->field_id = new_field; + streaming_fieldchange(dev); + } + } + } + else { + /* Not streaming. + * We are in the read mode + * update the reader and let them know that another + * field is available. The reader always waits till we have read + * two fields. Thus he/she/it(?) needs to be notified + * when we read two fields + */ + if (new_field != dev->field_id) { + dev->field_id = new_field; + if (dev->field_changes >0) dev->field_changes--; + wake_up_interruptible(&dev->wait_queue); + } + } + } + else { + /* CASE 2 - IRQs ENABLES. AN INTERRUPT RAISED WHENEVER THE FIELD BIT CHANGES */ + if (dev->streaming) { + /* If we have streaming running, then call the function + * responsible for updating the streaming display + * + * Differant implementations of streaming + * for color and grey scale follow + */ + if ((dev->mode & HRT_COLOR_MODE) || !(dev->mode & HRT_DUAL_PORTED_MODE)){ + /* if we are in the color mode, we follow differant states + * + * State 0 + * + * device goes live + * state changes to 1 + * + * State 1 + * + * detect 2 field changes + * issue freeze_next command + * move to state 2 + * + * State 2 + * + * detect 2 field changes + * call the streaming_framechange function + * to read the current frame + * move back to state 0 + */ + if (dev->streaming_state == 0){ + hrt_printk("State 0\n"); + if(dev->is_frozen){ + hrt_printk("HRT_GO_LIVE\n"); + hrt_go_live(dev); + } + else + hrt_printk ("THIS IS AN ERROR\n"); + dev->streaming_state = 1; + dev->field_changes = 2; + } + else if (dev->streaming_state == 1){ + hrt_printk("State 1 dev->field_changes = %d\n", dev->field_changes); + new_field = hrt_get_field(dev); + if (new_field != dev->field_id){ + dev->field_id = new_field; + if(dev->field_changes > 0) dev->field_changes--; + if (dev->field_changes == 0){ + dev->streaming_state = 2; + dev->field_changes = 2; + hrt_printk("HRT_FREEZE_NEXT\n"); + hrt_freeze_next(dev); + } + } + } + else if (dev->streaming_state == 2){ + hrt_printk("State 2 dev->field_changes = %d\n", dev->field_changes); + new_field = hrt_get_field(dev); + if (new_field != dev->field_id){ + dev->field_id = new_field; + streaming_fieldchange_color(dev); + } + } + } + else { + /* Streaming + Grey scale mode + * + * This one not as complicated as the color function + * Just read the current available field + * whenever there is a field change + */ + dev->field_id = new_field; + streaming_fieldchange_irq(dev); + } + } + else { + /* Not streaming. + * We are in the read mode + * update the reader and let them know that another + * field is available. The reader always waits till we have read + * two fields. Thus he/she/it(?) needs to be notified + * when we read two fields + */ + dev->field_id = new_field; + if (dev->field_changes > 0) dev->field_changes--; + wake_up_interruptible(&dev->wait_queue); + } + } + + + done: + hrt_unlock(dev); +} + +/******************************************************************** + * per_file_init + * + * allocates and initializes per-file data, which + * is currently just the ROI (region-of-interest) subwindow + * and a pointer back to this hrtdev + */ +struct hrt_per_file *per_file_init(hrt_t *hrtdev) +{ + struct hrt_per_file *per_file = vmalloc(sizeof(*per_file)); + + per_file->hrtdev = hrtdev; + per_file->win.height = HRT_HEIGHT; + if (hrtdev->mode & HRT_COLOR_MODE) + per_file->win.width = HRT_COLOR_WIDTH; + else + per_file->win.width = HRT_GRAY_WIDTH; + per_file->win.startx = 0; + per_file->win.starty = 0; + + return per_file; } + /********************************************************************/ /** * hrt_open @@ -2281,93 +2560,76 @@ */ int hrt_open(struct inode *inode, struct file *file) { - int minor = iminor(inode); - int result = 0; - struct hrt_dev *dev; - struct hrt_fh *fh; - - printk(KERN_DEBUG "hrt: open called (minor=%d)\n", minor); - list_for_each_entry(dev, &hrt_devlist, hrt_devlist) - if (dev->video_dev->minor == minor) - goto found; - return -ENODEV; - -found: - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) { - return -ENOMEM; - } - file->private_data = fh; - fh->dev = dev; - fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fh->win.height = HRT_HEIGHT; - - if (dev->mode & HRT_COLOR_MODE) { - fh->win.width = HRT_COLOR_WIDTH; - fh->win.depth = HRT_COLOR_BYTES_PER_PIXEL; - fh->fmt = &formats[0]; - } - else { - fh->win.width = HRT_GRAY_WIDTH; - fh->win.depth = HRT_GRAY_BYTES_PER_PIXEL; - fh->fmt = &formats[1]; - } - fh->win.startx = 0; - fh->win.starty = 0; - - videobuf_queue_vmalloc_init(&fh->vb_vidq, &hrt_video_qops, - NULL, &dev->spinlock, fh->type, V4L2_FIELD_INTERLACED, - sizeof(struct hrt_buffer), fh); - - /* If more than one user, mutex should be added */ - mutex_lock(&dev->lock); - - dev->users++; + unsigned int minor; + int result; + /* video device structure required to provide video4linux support */ + struct video_device *vfl = video_devdata(file); + hrt_t *dev = vfl->priv; + + result = 0; + minor = MINOR(inode->i_rdev); + if (minor >= HRT_MAX_DEVICES) return -ENODEV; + + dev = hrt_devices + minor; + HRT_DEBUG_MSG(1, "opening device %d at addr %lX", minor, (unsigned long)dev->phys_addr); + + /* Cannot open if device is not in closed state */ + if (dev->state != HRT_CLOSED_STATE) { + HRT_DEBUG_MSG(2, "already open"); + return -EBUSY; + } + /* Now we set the private data for the device file + * this is in the form of a structure hrt_per_file + * that consists of a hrt_t struct and a subwindow struct + */ + HRT_DEBUG_MSG(2, "setting private data"); + file->private_data = per_file_init(dev); + + /* Set device state to OPEN */ + dev->state = HRT_OPEN_STATE; - if (1 == dev->users) { + /* The device opens in the non streaming mode by default */ + dev->streaming = 0; - /* Set device state to OPEN */ - dev->state = HRT_OPEN_STATE; + /* Added 13 June 2005 */ + dev->streaming_state = 0; - /* Activate the timer */ - HRT_DEBUG_MSG(2, "installing timer/irq"); - result = hrt_timer_activate(dev); - } - mutex_unlock(&dev->lock); + /* Read the field bit and assign to the field_id */ + dev->field_id = hrt_get_field(dev); + + /* Activate the timer */ + HRT_DEBUG_MSG(2, "installing timer/irq"); + result = hrt_timer_activate(dev); - return result; + return result; } /********************************************************************/ -/* hrt_close +/* hrt_release * - * hrt_close should not need any lock, because + * hrt_release should not need any lock, because it is only called by the system, on last close; at that point there should be no possibility of more calls that touch this device, unless they are from a timer or interrrupt handler */ -int hrt_close(struct inode *inode, struct file *file) +int hrt_release(struct inode *inode, struct file *file) { - struct hrt_fh *fh = file->private_data; - struct hrt_dev *dev = fh->dev; - int minor = iminor(inode); - - videobuf_stop(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vidq); - kfree(fh); - - mutex_lock(&dev->lock); - dev->users--; - if (dev->users <= 0) { - dev->state = HRT_CLOSED_STATE; - hrt_timer_deactivate(dev); - } - mutex_unlock(&dev->lock); - printk("close called (minor=%d, users=%d)\n",minor, dev->users); - - return 0; + struct video_device *vfl = video_devdata(file); + hrt_t *dev = vfl->priv; + + hrt_printk( " hrt_release\n"); + if (dev->is_locked) { + hrt_unlock(dev); + } + if (dev->state != HRT_OPEN_STATE) return -ENODEV; + dev->state = HRT_CLOSED_STATE; + hrt_timer_deactivate(dev); + + /* Free our private data */ + vfree(file->private_data); + return 0; } /********************************************************************/ @@ -2377,160 +2639,28 @@ */ unsigned int hrt_poll(struct file *file, poll_table *wait) { - struct hrt_fh *fh = file->private_data; - struct hrt_buffer *buf; - enum v4l2_field field; - void *vbuf; - unsigned long flags = 0; - + struct hrt_per_file *per_file = file->private_data; + hrt_t *hrtdev = per_file->hrtdev; - if (1 == fh->vb_vidq.streaming) { - /* streaming capture */ - if (list_empty(&fh->vb_vidq.stream)) { - printk("list empty\n"); - return POLLERR; - } - - buf = list_entry(fh->vb_vidq.stream.next, struct hrt_buffer,vb.stream); - poll_wait(file, &buf->vb.done, wait); - - vbuf = videobuf_to_vmalloc(&buf->vb); - if (vbuf == NULL) { - printk("Can not convert videobuf to vmalloc in poll!\n"); - return POLLERR; - } - - if (buf->vb.memory == V4L2_MEMORY_USERPTR) { - memcpy((unsigned char *)buf->vb.baddr, vbuf, - fh->win.width * fh->win.height * fh->win.depth); - printk ("give user a buf : size is %d\n", fh->win.width * fh->win.height * fh->win.depth ); - } - } else { - /* read() capture */ - mutex_lock(&fh->vb_vidq.vb_lock); - - if (NULL == fh->vb_vidq.read_buf) { - /* need to cature a new frame */ - fh->vb_vidq.read_buf = videobuf_alloc(&fh->vb_vidq); - if (NULL == fh->vb_vidq.read_buf) - goto err; - - printk("After alloc in poll!\n"); - fh->vb_vidq.read_buf->memory = V4L2_MEMORY_USERPTR; - fh->vb_vidq.read_buf->bsize = fh->vb_vidq.msize; - field = videobuf_next_field(&fh->vb_vidq); - if (0 != fh->vb_vidq.ops->buf_prepare(&fh->vb_vidq, - fh->vb_vidq.read_buf,field)) { - kfree (fh->vb_vidq.read_buf); - fh->vb_vidq.read_buf = NULL; - goto err; - } - - printk("After prepare buffer in poll!\n"); - if (fh->vb_vidq.irqlock) - spin_lock_irqsave(&fh->vb_vidq.irqlock, flags); - - fh->vb_vidq.ops->buf_queue(&fh->vb_vidq,fh->vb_vidq.read_buf); - - if (fh->vb_vidq.irqlock) - spin_unlock_irqrestore(&fh->vb_vidq.irqlock, flags); - - fh->vb_vidq.read_off = 0; - } - - mutex_unlock(&fh->vb_vidq.vb_lock); - buf = (struct hrt_buffer*)fh->vb_vidq.read_buf; + if (!hrtdev->streaming) { + poll_wait(file, &hrtdev->wait_queue, wait); + } else { + /* Go to sleep if the done list is empty */ + while (!hrtdev->done_list.length) { + up(&hrtdev->sem); + if (wait_event_interruptible + (hrtdev->wait_queue, (hrtdev->done_list.length))) + return -ERESTARTSYS; - poll_wait(file, &buf->vb.done, wait); - printk("after poll wait\n"); - } + if (down_interruptible(&hrtdev->sem)) + return -ERESTARTSYS; + } + } - if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) - return POLLIN|POLLRDNORM; + return POLLIN | POLLRDNORM; +} - return 0; -err: - mutex_unlock(&fh->vb_vidq.vb_lock); - return POLLERR; -} -#define CALL(q, f, arg...) \ - ((q->int_ops->f) ? q->int_ops->f(arg) : 0) -/* just for read */ -size_t hrt_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking) -{ - enum v4l2_field field; - unsigned long flags = 0; - unsigned size, nbufs; - int retval; - - mutex_lock(&q->vb_lock); - - nbufs = 1; size = 0; - q->ops->buf_setup(q, &nbufs, &size); - - if (NULL == q->read_buf) { - /* need to capture a new frame */ - retval = -ENOMEM; - q->read_buf = videobuf_alloc(q); - - //printk(1, "video alloc=0x%p\n", q->read_buf); - if (NULL == q->read_buf) - goto done; - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->bsize = count; /* preferred size */ - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, q->read_buf, field); - - if (0 != retval) { - kfree(q->read_buf); - q->read_buf = NULL; - goto done; - } - if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); - - q->ops->buf_queue(q, q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); - q->read_off = 0; - } - - /* wait until capture is done */ - retval = videobuf_waiton(q->read_buf, nonblocking, 1); - if (0 != retval) - goto done; - - CALL(q, sync, q, q->read_buf); - - if (VIDEOBUF_ERROR == q->read_buf->state) { - /* catch I/O errors */ - q->ops->buf_release(q, q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - retval = -EIO; - goto done; - } - - /* Copy to userspace */ - retval = CALL(q, video_copy_to_user, q, data, count, nonblocking); - if (retval < 0) - goto done; - - q->read_off += retval; - if (q->read_off == q->read_buf->size) { - /* all data copied, cleanup */ - q->ops->buf_release(q, q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - } - -done: - mutex_unlock(&q->vb_lock); - return retval; -} /******************************************************************** * hrt_read @@ -2538,37 +2668,191 @@ * Does a blocking read and return count number of bytes back to the user * Differant implementations for color/grey scale/single ported/dual ported */ -int hrt_read(struct file *file, char __user *data, size_t count, loff_t * ppos) +int hrt_read(struct file *file, char *buf, size_t count, loff_t * ppos) { - struct hrt_fh *fh = file->private_data; - int retval = 0; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - - retval = hrt_read_one(&fh->vb_vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); - - break; - default: - BUG(); - } + int max_count; + + /* atulya/sean - to measure the frame rate + * record the jiffies at this time + * then find the jiffies at the time the function returns + * the differance gives the time taken to read one frame + * and thus the frame rate + */ + unsigned int starttime; + + int old_field; + struct video_device *vfl = video_devdata(file); + hrt_t *dev = vfl->priv; + + HRT_DEBUG_MSG(3, "hrt_read count = %d", count); + if (dev->state != HRT_OPEN_STATE) return -ENODEV; + + + //hrt_printk( "hrt_read: (start) jiffies = %ld\n", jiffies); + starttime = jiffies; + + if (dev->mode & HRT_COLOR_MODE) { + /* First implementation - COLOR device + * + * These ones are single ported so + * need to wait till the entire field gets digitized before we can read it + * This is a conservative approach..and wastes an extra frame just to make + * sure that we get the correct frame boundary. + * Can be tweaked to make it faster + */ + hrt_lock(dev); + dev->field_changes = 2; + if (dev->is_frozen) { + hrt_go_live (dev); + hrt_unlock(dev); + /* Go live + * and + * wait for two field changes + */ + if (wait_event_interruptible(dev->wait_queue, dev->field_changes == 0)) { + return -ERESTARTSYS; + } + hrt_lock(dev); + dev->field_changes = 2; + } + hrt_freeze_next(dev); + hrt_unlock(dev); + /* Now we know that we are at a frame bondary + * Wait for 2 field changes + * and at that time we can read both fields as one frame + */ + if (wait_event_interruptible(dev->wait_queue, dev->field_changes == 0)) { + return -ERESTARTSYS; + } + /* Cannot return more bytes than what the device sends to us + * Check for that */ + max_count = dev->win->width * dev->win->height * dev->bytes_per_pixel; + if (count > max_count) count = max_count; + + if (down_interruptible(&dev->sem)) + return -ERESTARTSYS; + + old_field = dev->field_id; + + /* Grab a field */ + grab_field(dev, dev->framedata, old_field); - return retval; + printk(KERN_ALERT "\nDEV FIELD IS %d \n", old_field); + + /* Grab the other field */ + grab_field(dev, dev->framedata,(!old_field) ); + } + else { + /* Implementation 2 - GREY SCALE DULA ported device + * + * These devices are dual ported so we can + * read at a faster rate + * Dont need the extra checking required in the + * case of single ported devices. + * Results in a faster rate + * + * Just grab one field, + * wait for a field change + * and grab the other field + */ + if (dev->mode & HRT_DUAL_PORTED_MODE) { + max_count = dev->win->width * dev->win->height * dev->bytes_per_pixel; + if (count > max_count) count = max_count; + down_interruptible(&dev->sem); + old_field = dev->field_id; + + /* Grab a field */ + grab_field(dev, dev->framedata, old_field); + + /* Go to sleep until the field bit changes */ + while (old_field == dev->field_id) { + up(&dev->sem); + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (wait_event_interruptible + (dev->wait_queue, (old_field != dev->field_id))) + return -ERESTARTSYS; + + if (down_interruptible(&dev->sem)) + return -ERESTARTSYS; + } + + /* Grab the other field */ + grab_field(dev, dev->framedata, dev->field_id); + } + else { + /* Imlementation 3 - GREYSCALE SINGLE ported device + * + * Again similar implementation as the color devices + */ + hrt_lock(dev); + dev->field_changes = 2; + if (dev->is_frozen) { + hrt_go_live (dev); + hrt_unlock(dev); + if (wait_event_interruptible(dev->wait_queue, dev->field_changes == 0)) { + return -ERESTARTSYS; + } + hrt_lock(dev); + dev->field_changes = 2; + } + hrt_freeze_next(dev); + hrt_unlock(dev); + if (wait_event_interruptible(dev->wait_queue, dev->field_changes == 0)) { + return -ERESTARTSYS; + } + + max_count = dev->win->width * dev->win->height * dev->bytes_per_pixel; + if (count > max_count) count = max_count; + + if (down_interruptible(&dev->sem)) + return -ERESTARTSYS; + + old_field = dev->field_id; + + /* Grab a field */ + grab_field(dev, dev->framedata, old_field); + + /* Grab the other field */ + grab_field(dev, dev->framedata,(!old_field) ); + } + } + + /* Both returned fields have been stored in their corresponding + * location inside the dev->framedata buffer + * Return to the user + */ + if (copy_to_user(buf, dev->framedata, count)) { + up(&dev->sem); + return -EFAULT; + } + /* Clear the buffer */ + if (dev->mode & HRT_COLOR_MODE) + memset(dev->framedata, 0, HRT_COLOR_FRAMESIZE); + else + memset(dev->framedata, 0, HRT_GRAY_FRAMESIZE); + + + up(&dev->sem); + /* (1/ (time taken to read one frame)) = frame rate */ + hrt_printk( " Frame rate = %d\n", (int)( HZ / (jiffies-starttime) ) ); + return count; } - + /******************************************************************** * * v4l1_ioctls - used for printing out ioctl codes in hrt_do_ioctl */ static const char *v4l1_ioctls[] = { - "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", - "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", - "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", - "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", - "SMICROCODE", "GVBIFMT", "SVBIFMT" + "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", + "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", + "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", + "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", + "SMICROCODE", "GVBIFMT", "SVBIFMT" }; + /******************************************************************** * * hrt_do_ioctl - handles ioctl's on /dev/video @@ -2576,104 +2860,355 @@ static int hrt_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { - struct hrt_fh *fh = file->private_data; - struct hrt_dev *dev = fh->dev; - unsigned long flags = 0; - int ret=-EINVAL; - dev->win = &fh->win; - - /* This nice code copied from xawtv's libng. - It prints out the ioctl's that are done. - */ - switch (_IOC_TYPE(cmd)) { - case 'v': - printk("ioctl 0x%x (v4l1, VIDIOC%s)\n", - cmd, (_IOC_NR(cmd) < ARRAY_SIZE(v4l1_ioctls)) ? - v4l1_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'V': - /*printk("ioctl 0x%x (v4l2, %s)\n", - cmd, v4l2_ioctl_names[_IOC_NR(cmd)]); */ - break; - default: - break;// printk("ioctl 0x%x (?)\n", cmd); + struct hrt_per_file *per_file = file->private_data; + hrt_t *hrtdev = per_file->hrtdev; + hrtdev->win = &per_file->win; + + /* This nice code copied from xawtv's libng. + It prints out the ioctl's that are done. + */ + switch (_IOC_TYPE(cmd)) { + case 'v': + dprintk("ioctl 0x%x (v4l1, VIDIOC%s)\n", + cmd, (_IOC_NR(cmd) < ARRAY_SIZE(v4l1_ioctls)) ? + v4l1_ioctls[_IOC_NR(cmd)] : "???"); + break; + case 'V': + /*dprintk("ioctl 0x%x (v4l2, %s)\n", + cmd, v4l2_ioctl_names[_IOC_NR(cmd)]); */ + break; + default: + dprintk("ioctl 0x%x (?)\n", cmd); + } + + switch (cmd) { + case IOC_HRT_FREEZE_FRAME: + HRT_DEBUG_MSG(2, "IOC_HRT_FREEZE_FRAME: called"); + hrt_freeze_next(hrtdev); + break; + + case IOC_HRT_GO_LIVE: + HRT_DEBUG_MSG(2, "IOC_HRT_GO_LIVE: called"); + hrt_go_live(hrtdev); + break; + case IOC_HRT_UPSIDE_DOWN: + HRT_DEBUG_MSG(2, "IOC_HRT_UPSIDE_DOWN: called"); + if (hrtdev->upside_down) + hrtdev->upside_down = 0; + else + hrtdev->upside_down = 1; + break; + + /* Streaming ioctl's */ + case VIDIOC_REQBUFS: { + struct v4l2_requestbuffers *req = arg; + + if (hrtdev->stream_buffers_mapped) { + hrt_printk("REQBUFS - Can't request buffers if " + " buffers are already mapped\n"); + return -EPERM; } - - switch (cmd) { - case IOC_HRT_FREEZE_FRAME: - HRT_DEBUG_MSG(2, "IOC_HRT_FREEZE_FRAME: called"); - spin_lock_irqsave(&dev->spinlock,flags); - - hrt_freeze_next(dev); - - spin_unlock_irqrestore(&dev->spinlock,flags); - return 0; - - case IOC_HRT_GO_LIVE: - HRT_DEBUG_MSG(2, "IOC_HRT_GO_LIVE: called"); - spin_lock_irqsave(&dev->spinlock,flags); - - hrt_go_live(dev); - - spin_unlock_irqrestore(&dev->spinlock,flags); - - return 0; + if (!mmap_request_buffers(hrtdev, req)) { + hrt_printk("REQBUFS - Request of buffers failed\n"); + return -EINVAL; + } + return 0; + } + case VIDIOC_QUERYBUF: { + struct v4l2_buffer *buf = + (struct v4l2_buffer *) arg; + int i; + i = buf->index; - case IOC_HRT_UPSIDE_DOWN: - HRT_DEBUG_MSG(2, "IOC_HRT_UPSIDE_DOWN: called"); - mutex_lock(&dev->lock); - - if (dev->upside_down) - dev->upside_down = 0; - else - dev->upside_down = 1; - - mutex_unlock(&dev->lock); - - return 0; -/* - case VIDIOC_REQBUFS: { - struct v4l2_requestbuffers *req = arg; - printk("ioctl reqbufs\n"); - return videobuf_reqbufs(&fh->vb_vidq, req); + if (i < 0 || i >= MAX_CAPTURE_BUFFERS || + !hrtdev->stream_buf[i].requested || + (buf->type & V4L2_BUF_TYPE_VIDEO_CAPTURE) != + (hrtdev->stream_buf[i].vidbuf.type & V4L2_BUF_TYPE_VIDEO_CAPTURE)) { + hrt_printk("QUERYBUF - bad parameter\n"); + return -EINVAL; } -*/ -/* - case VIDIOC_REQBUFS: { - struct v4l2_requestbuffers *req = arg; - printk("ioctl reqbufs\n"); - - if (!dev->video_dev->vidioc_reqbufs) - break; - return(dev->video_dev->vidioc_reqbufs(file, fh, arg)); + *buf = hrtdev->stream_buf[i].vidbuf; + return 0; + } + case VIDIOC_QBUF: { + struct v4l2_buffer *buf = + (struct v4l2_buffer *) arg; + + if (!hrtdev->stream_buffers_mapped) { + return -EINVAL; } -*/ - case VIDIOC_ENUMSTD: { - struct v4l2_standard *e = arg; - struct v4l2_fract fract = { 1001, 30000 }; - unsigned int index = e->index; - - /* One standard (NTSC) */ - if (index > 0) - return -EINVAL; - - e->id = V4L2_STD_NTSC_M; - e->index = index; - strcpy(e->name, "NTSC"); - e->frameperiod = fract; - e->framelines = dev->win->height; + + if (!hrt_queuebuffer(hrtdev, buf)) { + return -EINVAL; + } + return 0; + } + case VIDIOC_DQBUF: { + struct v4l2_buffer *buf = + (struct v4l2_buffer *) arg; + + if (!hrt_dequeuebuffer(hrtdev, buf)) { + return -EINVAL; + } + return 0; + } + case VIDIOC_STREAMON: { + __u32 *type = (__u32 *) arg; + if (!hrt_streamon(hrtdev, *type)) + return -EINVAL; + return 0; + } + case VIDIOC_STREAMOFF: { + __u32 *type = (__u32 *) arg; + hrt_streamoff(hrtdev, *type); + return 0; + } + + /* Non-streaming ioctl's */ + case VIDIOC_QUERYCAP: { + struct v4l2_capability *b = + (struct v4l2_capability *) arg; + + strcpy(b->driver, "hrt"); + strncpy(b->card, "PS 512-8-PCI", sizeof(b->card)); + /*sprintf(b->bus_info,"PCI:%s", hrtdev->pci_dev->slot_name);*/ + b->version = KERNEL_VERSION(0, 0, 2); + + if (disable_streaming) { + b->capabilities = + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; + } else { + + + b->capabilities = + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + } + return 0; + } + case VIDIOC_ENUM_FMT: { + struct v4l2_fmtdesc *f = arg; + enum v4l2_buf_type type = f->type; + int index = f->index; + + /* There's only one format */ + if (index > 0) + return -EINVAL; + + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + memset(f, 0, sizeof(*f)); + f->index = index; + f->type = type; + if(hrtdev->mode & HRT_COLOR_MODE){ + f->pixelformat = V4L2_PIX_FMT_RGB555; //check this one + strcpy(f->description, "Color"); + } + else{ + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description, "Grey"); + } return 0; + } else { + return -EINVAL; } + } + case VIDIOC_TRY_FMT: + case VIDIOC_S_FMT: + + case VIDIOC_G_FMT: { + struct v4l2_format *f = arg; - default: - ret=video_ioctl2(inode,file,cmd,(unsigned long)arg); - break; + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + + /* memset(&f->fmt.pix, 0, + sizeof(struct v4l2_pix_format));*/ + f->fmt.pix.width = hrtdev->win->width; + f->fmt.pix.height = hrtdev->win->height; + + if(hrtdev->mode & HRT_COLOR_MODE) + f->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB555; + else + f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; + + + //f->fmt.pix.pixelformat = V4L2_FIELD_ANY; + + f->fmt.pix.bytesperline = hrtdev->bytesperline; + f->fmt.pix.sizeimage = hrtdev->framesize; + hrt_printk("pix.width (%d), pic.height (%d)", + f->fmt.pix.width, f->fmt.pix.height); + hrt_printk("pix.bytesperline (%d), pic.sizeimage (%d)", + f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); + return 0; + } else { + return -EINVAL; + } + } + + case VIDIOC_G_CROP: { + struct v4l2_crop * win = arg; + + win->c.height = hrtdev->win->height; + win->c.width = hrtdev->win->width; + win->c.top = hrtdev->win->starty; + win->c.left = hrtdev->win->startx; + + return 0; + } + + case VIDIOC_S_CROP: { + struct v4l2_crop *win = arg; + + hrtdev->win->height = win->c.height; + hrtdev->win->width = win->c.width; + hrtdev->win->starty = win->c.top; + hrtdev->win->startx = win->c.left; + + return 0; + + } + + case VIDIOC_G_STD: { + v4l2_std_id *id = arg; + + *id = V4L2_STD_NTSC; + return 0; + } + case VIDIOC_S_STD: { + /* There's only one standard that we support, NTSC */ + return 0; + } + case VIDIOC_QUERYCTRL: { + struct v4l2_queryctrl *c = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(hrt_ctls); i++) + if (hrt_ctls[i].id == c->id) + break; + + /* Didn't find the id */ + if (i == ARRAY_SIZE(hrt_ctls)) { + return -EINVAL; } - - return ret; + + *c = hrt_ctls[i]; + return 0; + } + case VIDIOC_G_CTRL: { + struct v4l2_control *c = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(hrt_ctls); i++) + if (hrt_ctls[i].id == c->id) + break; + + if (i == sizeof(hrt_ctls)) + return -EINVAL; + + if (c->id == V4L2_CID_BRIGHTNESS) { + /* + c->value = hrtdev->regvals[HRT_BRIGHTNESS_REG]; + */ + c->value = hrtdev->saa7110_registers[HRT_BRIGHTNESS_REG]; + } else if (c->id == V4L2_CID_CONTRAST) { + /* + c->value = hrtdev->regvals[HRT_CONTRAST_REG]; + */ + c->value = hrtdev->saa7110_registers[HRT_BRIGHTNESS_REG]; + + } else { + return -EINVAL; + } + + return 0; + } + case VIDIOC_S_CTRL: { + /* + struct v4l2_control *c = arg; + int i; + + for (i = 0; i < sizeof(hrt_ctls); i++) + if (hrt_ctls[i].id == c->id) + break; + if (i == sizeof(hrt_ctls)) + return -EINVAL; + + if (c->id == V4L2_CID_BRIGHTNESS) { + if (c->value > 255) + return -EINVAL; + c->value = i2c_set_reg(hrtdev, HRT_BRIGHTNESS_REG, + c->value); + } else if (c->id == V4L2_CID_CONTRAST) { + if (c->value > 255) + return -EINVAL; + c->value = i2c_set_reg(hrtdev, HRT_CONTRAST_REG, + c->value); + } else { + return -EINVAL; + } + */ + return 0; + } + case VIDIOC_ENUMINPUT: { + struct v4l2_input *i = arg; + unsigned int n; + + /* Only one input */ + if (i->index > 0) + return -EINVAL; + + n = i->index; + memset(i, 0, sizeof(*i)); + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + sprintf(i->name, "NTSC Camera"); + + return 0; + } + case VIDIOC_ENUMSTD: { + struct v4l2_standard *e = arg; + struct v4l2_fract fract = { 1001, 30000 }; + unsigned int index = e->index; + + /* One standard (NTSC) */ + if (index > 0) + return -EINVAL; + + e->id = V4L2_STD_NTSC_M; + e->index = index; + strcpy(e->name, "NTSC"); + e->frameperiod = fract; + e->framelines = hrtdev->win->height; + + return 0; + } + case VIDIOC_G_PARM: { + struct v4l2_streamparm *parm = arg; + struct v4l2_standard s; + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + memset(parm, 0, sizeof(*parm)); + + v4l2_video_std_construct(&s, V4L2_STD_NTSC, + "NTSC"); + parm->parm.capture.timeperframe = s.frameperiod; + return 0; + } + case VIDIOC_G_INPUT: { + return 0; + } + case VIDIOC_S_INPUT: { + return 0; + } + default: + return -ENOIOCTLCMD; + } + + return 0; } /******************************************************************** @@ -2685,37 +3220,23 @@ int hrt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct hrt_fh *per_file = file->private_data; - struct hrt_dev *dev = per_file->dev; - int ret; - dev->win = &per_file->win; -#if 0 - mutex_lock(&dev->lock); - - ret = hrt_do_private_ioctl(dev, cmd, arg); - if (ret != -EINVAL) { - mutex_unlock(&dev->lock); - // up(&dev->sem); - return ret; - } - #endif - - //ret = video_usercopy(inode, file, cmd, arg, hrt_do_ioctl); - ret = hrt_do_ioctl(inode, file, cmd, (void *)arg); - // mutex_lock(&dev->lock); - - - return ret; -} - -/********************************************************************/ -/** - * hrt_mmap - called by the mmap() system call on /dev/video - */ -int hrt_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct hrt_fh *fh = file->private_data; - return videobuf_mmap_mapper(&fh->vb_vidq, vma); + struct hrt_per_file *per_file = file->private_data; + hrt_t *hrtdev = per_file->hrtdev; + int ret; + hrtdev->win = &per_file->win; + + dprintk("ioctl arg = %lx\n", arg); + + down(&hrtdev->sem); + + ret = hrt_do_private_ioctl(hrtdev, cmd, arg); + if (ret != -EINVAL) { + up(&hrtdev->sem); + return ret; + } + ret = video_usercopy(inode, file, cmd, arg, hrt_do_ioctl); + up(&hrtdev->sem); + return ret; } #ifdef CONFIG_PCI @@ -2731,17 +3252,17 @@ /********************************************************************/ static struct pci_device_id hrt_pci_tbl[] __devinitdata = { - {PCI_DEVICE(HRT_VENDOR_ID, HRT_DEVICE_ID_GREY)}, - {PCI_DEVICE(HRT_VENDOR_ID, HRT_DEVICE_ID_COLOR)}, - {0,} + {PCI_DEVICE(HRT_VENDOR_ID, HRT_DEVICE_ID_GREY)}, + {PCI_DEVICE(HRT_VENDOR_ID, HRT_DEVICE_ID_COLOR)}, + {0,} }; /********************************************************************/ static struct pci_driver hrt_pci_driver = { - .name = "hrt", - .id_table = hrt_pci_tbl, - .probe = hrt_pci_probe, - .remove = __devexit_p(hrt_pci_remove) + .name = "hrt", + .id_table = hrt_pci_tbl, + .probe = hrt_pci_probe, + .remove = __devexit_p(hrt_pci_remove) }; /********************************************************************/ @@ -2749,53 +3270,61 @@ const struct pci_device_id *pci_id) { - HRT_DEBUG_MSG(2, "probing pci device"); - - /* check that this is a type of device we support */ - if ((pci_dev->device != HRT_DEVICE_ID_COLOR) && - (pci_dev->device != HRT_DEVICE_ID_GREY)) { - HRT_ERROR_MSG("unknown device type 0x%hx", - pci_dev->device); - return -ENODEV; - } - - if (hrt_num_devices >= HRT_MAX_DEVICES) { - HRT_ERROR_MSG("need to increase HRT_MAX_DEVICES"); - return -ENOMEM; - } - - - return hrt_init(pci_resource_start(pci_dev, 0), pci_dev); + printk(KERN_ALERT "******I am in PCI Probe ********\n"); + + HRT_DEBUG_MSG(2, "probing pci device"); + + /* check that this is a type of device we support */ + if ((pci_dev->device != HRT_DEVICE_ID_COLOR) && + (pci_dev->device != HRT_DEVICE_ID_GREY)) { + HRT_ERROR_MSG("unknown device type 0x%hx", + pci_dev->device); + return -ENODEV; + } + + if (hrt_num_devices >= HRT_MAX_DEVICES) { + HRT_ERROR_MSG("need to increase HRT_MAX_DEVICES"); + return -ENOMEM; + } + + + return hrt_init(pci_resource_start(pci_dev, 0), pci_dev); } /********************************************************************/ /* since these cards are not intended to be hot-pluggable, - we do not try to reuse hrt_dev objects; we just use the remove + we do not try to reuse hrt_t objects; we just use the remove operation for removal of the device driver module */ void hrt_pci_remove (struct pci_dev *pci_dev) { - struct hrt_dev *dev; - HRT_DEBUG_MSG(2, "hrt_pci_remove"); - dev = (struct hrt_dev *) pci_get_drvdata (pci_dev); - hrt_cleanup(dev); - - pci_disable_device(pci_dev); + + hrt_t *dev; + HRT_DEBUG_MSG(2, "hrt_pci_remove"); + dev = (hrt_t *) pci_get_drvdata (pci_dev); + hrt_cleanup(dev); + + /* Added by Sean/ Atulya 2005.06.14 + video_unregister_device(&dev->video_dev); + now moved to hrt_cleanup + */ + + pci_disable_device(pci_dev); } /********************************************************************/ void hrt_pci_init(void) { - int ret; - HRT_DEBUG_MSG(2, "pci_register_driver"); - ret = pci_register_driver(&hrt_pci_driver); + HRT_DEBUG_MSG(2, "pci_register_driver"); + pci_register_driver(&hrt_pci_driver); } /********************************************************************/ void hrt_pci_cleanup(void) { - HRT_DEBUG_MSG(2, "pci_unregister_driver"); - pci_unregister_driver(&hrt_pci_driver); + hrt_printk( " hrt_pci_cleanup\n"); + HRT_DEBUG_MSG(2, "pci_unregister_driver"); + pci_unregister_driver(&hrt_pci_driver); } #else @@ -2810,7 +3339,7 @@ /********************************************************************/ void hrt_pci_cleanup(void) { - printk( " no pci support hrt_pci_cleanup\n"); + hrt_printk( " no pci support hrt_pci_cleanup\n"); } #endif @@ -2824,63 +3353,390 @@ /********************************************************************/ void hrt_cleanup_module(void) { - HRT_MODULE_CHECK (HRT_MODULE_INITIALIZING_STATE | - HRT_MODULE_INITIALIZED_STATE, "6"); - - hrt_module_state = HRT_MODULE_FINALIZING_STATE; - - HRT_DEBUG_MSG(2, "hrt_cleanup_module"); - - hrt_isa_cleanup(); - - hrt_pci_cleanup(); - - hrt_debug_cleanup(); - - hrt_module_state = HRT_MODULE_UNINITIALIZED_STATE; - + hrt_printk( " initiating hrt_cleanup_module\n"); + HRT_MODULE_CHECK (HRT_MODULE_INITIALIZING_STATE | + HRT_MODULE_INITIALIZED_STATE, "6"); + hrt_module_state = HRT_MODULE_FINALIZING_STATE; + HRT_DEBUG_MSG(2, "hrt_cleanup_module"); + hrt_printk( " calling hrt_isa_cleanup\n"); + hrt_isa_cleanup(); + hrt_printk( " calling hrt_pci_cleanup\n"); + hrt_pci_cleanup(); + hrt_printk( " unregistering the 'hrt' device\n"); + if (hrt_major_number) unregister_chrdev(hrt_major_number, "hrt"); + hrt_printk( " calling hrt_debug_cleanup\n"); + hrt_debug_cleanup(); + hrt_module_state = HRT_MODULE_UNINITIALIZED_STATE; + hrt_printk( " cleanup completed\n"); } /********************************************************************/ int hrt_init_module(void) { - int result = 0; - - hrt_module_state = HRT_MODULE_INITIALIZING_STATE; - hrt_debug_init(); - - /* use major number returned by system if no - major number is specified by this module */ - - if (major_number == 0) hrt_major_number = result; - else hrt_major_number = major_number; - - HRT_ERROR_MSG("module initializing with major number %d", - hrt_major_number); - - /* detect ISA/PC104 devices, and PCI devices that are - jumpered to use the ISA/PC104 I/O address space */ - - hrt_isa_init(); - - testing_isa_mode = 0; - - printk(KERN_ALERT "------------ENTERING PCI MODE!!!!--------------\n"); - - hrt_pci_init(); - - /* now detect regular PCI devices */ - if (hrt_num_devices == 0) { - HRT_ERROR_MSG("no hrt devices detected"); - hrt_module_state = HRT_MODULE_UNINITIALIZED_STATE; - return -ENODEV; - } else { - HRT_ERROR_MSG("found %d hrt devices", hrt_num_devices); - } - hrt_module_state = HRT_MODULE_INITIALIZED_STATE; + int result = 0; + + hrt_module_state = HRT_MODULE_INITIALIZING_STATE; + hrt_debug_init(); + + printk(KERN_ALERT "DAN ->hrt_mdule_state is %d\n", +hrt_module_state); + + /* Added 2005.06.11 Sean/ Atulya + begin */ + memset(hrt_devices, 0, sizeof(hrt_devices)); + + /* use major number returned by system if no + major number is specified by this module */ + if (major_number == 0) hrt_major_number = result; + else hrt_major_number = major_number; + HRT_ERROR_MSG("module initializing with major number %d", + hrt_major_number); + + /* detect ISA/PC104 devices, and PCI devices that are + jumpered to use the ISA/PC104 I/O address space */ + + hrt_isa_init(); + testing_isa_mode = 0; + printk(KERN_ALERT "\n"); + printk(KERN_ALERT "\n"); + printk(KERN_ALERT "\n"); + printk(KERN_ALERT "\n"); + printk(KERN_ALERT "\n"); + printk(KERN_ALERT "------------ENTERING PCI MODE!!!!--------------\n"); + printk(KERN_ALERT "\n"); + printk(KERN_ALERT "\n"); + printk(KERN_ALERT "\n"); + printk(KERN_ALERT "\n"); + printk(KERN_ALERT "\n"); + hrt_pci_init(); - return 0; + + + + /* now detect regular PCI devices */ + if (hrt_num_devices == 0) { + HRT_ERROR_MSG("no hrt devices detected"); + hrt_module_state = HRT_MODULE_UNINITIALIZED_STATE; + return -ENODEV; + } else { + HRT_ERROR_MSG("found %d hrt devices", hrt_num_devices); + } + hrt_module_state = HRT_MODULE_INITIALIZED_STATE; + printk(KERN_ALERT "DAN ->hrt_mdule_state is %d\n", +hrt_module_state); + /* I am done probling change global state */ + cleanup_context = 1; + + return 0; +} + +/********************************************************************/ +/** + * hrt_vma_open - increments reference count + */ +static void hrt_vma_open(struct vm_area_struct *vma) +{ + struct video_device *vdev = video_devdata(vma->vm_file); + hrt_t *hrtdev = vdev->priv; + struct stream_buffer *buf; + + hrt_printk( "hrt_vma_open\n"); + if (hrtdev == NULL) + return; + buf = mmap_stream_buffer_from_offset(hrtdev, vma->vm_pgoff); + if (buf == NULL) + return; + else { + hrt_printk("hrt_vma_open : buf allocated at (0x%lx)", (unsigned long)buf); + } + + buf->vma_refcount++; + +} + +/********************************************************************/ +/** + * hrt_vma_close - decrements reference count of a stream buffer + */ +static void hrt_vma_close(struct vm_area_struct *vma) +{ + struct video_device *vdev = video_devdata(vma->vm_file); + hrt_t *hrtdev = vdev->priv; + struct stream_buffer *buf; + + if (hrtdev == NULL) + return; + + buf = mmap_stream_buffer_from_offset(hrtdev, vma->vm_pgoff); + buf->vma_refcount--; + + if (buf->vma_refcount > 0) { + return; + } + if (hrtdev->streaming) { + hrt_printk(KERN_WARNING "munmap() called while streaming\n"); + hrt_streamoff(hrtdev, buf->vidbuf.type); + } + if (buf->vaddress != NULL) { + vfree(buf->vaddress); + buf->vaddress = NULL; + } + buf->vidbuf.flags = 0; + + if (hrtdev->stream_buffers_mapped > 0) + hrtdev->stream_buffers_mapped--; +} + +/********************************************************************/ +/** + * hrt_vma_nopage - calls kvirt_to_pa to convert the vaddress in the + * stream buffer (indexed via the offset parameter to mmap()) to + * a page number for access from userspace + */ +struct page *hrt_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int * type) +{ + struct video_device *vdev = video_devdata(vma->vm_file); + hrt_t *hrtdev = vdev->priv; + + struct stream_buffer *buf; + unsigned long offset_into_buf; + struct page *page; + + buf = mmap_stream_buffer_from_offset(hrtdev, vma->vm_pgoff); + if (buf == NULL) + return 0; + offset_into_buf = address - vma->vm_start; + if (offset_into_buf >= buf->vidbuf.length) { + hrt_printk("Attempt to read past end of mmap() buffer\n"); + return 0; + } + page = vmalloc_to_page(buf->vaddress + offset_into_buf); + if (page != NULL) + atomic_inc(&page->_count); + return page; +} + + +/********************************************************************/ +/** + * hrt_vm_ops - vm operations on /dev/video + */ +struct vm_operations_struct hrt_vm_ops = { + .open = hrt_vma_open, + .close = hrt_vma_close, + .nopage = hrt_vma_nopage, +}; + + +/********************************************************************/ +int hrt_queuebuffer( hrt_t *hrtdev, + struct v4l2_buffer *vidbuf) +{ + int i = vidbuf->index; + struct stream_buffer *buf = NULL; + + if ( !(hrtdev->stream_buffers_mapped) ) { + return 0; + } + if (vidbuf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + hrt_printk("QBUF - wrong type (type = %x)\n", vidbuf->type); + return 0; + } + if (i < 0 || i >= MAX_CAPTURE_BUFFERS + || !hrtdev->stream_buf[i].requested) { + hrt_printk("QBUF - buffer index %d is out of range\n", i); + return 0; + } + buf = &hrtdev->stream_buf[i]; + + hrt_printk("hrt_queuebuffer : buf (0x%lx)", (unsigned long)buf); + + if (!(buf->vidbuf.flags & V4L2_BUF_FLAG_MAPPED)) { + hrt_printk("QBUF - buffer %d is not mapped\n", i); + return 0; + } + if ((buf->vidbuf.flags & V4L2_BUF_FLAG_QUEUED)) { + hrt_printk("QBUF - buffer %d is already queued\n", i); + return 0; + } + buf->vidbuf.flags &= ~V4L2_BUF_FLAG_DONE; + do_gettimeofday(&buf->vidbuf.timestamp); + + queue_add_tail(buf, &hrtdev->capture_list); + buf->vidbuf.flags |= V4L2_BUF_FLAG_QUEUED; + return 1; +} + + +/********************************************************************/ +/** + * hrt_dequeuebuffer - called by the DQBUF ioctl. + * Returns a buffer from the done queue. + */ +int hrt_dequeuebuffer(hrt_t *hrtdev, + struct v4l2_buffer *buf) +{ + struct stream_buffer *newbuf; + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + hrt_printk("DQBUF - Wrong buffer type\n"); + return 0; + } + newbuf = queue_del_head(&hrtdev->done_list); + if (newbuf == NULL) { + hrt_printk("DQBUF - No buffers on done queue\n"); + return 0; + } + newbuf->vidbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; + *buf = newbuf->vidbuf; + + return 1; } + +/********************************************************************/ +/** + * mmap_request_buffers - called by the ioctl REQBUF to request buffers + */ +int mmap_request_buffers(hrt_t *dev, struct v4l2_requestbuffers *req) +{ + int i; + u32 buflen; + u32 type; + + if (req->count < 1) + req->count = 1; + if (req->count > MAX_CAPTURE_BUFFERS) + req->count = MAX_CAPTURE_BUFFERS; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* The buffer length needs to be a multiple of the page size */ + buflen = (dev->framesize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + hrt_printk("Granting %d buffers, buflen (%d)\n", req->count, buflen); + + /* Now initialize the buffer structures. Don't allocate the + buffers until they're mapped. */ + for (i = 0; i < req->count; i++) { + dev->stream_buf[i].requested = 1; + dev->stream_buf[i].vidbuf.index = i; + dev->stream_buf[i].vidbuf.type = type; + /* offset must be unique for each buffer, and a multiple + of PAGE_SIZE on 2.4.x */ + dev->stream_buf[i].vidbuf.m.offset = PAGE_SIZE * (i + 1); + dev->stream_buf[i].vidbuf.length = buflen; + dev->stream_buf[i].vidbuf.bytesused = 0; + dev->stream_buf[i].vidbuf.flags = 0; + /* XXX: should set timestamp? */ + dev->stream_buf[i].vidbuf.sequence = 0; + dev->stream_buf[i].vma_refcount = 0; + dev->stream_buf[i].vaddress = NULL; + memset(&dev->stream_buf[i].vidbuf.timecode, 0, + sizeof(struct v4l2_timecode)); + } + for (i = req->count; i < MAX_CAPTURE_BUFFERS; i++) + dev->stream_buf[i].requested = 0; + dev->stream_buffers_requested = req->count; + + return 1; +} + +/********************************************************************/ +/** + * hrt_mmap - called by the mmap() system call on /dev/video + */ +int hrt_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *dev = video_devdata(file); + hrt_t *hrtdev = dev->priv; + struct stream_buffer *buf = NULL; + + down(&hrtdev->sem); + + hrt_printk("hrt_mmap\n"); + + if (next_mmap_is_direct) { + int ret; + next_mmap_is_direct = 0; + ret = hrt_direct_mmap(file, vma); + up(&hrtdev->sem); + return ret; + } + + buf = mmap_stream_buffer_from_offset(hrtdev, vma->vm_pgoff); + + if (buf == NULL) { + hrt_printk("mmap() - Invalid offset parameter\n"); + up(&hrtdev->sem); + return -EINVAL; + } + if (buf->vidbuf.length != vma->vm_end - vma->vm_start) { + hrt_printk("mmap() - Bad length parameter\n"); + up(&hrtdev->sem); + return -EINVAL; + } + if (!buf->requested) { + hrt_printk("mmap() - Buffer is not available for mapping\n"); + up(&hrtdev->sem); + return -EINVAL; + } + if (buf->vidbuf.flags & V4L2_BUF_FLAG_MAPPED) { + hrt_printk("mmap() - Buffer is already mapped\n"); + up(&hrtdev->sem); + return -EINVAL; + } + if (buf->vaddress != NULL) + vfree(buf->vaddress); + /* + * Allocate virtual memory. This memory is mapped to the + * buffer in user space. + */ + buf->vaddress = vmalloc(buf->vidbuf.length); + if (buf->vaddress == NULL) { + hrt_printk("Could not allocate mmap() buffer\n"); + up(&hrtdev->sem); + return -ENODEV; + } + else { + hrt_printk("Successfully allocated mmap() buffer\n"); + } + + buf->vidbuf.flags |= V4L2_BUF_FLAG_MAPPED; + hrtdev->stream_buffers_mapped++; + vma->vm_ops = &hrt_vm_ops; + if (vma->vm_ops->open) + vma->vm_ops->open(vma); + + up(&hrtdev->sem); + return 0; +} + +/********************************************************************/ +/** + * hrt_streamon - called by the STREAMON ioctl. + */ +int hrt_streamon(hrt_t *hrtdev, __u32 type) +{ + struct stream_buffer *buf; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + printk("STREAMON - Wrong buffer type\n"); + return 0; + } + + /* Move any leftover done buffers to the free pool */ + while ((buf = queue_del_head(&hrtdev->done_list))) + buf->vidbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; + + hrtdev->streaming = 1; + hrt_printk("Streaming is turned on\n"); + + return 1; +} + +/********************************************************************/ +/*MODULE_LICENSE("GPL");*/ + module_init(hrt_init_module); module_exit(hrt_cleanup_module); + +