News:

Registered a URL and setup a forum as the IPCam stuff really needed its own site vs my irregular blog posts about IPCam hacking at http://www.computersolutions.cn/blog

Author Topic: Compiling in WebCam Device Drivers  (Read 4565 times)

  • No avatar
  • *****
June 19, 2011, 05:33:07 am
So, you have a working kernel, and you want some video?

Ok, so you need some device drivers.

Unfortunately we're on an ancient kernel, and all the love and joy is going to others.
What to do?

Backport...


First - we need to know what device we have (from a USB perspective).
Mine is a PixArt device, but I also have a Sonix zc3xx based one.

We can find this out by looking at the USB id's shown during boot.

If you miss these, you can always use dmesg to check the boot log (assuming you have that compiled in also!).

All files in this tutorial are available at http://www.openipcam.com/files/Tutorials/WebCam

So, lets start.


First up, we need to add a USB kernel patch to our usb drivers folder, so that we have the spca5xx drivers for our webcam.  I got this from the mxhard.fr site, which of course is blocked in China.  Joy.

http://mxhaard.free.fr/spca50x/embedded/KernelPatch/usb-2.4.31LE06.patch.tar.gz


Go to the uClinux-dist/linux-2.4.x/drivers/usb folder

and download the patch from there, or from the tutorial folder, and unzip

Now patch the files

patch -p1 < usb-2.4.31.patch

It will ask about reversing, say no (this is the default), and then ask if you want to go ahead and make the changes (say yes).

It will now tell you that its done, and it had 2 issues.

Take a look at Config.in.rej and Makefile.rej

Code: [Select]
cat Config.in.rej
--- Config.in 2004-02-19 15:14:06.000000000 +0100
+++ Config.in 2005-11-25 21:11:03.000000000 +0100
@@ -76,6 +76,7 @@
       dep_tristate '  USB Konica Webcam support' CONFIG_USB_KONICAWC $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
+      dep_tristate '  USB SPCA5XX Sunplus Vimicro Sonix Cameras' CONFIG_USB_SPCA5XX $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB W996[87]CF Camera support' CONFIG_USB_W9968CF $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_I2C

Config.in.rej actually worked, but its not identical to our Config.in, so it says it failed.
The Patch file adds the SPCA5XX line to the Config.in file.

Check to make sure thats there.

Code: [Select]
grep SPCA5 Config.ingrep SPCA5 Config.in
      dep_tristate '  USB SPCA5XX Sunplus Vimicro Sonix Cameras' CONFIG_USB_SPCA5XX $CONFIG_USB $CONFIG_VIDEO_DEV

Yup, so we can forget that one.

How about the Makefile?

Code: [Select]
cat Makefile.rej
--- Makefile 2004-02-19 15:14:06.000000000 +0100
+++ Makefile 2005-11-13 13:02:18.000000000 +0100
@@ -77,6 +77,11 @@
  obj-y += host/usb-ohci.o
 endif
 
+subdir-$(CONFIG_USB_SPCA5XX) += spca5xx
+ifeq ($(CONFIG_USB_SPCA5XX),y)
+ obj-y += spca5xx/spca5xx.o
+endif
+
 subdir-$(CONFIG_USB_SL811HS_ALT) += host
 subdir-$(CONFIG_USB_SL811HS) += host

That looks like it adds the CONFIG_USB_SPCA5XX to our Makefile.  Lets check.
Nope, it didn't, so we need to add that in manually.

Add the below

Code: [Select]
subdir-$(CONFIG_USB_SPCA5XX)    += spca5xx
ifeq ($(CONFIG_USB_SPCA5XX),y)
        obj-y += spca5xx/spca5xx.o
endif

..above this line near the bottom of the Makefile

Code: [Select]
include $(TOPDIR)/Rules.make

Save.


Good, now we need to patch the spca5xx folder files, as we have 2.4.20, and our kernel is still missing stuff it would like.

Code: [Select]
cd spca5xx
We need to change the spca_core.c file slightly to compile.
There are 3 changes needed.

Find this:

Code: [Select]
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22)
static struct usb_driver spca5xx_driver = {
.owner = THIS_MODULE,
.name = "spca5xx",
.id_table = device_table,
.probe = spca5xx_probe,
.disconnect = spca5xx_disconnect
};
#else
static struct usb_driver spca5xx_driver = {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)
THIS_MODULE,
#endif
"spca5xx",
spca5xx_probe,
spca5xx_disconnect,
{NULL,NULL}
};
#endif


And replace that entire text with this:
Code: [Select]
static struct usb_driver spca5xx_driver = {
name: "spca5xx",
id_table: device_table,
probe: spca5xx_probe,
disconnect: spca5xx_disconnect
};


