Thanks for your answer,

a few problems though:
> The videodevX package Supports v4l1 and v4l2 and should work on 2.4.0
> series kernels.
It needed some hacking to get it to work. Attached is the patch
against  videodevX-050900.tgz. It works for me (2.4.0test8 kernel), and
all the code I introduced is ifdef'ed KERNEL_VERSION >= 2.4.0. The only
missing thing is /proc filesystem support for devices registered with
v4l2_register_device (video_register_device has /proc support).

Just one problem. In the original driver vm_area_struct.vm_offset is
used. Since that doesn't appear to exist in newer kernels, i've used
vm_area_struct.vm_pgoff*PAGE_SIZE, but i don't really know if that's
correct. I works with videodevX+bttv and videodevX+bttv2, though.

The bttv2 driver compiled without problems.

regards,
I�aki

PD: I've noticed some possible bugs in the bttv2 driver. Should I mail
them to you directly or to the list?
--- 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

Reply via email to