Re: [V4L] videodev2 + 2.4.0test8

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



> 1) Read the docs on the v4l2 page - videodev2 is not 2.4.0 capable.
OK. I should have read more carefully.

> 2) Download videodevX package from http://bttv-v4l2.sourceforge.net/
> 
> The videodevX package Supports v4l1 and v4l2 and should work on 2.4.0
> series kernels.
It doesn't compile out of the box (videodevX-050900), attached is the
patch that makes it work for me. All the code i wrote is ifdef'ed
LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0), the original code is
untouched.
Apparently it works fine. Just one question:
does anybody know which is the equivalent of "struct
vm_area_struct.vm_offset" in newer kernels?
i've used vm_pgoff*PAGE_SIZE, but i don't really know if that's correct.

The driver itself (bttv2) does compile and work fine.

regards,
Iñaki

--- videodevX.c	Tue Sep  5 08:49:08 2000
+++ videodevX.c	Sun Oct  1 18:16:49 2000
@@ -362,6 +362,14 @@
 	return -EINVAL;
 }
 
+/* forward declarations */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+ static void videodev_proc_create_dev (struct video_device *vfd, char *name);
+ static void videodev_proc_destroy_dev (struct video_device *vfd);
+#endif
+#endif
+
 /*
  *	Video For Linux device drivers request registration here.
  */
@@ -372,24 +380,29 @@
 	int base;
 	int err;
 	int end;
+	char *name_base;
 	
 	switch(type)
 	{
 		case VFL_TYPE_GRABBER:
 			base=0;
 			end=64;
+			name_base = "video";
 			break;
 		case VFL_TYPE_VTX:
 			base=192;
 			end=224;
+			name_base = "vtx";
 			break;
 		case VFL_TYPE_VBI:
 			base=224;
 			end=240;
+			name_base = "vbi";
 			break;
 		case VFL_TYPE_RADIO:
 			base=64;
 			end=128;
+			name_base = "radio";
 			break;
 		default:
 			return -1;
@@ -399,6 +412,8 @@
 	{
 		if((video_device[i]==NULL)&&(v4l2_device[i]==NULL))
 		{
+			char name[16];
+
 			video_device[i]=vfd;
 			vfd->minor=i;
 			/* The init call may sleep so we book the slot out
@@ -414,6 +429,13 @@
 					return err;
 				}
 			}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+			sprintf (name, "%s%d", name_base, i - base);
+			videodev_proc_create_dev (vfd, name);
+#endif
+#endif
 			return 0;
 		}
 	}
@@ -428,14 +450,17 @@
 {
 	if(video_device[vfd->minor]!=vfd)
 		panic("vfd: bad unregister");
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	videodev_proc_destroy_dev (vfd);
+#endif
+#endif
+
 	video_device[vfd->minor]=NULL;
 	MOD_DEC_USE_COUNT;
 }
 
-
-
-
-
 /*
  *	Active devices 
  */
@@ -657,14 +682,23 @@
 		/*  For v4l compatibility. v4l apps typically pass zero	*/
 		/*  for the offset, so replace it with the real value	*/
 		/*  saved from before					*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 		if (vma->vm_offset == 0 && vfl->ioctl)
+#else
+		if (vma->vm_pgoff == 0 && vfl->ioctl)
+#endif
 		{
 			struct v4l2_buffer buf;
 			buf.index = 0;
 			buf.type = V4L2_BUF_TYPE_CAPTURE;
 			if (vfl->ioctl(file->private_data,
 				       VIDIOC_QUERYBUF, &buf) == 0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 				vma->vm_offset = buf.offset;
+#else
+			/* FIXME: where is vm_offset in newer kernels? */
+				vma->vm_pgoff = buf.offset/PAGE_SIZE;
+#endif
 		}
 		err = vfl->mmap(file->private_data, vma);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,3)
@@ -914,6 +948,7 @@
 
 #ifndef HAVE_DO_SELECT
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 /*  Note: This code, inside the #ifndef HAVE_DO_SELECT ... #endif,
     is copied from fs/select.c, and is only included
     here because do_select() is not exported to modules. In the future
@@ -1016,6 +1051,145 @@
 	unlock_kernel();
 	return retval;
 }
+#else // KERNEL_VERSION < 2.4.0
+#include <linux/smp_lock.h>
+#include <linux/file.h>
+
+#define MEM(i,m)	((m)+(unsigned)(i)/__NFDBITS)
+#define ISSET(i,m)	(((i)&*(m)) != 0)
+
+#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
+
+#undef __IN
+#undef __OUT
+#define __IN(fds, n)		(fds->in + n)
+#define __OUT(fds, n)		(fds->out + n)
+#define __EX(fds, n)		(fds->ex + n)
+#define __RES_IN(fds, n)	(fds->res_in + n)
+#define __RES_OUT(fds, n)	(fds->res_out + n)
+#define __RES_EX(fds, n)	(fds->res_ex + n)
+
+#define BITS(fds, n)		(*__IN(fds, n)|*__OUT(fds, n)|*__EX(fds, n))
+
+#define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR)
+#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
+#define POLLEX_SET (POLLPRI)
+/*  This stuff comes from the fs/select.c present in a 2.0.0test8 */
+/*  kernel. It should be kept in sync with that. */
+static int my_max_select_fd(unsigned long n, fd_set_bits *fds)
+{
+	unsigned long *open_fds;
+	unsigned long set;
+	int max;
+
+	/* handle last in-complete long-word first */
+	set = ~(~0UL << (n & (__NFDBITS-1)));
+	n /= __NFDBITS;
+	open_fds = current->files->open_fds->fds_bits+n;
+	max = 0;
+	if (set) {
+		set &= BITS(fds, n);
+		if (set) {
+			if (!(set & ~*open_fds))
+				goto get_max;
+			return -EBADF;
+		}
+	}
+	while (n) {
+		open_fds--;
+		n--;
+		set = BITS(fds, n);
+		if (!set)
+			continue;
+		if (set & ~*open_fds)
+			return -EBADF;
+		if (max)
+			continue;
+get_max:
+		do {
+			max++;
+			set >>= 1;
+		} while (set);
+		max += n * __NFDBITS;
+	}
+
+	return max;
+}
+
+static int 
+my_do_select(int n, fd_set_bits *fds, long *timeout)
+{
+	poll_table table, *wait;
+	int retval, i, off;
+	long __timeout = *timeout;
+
+ 	read_lock(&current->files->file_lock);
+	retval = my_max_select_fd(n, fds);
+	read_unlock(&current->files->file_lock);
+
+	if (retval < 0)
+		return retval;
+	n = retval;
+
+	poll_initwait(&table);
+	wait = &table;
+	if (!__timeout)
+		wait = NULL;
+	retval = 0;
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		for (i = 0 ; i < n; i++) {
+			unsigned long bit = BIT(i);
+			unsigned long mask;
+			struct file *file;
+
+			off = i / __NFDBITS;
+			if (!(bit & BITS(fds, off)))
+				continue;
+			file = fget(i);
+			mask = POLLNVAL;
+			if (file) {
+				mask = DEFAULT_POLLMASK;
+				if (file->f_op && file->f_op->poll)
+					mask = file->f_op->poll(file, wait);
+				fput(file);
+			}
+			if ((mask & POLLIN_SET) && ISSET(bit, __IN(fds,off))) {
+				SET(bit, __RES_IN(fds,off));
+				retval++;
+				wait = NULL;
+			}
+			if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(fds,off))) {
+				SET(bit, __RES_OUT(fds,off));
+				retval++;
+				wait = NULL;
+			}
+			if ((mask & POLLEX_SET) && ISSET(bit, __EX(fds,off))) {
+				SET(bit, __RES_EX(fds,off));
+				retval++;
+				wait = NULL;
+			}
+		}
+		wait = NULL;
+		if (retval || !__timeout || signal_pending(current))
+			break;
+		if(table.error) {
+			retval = table.error;
+			break;
+		}
+		__timeout = schedule_timeout(__timeout);
+	}
+	current->state = TASK_RUNNING;
+
+	poll_freewait(&table);
+
+	/*
+	 * Up-to-date the caller timeout.
+	 */
+	*timeout = __timeout;
+	return retval;
+}
+#endif // KERNEL_VERSION 2.4.0
 #endif // HAVE_DO_SELECT
 
 static int
@@ -1056,7 +1230,11 @@
 	memset(bits, 0, 6 * size);
 	SET(BIT(fd), __FD_IN((&fds), fd / __NFDBITS));
 
+#ifndef HAVE_DO_SELECT
 	ret = my_do_select(n, &fds, &timeout);
+#else
+	ret = do_select(n, &fds, &timeout);
+#endif
 
 	if (ret < 0)
 		goto out;
@@ -1774,8 +1952,7 @@
 	MOD_DEC_USE_COUNT;
 }
 
-
-#ifdef CONFIG_PROC_FS
+#if defined(CONFIG_PROC_FS) && (defined(CONFIG_VIDEO_PROC_FS) || (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)))
 /*
  *	/ p r o c / v i d e o d e v   H A N D L E R
  */
@@ -1787,8 +1964,11 @@
 	"vbi",		"vtr",		"teletext",	"radio", 
 	"undef",	"undef",	"undef",	"undef",
 };
+
+/*  Code common to 2.4.0 and pre2.4.0 implementations. */
 static int
-video_read_proc(char *buf, char **start, off_t offset, int len, int unused)
+video_build_proc(char *buf, char **start, off_t offset, int len,
+		 void *data)
 {
 	struct v4l2_device *vfl;
 	struct video_device *vfl1;
@@ -1832,12 +2012,133 @@
 	return len;
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+static int
+video_read_proc(char *buf, char **start, off_t offset, int len, int unused)
+{
+	return video_build_proc(buf, start, offset, len, unused);
+}
+
+struct videodev_proc_data {
+	struct list_head proc_list;
+	char name[16];
+	struct video_device *vdev;
+	struct proc_dir_entry *proc_entry;
+};
+
 /* proc file for /proc/videodev */
 static struct proc_dir_entry video_proc_entry =
 {
 	0, 8, "videodev", S_IFREG | S_IRUGO, 1, 0, 0, 0, NULL,
 	&video_read_proc
 };
+
+#else // LINUX_VERSION_CODE >= 2.4.0
+struct videodev_proc_data {
+	struct list_head proc_list;
+	char name[16];
+	struct video_device *vdev;
+	struct proc_dir_entry *proc_entry;
+};
+
+static struct proc_dir_entry *video_dev_proc_entry = NULL;
+struct proc_dir_entry *video_proc_entry = NULL;
+EXPORT_SYMBOL(video_proc_entry);
+LIST_HEAD(videodev_proc_list);
+
+static int videodev_proc_read(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	int len = video_build_proc(page, start, off, count, data);
+
+	/* FIXME: Why does the videodev.c included in kernel do this? */
+	len -= off;
+
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0)
+			return 0;
+	}
+	else
+		len = count;
+
+	*start = page + off;
+
+	return len;
+}
+
+static void videodev_proc_create(void)
+{
+	video_proc_entry = create_proc_entry("video", S_IFDIR, &proc_root);
+
+	if (video_proc_entry == NULL) {
+		printk("video_dev: unable to initialise /proc/video\n");
+		return;
+	}
+
+	video_proc_entry->owner = THIS_MODULE;
+	video_dev_proc_entry = create_proc_entry("dev", S_IFDIR, video_proc_entry);
+
+	if (video_dev_proc_entry == NULL) {
+		printk("video_dev: unable to initialise /proc/video/dev\n");
+		return;
+	}
+
+	video_dev_proc_entry->owner = THIS_MODULE;
+}
+
+#ifdef MODULE
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+static void videodev_proc_destroy(void)
+{
+	if (video_dev_proc_entry != NULL)
+		remove_proc_entry("dev", video_proc_entry);
+
+	if (video_proc_entry != NULL)
+		remove_proc_entry("video", &proc_root);
+}
+#endif
+#endif
+
+static void videodev_proc_create_dev (struct video_device *vfd, char *name)
+{
+	struct videodev_proc_data *d;
+	struct proc_dir_entry *p;
+
+	if (video_dev_proc_entry == NULL)
+		return;
+
+	d = kmalloc (sizeof (struct videodev_proc_data), GFP_KERNEL);
+	if (!d)
+		return;
+
+	p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry);
+	p->data = vfd;
+	p->read_proc = videodev_proc_read;
+
+	d->proc_entry = p;
+	d->vdev = vfd;
+	strcpy (d->name, name);
+
+	list_add (&d->proc_list, &videodev_proc_list);
+}
+
+static void videodev_proc_destroy_dev (struct video_device *vfd)
+{
+	struct list_head *tmp;
+	struct videodev_proc_data *d;
+
+	list_for_each (tmp, &videodev_proc_list) {
+		d = list_entry(tmp, struct videodev_proc_data, proc_list);
+		if (vfd == d->vdev) {
+			remove_proc_entry(d->name, video_dev_proc_entry);
+			list_del (&d->proc_list);
+			kfree (d);
+			break;
+		}
+	}
+}
+#endif
 #endif
 
 /*
@@ -1846,6 +2147,7 @@
 
 static struct file_operations video_fops =
 {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 	v4l2_video_llseek,
 	v4l2_video_read,
 	v4l2_video_write,
@@ -1858,6 +2160,17 @@
 	NULL,
 #endif
 	v4l2_video_release
+#else // LINUX_VERSION_CODE >= 2.4.0
+	owner:		THIS_MODULE,
+	llseek:		v4l2_video_llseek,
+	read:		v4l2_video_read,
+	write:		v4l2_video_write,
+	ioctl:		v4l2_video_ioctl,
+	mmap:		v4l2_video_mmap,
+	open:		v4l2_video_open,
+	release:	v4l2_video_release,
+	poll:		v4l2_video_poll
+#endif
 };
 
 /*
@@ -1883,9 +2196,16 @@
 		v4l2_device[i] = NULL;
 	for (i = 0; i < VIDEO_NUM_DEVICES; i++)
 		video_device[i] = NULL;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 #ifdef CONFIG_PROC_FS
 	proc_register(&proc_root, &video_proc_entry);
 #endif
+#else // KERNEL >= 2.4.0
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	videodev_proc_create ();
+#endif
+#endif
+
 	masterclock = NULL;
 
 	while(vfli->init!=NULL)
@@ -1905,9 +2225,16 @@
 
 void cleanup_module(void)
 {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 #ifdef CONFIG_PROC_FS
 	proc_unregister(&proc_root, video_proc_entry.low_ino);
 #endif
+#else // KERNEL >= 2.4.0
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	videodev_proc_destroy ();
+#endif
+#endif
+
 	unregister_chrdev(VIDEO_MAJOR, "v4l1/2");
 }
 #endif


[Index of Archives]     [Linux DVB]     [Video Disk Recorder]     [Asterisk]     [Photo]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Free Photo Albums]     [Fedora Users]     [Fedora Women]     [ALSA Users]     [ALSA Devel]     [Linux USB]

Powered by Linux