Next, find this:
Code: [Select]
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
static int
spca5xx_probe (struct usb_interface *intf, const struct usb_device_id *id)
#else
static void *
spca5xx_probe (struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
#endif

And replace that entire text with this:
Code: [Select]
static void *
spca5xx_probe (struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)


Save that, and lets try it out.

change to your main uClinux folder, and

make menuconfig
select Customise Kernel Settings
Exit, Exit, Say yes to do you wish to save your new kernel configuration.

You'll now see the Kernel Configuration page.
Lets see if our Drivers are there.

Go to Multimedia Devices, and make sure V4L is checked.
Exit back a page, then go to USB Devices, and check USB SPCA5XX.
Exit, Exit, Say yes to do you wish to Save.

Now, lets see if that worked.

Code: [Select]
make dep
make

Oh no, it didn't work.

Code: [Select]
make[4]: Entering directory `/home2/NUVO/uClinux-dist/linux-2.4.x/drivers/usb/spca5xx'
arm-elf-gcc -D__KERNEL__ -I/home2/NUVO/uClinux-dist/linux-2.4.x/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fno-common -pipe -fno-builtin -D__linux__ -DNO_MM -mapcs-32 -march=armv4 -mtune=arm7tdmi -mshort-load-bytes -DMODULE  -nostdinc -iwithprefix include -DKBUILD_BASENAME=spca_core  -c -o spca_core.o spca_core.c
spca_core.c: In function `kvirt_to_pa':
spca_core.c:598: structure has no member named `pgd'
make[4]: *** [spca_core.o] Error 1
make[4]: Leaving directory `/home2/NUVO/uClinux-dist/linux-2.4.x/drivers/usb/spca5xx'
make[3]: *** [_modsubdir_spca5xx] Error 2
make[3]: Leaving directory `/home2/NUVO/uClinux-dist/linux-2.4.x/drivers/usb'
make[2]: *** [_modsubdir_usb] Error 2
make[2]: Leaving directory `/home2/NUVO/uClinux-dist/linux-2.4.x/drivers'
make[1]: *** [_mod_drivers] Error 2
make[1]: Leaving directory `/home2/NUVO/uClinux-dist/linux-2.4.x'
make: *** [modules] Error 2

Lets go see why - remember to change back to the spca5xx folder first though.

Code: [Select]
cd uClinux-dist/linux-2.4.x/drivers/usb/spca5xx

Its complaining about pgd in kvirt_to_pa.
Any idea?

Here's a hint.  armnommu.

Still no idea?  tsk tsk.

Our SoC has no MMU, so we don't have virtual paging to deal with.
So, lets take a look at another driver in our BSP, and see how they do it in that.

ov511.c uses kvirt_to_pa, and does it this way
Code: [Select]
static inline unsigned long
kvirt_to_pa(unsigned long adr)
{
        unsigned long kva, ret;

        kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
        kva |= adr & (PAGE_SIZE-1); /* restore the offset */
        ret = __pa(kva);
        return ret;
}

I'll bet if we replaced the equivalent code in the spca_core.c file that would work.

Open up spca_core.c
Find kvirt_to_pa

Replace all this text:
Code: [Select]
#ifdef RH9_REMAP
static inline unsigned long
kvirt_to_pa (unsigned long adr)
{
  unsigned long kva, ret;

  kva = (unsigned long) page_address (vmalloc_to_page ((void *) adr));
  kva |= adr & (PAGE_SIZE - 1); /* restore the offset */
  ret = __pa (kva);
  return ret;
}

#else /* RH9_REMAP */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
static inline unsigned long
kvirt_to_pa (unsigned long adr)
{
  unsigned long kva, ret;

  kva = (unsigned long) page_address (vmalloc_to_page ((void *) adr));
  kva |= adr & (PAGE_SIZE - 1);
  ret = __pa (kva);
  return ret;
}
#else
static inline unsigned long
kvirt_to_pa (unsigned long adr)
{
  unsigned long va, kva, ret;

  va = VMALLOC_VMADDR (adr);
  kva = uvirt_to_kva (pgd_offset_k (va), va);
  ret = __pa (kva);
  return ret;
}
#endif
#endif /* RH9_REMAP */

with this:

Code: [Select]
static inline unsigned long
kvirt_to_pa(unsigned long adr)
{
        unsigned long kva, ret;

        kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
        kva |= adr & (PAGE_SIZE-1); /* restore the offset */
        ret = __pa(kva);
        return ret;
}


Now lets see if that compiles.

Change back to the uClinux folder, and try another make

Assuming you didn't make any mistakes it should compile cleanly.

We'll end up with kernel modules compiled, but not added to our kernel.
These still have to be tested before we add them statically to our kernel build.

I've made a test kernel, and romfs with appropriate files, and put it in the work folder.
I've also put a prepatched fileset into the work folder also.  You can download those files, and copy over into
your uClinux-dist/linux-2.4.x/drivers/usb/folder in the uClinux BSP to add without all the work.

If you want to test, compile.
Then insmod the modules in your test firmware

eg

insmod videodev
insmod spca_core

and see if the driver works for your hardware.   

I've put a precompiled Linux kernel, and ROMFS into the folder.  You can test if you dare  8)
If it works for you, let me know.














  • No avatar
  • *****
June 19, 2011, 01:22:53 pm
Other sources for drivers -

http://linuxtv.org/wiki/index.php/Webcam_Devices
http://winbond-webcam.sourceforge.net/
http://www.saillard.org/linux/pwc/

I'll probably compile up the last spca5xx gspca driver that supports v4l v1, and give that a go too.


Can someone email me this patch http://mxhaard.free.fr/spca50x/embedded/KernelPatch/usb- 2.4.31LE06.patch.tar.gz
mxhaard is blocked here.
Thx.
« Last Edit: June 19, 2011, 02:16:36 pm by admin »

June 20, 2011, 07:49:57 am
Great work, great tutorial

Here is the file you requested: