3.5. Reading The Video Image


static long camera_read(struct video_device *dev, char *buf,
                                unsigned long count)
{
        struct wait_queue wait = { current, NULL };
        u8 *ptr;
        int len;
        int i;

        add_wait_queue(&capture_wait, &wait);

        while(!capture_ready)
        {
                if(file->flags&O_NDELAY)
                {
                        remove_wait_queue(&capture_wait, &wait);
                        current->state = TASK_RUNNING;
                        return -EWOULDBLOCK;
                }
                if(signal_pending(current))
                {
                        remove_wait_queue(&capture_wait, &wait);
                        current->state = TASK_RUNNING;
                        return -ERESTARTSYS;
                }
                schedule();
                current->state = TASK_INTERRUPTIBLE;
        }
        remove_wait_queue(&capture_wait, &wait);
        current->state = TASK_RUNNING;

  

The first thing we have to do is to ensure that the application waits until the next frame is ready. The code here is almost identical to the mouse code we used earlier in this chapter. It is one of the common building blocks of Linux device driver code and probably one which you will find occurs in any drivers you write.

We wait for a frame to be ready, or for a signal to interrupt our waiting. If a signal occurs we need to return from the system call so that the signal can be sent to the application itself. We also check to see if the user actually wanted to avoid waiting - ie if they are using non-blocking I/O and have other things to get on with.

Next we copy the data from the card to the user application. This is rarely as easy as our example makes out. We will add capture_w, and capture_h here to hold the width and height of the captured image. We assume the card only supports 24bit RGB for now.



        capture_ready = 0;

        ptr=(u8 *)buf;
        len = capture_w * 3 * capture_h; /* 24bit RGB */

        if(len>count)
                len=count;  /* Doesn't all fit */

        for(i=0; i<len; i++)
        {
                put_user(inb(io+IMAGE_DATA), ptr);
                ptr++;
        }

        hardware_restart_capture();
                
        return i;
}

  

For a real hardware device you would try to avoid the loop with put_user(). Each call to put_user() has a time overhead checking whether the accesses to user space are allowed. It would be better to read a line into a temporary buffer then copy this to user space in one go.

Having captured the image and put it into user space we can kick the card to get the next frame acquired.