Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / drivers / media / video / pwc / pwc-if.c
index d470394..4141829 100644 (file)
@@ -1,7 +1,7 @@
 /* Linux driver for Philips webcam
    USB and Video4Linux interface part.
    (C) 1999-2004 Nemosoft Unv.
-   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+   (C) 2004      Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/version.h>
 #include <asm/io.h>
-#include <linux/moduleparam.h>
 
 #include "pwc.h"
+#include "pwc-ioctl.h"
 #include "pwc-kiara.h"
 #include "pwc-timon.h"
-#include "pwc-dec23.h"
-#include "pwc-dec1.h"
 #include "pwc-uncompress.h"
 
 /* Function prototypes and driver templates */
 
 /* hotplug device table support */
-static const struct usb_device_id pwc_device_table [] = {
+static struct usb_device_id pwc_device_table [] = {
        { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
        { USB_DEVICE(0x0471, 0x0303) },
        { USB_DEVICE(0x0471, 0x0304) },
@@ -84,10 +81,9 @@ static const struct usb_device_id pwc_device_table [] = {
        { USB_DEVICE(0x0471, 0x0308) },
        { USB_DEVICE(0x0471, 0x030C) },
        { USB_DEVICE(0x0471, 0x0310) },
-       { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
+       { USB_DEVICE(0x0471, 0x0311) },
        { USB_DEVICE(0x0471, 0x0312) },
        { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
-       { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
        { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
        { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
        { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
@@ -98,9 +94,8 @@ static const struct usb_device_id pwc_device_table [] = {
        { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
        { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
        { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
-       { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
-       { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
-       { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */
+       { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
+       { USB_DEVICE(0x055D, 0x9001) },
        { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
        { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
        { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
@@ -127,13 +122,11 @@ static struct usb_driver pwc_driver = {
 static int default_size = PSZ_QCIF;
 static int default_fps = 10;
 static int default_fbufs = 3;   /* Default number of frame buffers */
-       int pwc_mbufs = 2;      /* Default number of mmap() buffers */
-#if CONFIG_PWC_DEBUG
-       int pwc_trace = PWC_DEBUG_LEVEL;
-#endif
+static int default_mbufs = 2;  /* Default number of mmap() buffers */
+       int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
 static int power_save = 0;
 static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
-static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
+static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
 static struct {
        int type;
        char serial_number[30];
@@ -145,7 +138,7 @@ static struct {
 
 static int pwc_video_open(struct inode *inode, struct file *file);
 static int pwc_video_close(struct inode *inode, struct file *file);
-static ssize_t pwc_video_read(struct file *file, char __user *buf,
+static ssize_t pwc_video_read(struct file *file, char __user * buf,
                          size_t count, loff_t *ppos);
 static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
 static int  pwc_video_ioctl(struct inode *inode, struct file *file,
@@ -210,44 +203,52 @@ static struct video_device pwc_template = {
 /* Here we want the physical address of the memory.
  * This is used when initializing the contents of the area.
  */
+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;
+}
 
-
-static void *pwc_rvmalloc(unsigned long size)
+static void * rvmalloc(unsigned long size)
 {
        void * mem;
        unsigned long adr;
 
+       size=PAGE_ALIGN(size);
        mem=vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr=(unsigned long) mem;
-       while (size > 0)
-        {
-          SetPageReserved(vmalloc_to_page((void *)adr));
-          adr  += PAGE_SIZE;
-          size -= PAGE_SIZE;
-        }
+       if (mem)
+       {
+               memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+               adr=(unsigned long) mem;
+               while (size > 0)
+               {
+                       SetPageReserved(vmalloc_to_page((void *)adr));
+                       adr+=PAGE_SIZE;
+                       size-=PAGE_SIZE;
+               }
+       }
        return mem;
 }
 
-static void pwc_rvfree(void * mem, unsigned long size)
+static void rvfree(void * mem, unsigned long size)
 {
        unsigned long adr;
 
-       if (!mem)
-               return;
-
-       adr=(unsigned long) mem;
-       while ((long) size > 0)
-        {
-          ClearPageReserved(vmalloc_to_page((void *)adr));
-          adr  += PAGE_SIZE;
-          size -= PAGE_SIZE;
-        }
-       vfree(mem);
+       if (mem)
+       {
+               adr=(unsigned long) mem;
+               while ((long) size > 0)
+               {
+                       ClearPageReserved(vmalloc_to_page((void *)adr));
+                       adr+=PAGE_SIZE;
+                       size-=PAGE_SIZE;
+               }
+               vfree(mem);
+       }
 }
 
 
@@ -255,83 +256,100 @@ static void pwc_rvfree(void * mem, unsigned long size)
 
 static int pwc_allocate_buffers(struct pwc_device *pdev)
 {
-       int i, err;
+       int i;
        void *kbuf;
 
-       PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
+       Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
 
        if (pdev == NULL)
                return -ENXIO;
 
-       /* Allocate Isochronuous pipe buffers */
+#ifdef PWC_MAGIC
+       if (pdev->magic != PWC_MAGIC) {
+               Err("allocate_buffers(): magic failed.\n");
+               return -ENXIO;
+       }
+#endif
+       /* Allocate Isochronous pipe buffers */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                if (pdev->sbuf[i].data == NULL) {
-                       kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+                       kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
                        if (kbuf == NULL) {
-                               PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
+                               Err("Failed to allocate iso buffer %d.\n", i);
                                return -ENOMEM;
                        }
-                       PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
+                       Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
                        pdev->sbuf[i].data = kbuf;
+                       memset(kbuf, 0, ISO_BUFFER_SIZE);
                }
        }
 
        /* Allocate frame buffer structure */
        if (pdev->fbuf == NULL) {
-               kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
+               kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
                if (kbuf == NULL) {
-                       PWC_ERROR("Failed to allocate frame buffer structure.\n");
+                       Err("Failed to allocate frame buffer structure.\n");
                        return -ENOMEM;
                }
-               PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);
+               Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
                pdev->fbuf = kbuf;
+               memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));
        }
-
        /* create frame buffers, and make circular ring */
        for (i = 0; i < default_fbufs; i++) {
                if (pdev->fbuf[i].data == NULL) {
                        kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
                        if (kbuf == NULL) {
-                               PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
+                               Err("Failed to allocate frame buffer %d.\n", i);
                                return -ENOMEM;
                        }
-                       PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
+                       Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
                        pdev->fbuf[i].data = kbuf;
-                       memset(kbuf, 0, PWC_FRAME_SIZE);
+                       memset(kbuf, 128, PWC_FRAME_SIZE);
                }
        }
 
        /* Allocate decompressor table space */
-       if (DEVICE_USE_CODEC1(pdev->type))
-               err = pwc_dec1_alloc(pdev);
-       else
-               err = pwc_dec23_alloc(pdev);
-
-       if (err) {
-               PWC_ERROR("Failed to allocate decompress table.\n");
-               return err;
-       }
+       kbuf = NULL;
+       switch (pdev->type)
+        {
+         case 675:
+         case 680:
+         case 690:
+         case 720:
+         case 730:
+         case 740:
+         case 750:
+#if 0
+           Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private));
+           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);       /* Timon & Kiara */
+           break;
+         case 645:
+         case 646:
+           /* TODO & FIXME */
+           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+           break;
+#endif
+       ;
+        }
+       pdev->decompress_data = kbuf;
 
        /* Allocate image buffer; double buffer for mmap() */
-       kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
+       kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
        if (kbuf == NULL) {
-               PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
-                               pwc_mbufs * pdev->len_per_image);
+               Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
                return -ENOMEM;
        }
-       PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);
+       Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
        pdev->image_data = kbuf;
-       for (i = 0; i < pwc_mbufs; i++) {
-               pdev->images[i].offset = i * pdev->len_per_image;
-               pdev->images[i].vma_use_count = 0;
-       }
-       for (; i < MAX_IMAGES; i++) {
-               pdev->images[i].offset = 0;
-       }
+       for (i = 0; i < default_mbufs; i++)
+               pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
+       for (; i < MAX_IMAGES; i++)
+               pdev->image_ptr[i] = NULL;
 
        kbuf = NULL;
 
-       PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
+       Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
        return 0;
 }
 
@@ -339,14 +357,21 @@ static void pwc_free_buffers(struct pwc_device *pdev)
 {
        int i;
 
-       PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);
+       Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
 
        if (pdev == NULL)
                return;
+#ifdef PWC_MAGIC
+       if (pdev->magic != PWC_MAGIC) {
+               Err("free_buffers(): magic failed.\n");
+               return;
+       }
+#endif
+
        /* Release Iso-pipe buffers */
        for (i = 0; i < MAX_ISO_BUFS; i++)
                if (pdev->sbuf[i].data != NULL) {
-                       PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
+                       Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
                        kfree(pdev->sbuf[i].data);
                        pdev->sbuf[i].data = NULL;
                }
@@ -355,7 +380,7 @@ static void pwc_free_buffers(struct pwc_device *pdev)
        if (pdev->fbuf != NULL) {
                for (i = 0; i < default_fbufs; i++) {
                        if (pdev->fbuf[i].data != NULL) {
-                               PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
+                               Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
                                vfree(pdev->fbuf[i].data);
                                pdev->fbuf[i].data = NULL;
                        }
@@ -366,19 +391,20 @@ static void pwc_free_buffers(struct pwc_device *pdev)
 
        /* Intermediate decompression buffer & tables */
        if (pdev->decompress_data != NULL) {
-               PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);
+               Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
                kfree(pdev->decompress_data);
                pdev->decompress_data = NULL;
        }
+       pdev->decompressor = NULL;
 
        /* Release image buffers */
        if (pdev->image_data != NULL) {
-               PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);
-               pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);
+               Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);
+               rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
        }
        pdev->image_data = NULL;
 
-       PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
+       Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
 }
 
 /* The frame & image buffer mess.
@@ -438,7 +464,7 @@ static void pwc_free_buffers(struct pwc_device *pdev)
 /**
   \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
  */
-static int pwc_next_fill_frame(struct pwc_device *pdev)
+static inline int pwc_next_fill_frame(struct pwc_device *pdev)
 {
        int ret;
        unsigned long flags;
@@ -463,17 +489,23 @@ static int pwc_next_fill_frame(struct pwc_device *pdev)
        }
        else {
                /* Hmm. Take it from the full list */
+#if PWC_DEBUG
                /* sanity check */
                if (pdev->full_frames == NULL) {
-                       PWC_ERROR("Neither empty or full frames available!\n");
+                       Err("Neither empty or full frames available!\n");
                        spin_unlock_irqrestore(&pdev->ptrlock, flags);
                        return -EINVAL;
                }
+#endif
                pdev->fill_frame = pdev->full_frames;
                pdev->full_frames = pdev->full_frames->next;
                ret = 1;
        }
        pdev->fill_frame->next = NULL;
+#if PWC_DEBUG
+       Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence);
+       pdev->fill_frame->sequence = pdev->sequence++;
+#endif
        spin_unlock_irqrestore(&pdev->ptrlock, flags);
        return ret;
 }
@@ -489,8 +521,6 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
        int i;
        unsigned long flags;
 
-       PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__);
-
        spin_lock_irqsave(&pdev->ptrlock, flags);
        pdev->full_frames = NULL;
        pdev->full_frames_tail = NULL;
@@ -510,15 +540,13 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
        pdev->image_read_pos = 0;
        pdev->fill_image = 0;
        spin_unlock_irqrestore(&pdev->ptrlock, flags);
-
-       PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__);
 }
 
 
 /**
   \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
  */
-int pwc_handle_frame(struct pwc_device *pdev)
+static int pwc_handle_frame(struct pwc_device *pdev)
 {
        int ret = 0;
        unsigned long flags;
@@ -528,40 +556,41 @@ int pwc_handle_frame(struct pwc_device *pdev)
           we can release the lock after this without problems */
        if (pdev->read_frame != NULL) {
                /* This can't theoretically happen */
-               PWC_ERROR("Huh? Read frame still in use?\n");
-               spin_unlock_irqrestore(&pdev->ptrlock, flags);
-               return ret;
-       }
-
-
-       if (pdev->full_frames == NULL) {
-               PWC_ERROR("Woops. No frames ready.\n");
+               Err("Huh? Read frame still in use?\n");
        }
        else {
-               pdev->read_frame = pdev->full_frames;
-               pdev->full_frames = pdev->full_frames->next;
-               pdev->read_frame->next = NULL;
-       }
-
-       if (pdev->read_frame != NULL) {
-               /* Decompression is a lenghty process, so it's outside of the lock.
-                  This gives the isoc_handler the opportunity to fill more frames
-                  in the mean time.
-               */
-               spin_unlock_irqrestore(&pdev->ptrlock, flags);
-               ret = pwc_decompress(pdev);
-               spin_lock_irqsave(&pdev->ptrlock, flags);
-
-               /* We're done with read_buffer, tack it to the end of the empty buffer list */
-               if (pdev->empty_frames == NULL) {
-                       pdev->empty_frames = pdev->read_frame;
-                       pdev->empty_frames_tail = pdev->empty_frames;
+               if (pdev->full_frames == NULL) {
+                       Err("Woops. No frames ready.\n");
                }
                else {
-                       pdev->empty_frames_tail->next = pdev->read_frame;
-                       pdev->empty_frames_tail = pdev->read_frame;
+                       pdev->read_frame = pdev->full_frames;
+                       pdev->full_frames = pdev->full_frames->next;
+                       pdev->read_frame->next = NULL;
+               }
+
+               if (pdev->read_frame != NULL) {
+#if PWC_DEBUG
+                       Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
+#endif
+                       /* Decompression is a lenghty process, so it's outside of the lock.
+                          This gives the isoc_handler the opportunity to fill more frames
+                          in the mean time.
+                       */
+                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
+                       ret = pwc_decompress(pdev);
+                       spin_lock_irqsave(&pdev->ptrlock, flags);
+
+                       /* We're done with read_buffer, tack it to the end of the empty buffer list */
+                       if (pdev->empty_frames == NULL) {
+                               pdev->empty_frames = pdev->read_frame;
+                               pdev->empty_frames_tail = pdev->empty_frames;
+                       }
+                       else {
+                               pdev->empty_frames_tail->next = pdev->read_frame;
+                               pdev->empty_frames_tail = pdev->read_frame;
+                       }
+                       pdev->read_frame = NULL;
                }
-               pdev->read_frame = NULL;
        }
        spin_unlock_irqrestore(&pdev->ptrlock, flags);
        return ret;
@@ -570,114 +599,12 @@ int pwc_handle_frame(struct pwc_device *pdev)
 /**
   \brief Advance pointers of image buffer (after each user request)
 */
-void pwc_next_image(struct pwc_device *pdev)
+static inline void pwc_next_image(struct pwc_device *pdev)
 {
        pdev->image_used[pdev->fill_image] = 0;
-       pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;
+       pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
 }
 
-/**
- * Print debug information when a frame is discarded because all of our buffer
- * is full
- */
-static void pwc_frame_dumped(struct pwc_device *pdev)
-{
-       pdev->vframes_dumped++;
-       if (pdev->vframe_count < FRAME_LOWMARK)
-               return;
-
-       if (pdev->vframes_dumped < 20)
-               PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);
-       else if (pdev->vframes_dumped == 20)
-               PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",
-                               pdev->vframe_count);
-}
-
-static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
-{
-       int awake = 0;
-
-       /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
-          frames on the USB wire after an exposure change. This conditition is
-          however detected  in the cam and a bit is set in the header.
-          */
-       if (pdev->type == 730) {
-               unsigned char *ptr = (unsigned char *)fbuf->data;
-
-               if (ptr[1] == 1 && ptr[0] & 0x10) {
-                       PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
-                       pdev->drop_frames += 2;
-                       pdev->vframes_error++;
-               }
-               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
-                       if (ptr[0] & 0x01) {
-                               pdev->snapshot_button_status = 1;
-                               PWC_TRACE("Snapshot button pressed.\n");
-                       }
-                       else {
-                               PWC_TRACE("Snapshot button released.\n");
-                       }
-               }
-               if ((ptr[0] ^ pdev->vmirror) & 0x02) {
-                       if (ptr[0] & 0x02)
-                               PWC_TRACE("Image is mirrored.\n");
-                       else
-                               PWC_TRACE("Image is normal.\n");
-               }
-               pdev->vmirror = ptr[0] & 0x03;
-               /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
-                  after a short frame; this condition is filtered out specifically. A 4 byte
-                  frame doesn't make sense anyway.
-                  So we get either this sequence:
-                  drop_bit set -> 4 byte frame -> short frame -> good frame
-                  Or this one:
-                  drop_bit set -> short frame -> good frame
-                  So we drop either 3 or 2 frames in all!
-                  */
-               if (fbuf->filled == 4)
-                       pdev->drop_frames++;
-       }
-       else if (pdev->type == 740 || pdev->type == 720) {
-               unsigned char *ptr = (unsigned char *)fbuf->data;
-               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
-                       if (ptr[0] & 0x01) {
-                               pdev->snapshot_button_status = 1;
-                               PWC_TRACE("Snapshot button pressed.\n");
-                       }
-                       else
-                               PWC_TRACE("Snapshot button released.\n");
-               }
-               pdev->vmirror = ptr[0] & 0x03;
-       }
-
-       /* In case we were instructed to drop the frame, do so silently.
-          The buffer pointers are not updated either (but the counters are reset below).
-          */
-       if (pdev->drop_frames > 0)
-               pdev->drop_frames--;
-       else {
-               /* Check for underflow first */
-               if (fbuf->filled < pdev->frame_total_size) {
-                       PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
-                                      " discarded.\n", fbuf->filled);
-                       pdev->vframes_error++;
-               }
-               else {
-                       /* Send only once per EOF */
-                       awake = 1; /* delay wake_ups */
-
-                       /* Find our next frame to fill. This will always succeed, since we
-                        * nick a frame from either empty or full list, but if we had to
-                        * take it from the full list, it means a frame got dropped.
-                        */
-                       if (pwc_next_fill_frame(pdev))
-                               pwc_frame_dumped(pdev);
-
-               }
-       } /* !drop_frames */
-       pdev->vframe_count++;
-       return awake;
-}
 
 /* This gets called for the Isochronous pipe (video). This is done in
  * interrupt time, so it has to be fast, not crash, and not stall. Neat.
@@ -693,12 +620,17 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
        awake = 0;
        pdev = (struct pwc_device *)urb->context;
        if (pdev == NULL) {
-               PWC_ERROR("isoc_handler() called with NULL device?!\n");
+               Err("isoc_handler() called with NULL device?!\n");
                return;
        }
-
+#ifdef PWC_MAGIC
+       if (pdev->magic != PWC_MAGIC) {
+               Err("isoc_handler() called with bad magic!\n");
+               return;
+       }
+#endif
        if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-               PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
+               Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
                return;
        }
        if (urb->status != -EINPROGRESS && urb->status != 0) {
@@ -713,13 +645,13 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
                        case -EILSEQ:           errmsg = "CRC/Timeout (could be anything)"; break;
                        case -ETIMEDOUT:        errmsg = "NAK (device does not respond)"; break;
                }
-               PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
+               Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
                /* Give up after a number of contiguous errors on the USB bus.
                   Appearantly something is wrong so we simulate an unplug event.
                 */
                if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
                {
-                       PWC_INFO("Too many ISOC errors, bailing out.\n");
+                       Info("Too many ISOC errors, bailing out.\n");
                        pdev->error_status = EIO;
                        awake = 1;
                        wake_up_interruptible(&pdev->frameq);
@@ -729,7 +661,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
 
        fbuf = pdev->fill_frame;
        if (fbuf == NULL) {
-               PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
+               Err("pwc_isoc_handler without valid fill frame.\n");
                awake = 1;
                goto handler_end;
        }
@@ -756,7 +688,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
 
                                        /* ...copy data to frame buffer, if possible */
                                        if (flen + fbuf->filled > pdev->frame_total_size) {
-                                               PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
+                                               Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
                                                pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
                                                pdev->vframes_error++;
                                        }
@@ -772,28 +704,96 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
                                /* Shorter packet... We probably have the end of an image-frame;
                                   wake up read() process and let select()/poll() do something.
                                   Decompression is done in user time over there.
-                                  */
+                                */
                                if (pdev->vsync == 2) {
-                                       if (pwc_rcv_short_packet(pdev, fbuf)) {
-                                               awake = 1;
-                                               fbuf = pdev->fill_frame;
+                                       /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
+                                          frames on the USB wire after an exposure change. This conditition is
+                                          however detected  in the cam and a bit is set in the header.
+                                        */
+                                       if (pdev->type == 730) {
+                                               unsigned char *ptr = (unsigned char *)fbuf->data;
+
+                                               if (ptr[1] == 1 && ptr[0] & 0x10) {
+#if PWC_DEBUG
+                                                       Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
+#endif
+                                                       pdev->drop_frames += 2;
+                                                       pdev->vframes_error++;
+                                               }
+                                               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+                                                       if (ptr[0] & 0x01)
+                                                               Info("Snapshot button pressed.\n");
+                                                       else
+                                                               Info("Snapshot button released.\n");
+                                               }
+                                               if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+                                                       if (ptr[0] & 0x02)
+                                                               Info("Image is mirrored.\n");
+                                                       else
+                                                               Info("Image is normal.\n");
+                                               }
+                                               pdev->vmirror = ptr[0] & 0x03;
+                                               /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
+                                                  after a short frame; this condition is filtered out specifically. A 4 byte
+                                                  frame doesn't make sense anyway.
+                                                  So we get either this sequence:
+                                                       drop_bit set -> 4 byte frame -> short frame -> good frame
+                                                  Or this one:
+                                                       drop_bit set -> short frame -> good frame
+                                                  So we drop either 3 or 2 frames in all!
+                                                */
+                                               if (fbuf->filled == 4)
+                                                       pdev->drop_frames++;
                                        }
+
+                                       /* In case we were instructed to drop the frame, do so silently.
+                                          The buffer pointers are not updated either (but the counters are reset below).
+                                        */
+                                       if (pdev->drop_frames > 0)
+                                               pdev->drop_frames--;
+                                       else {
+                                               /* Check for underflow first */
+                                               if (fbuf->filled < pdev->frame_total_size) {
+                                                       Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);
+                                                       pdev->vframes_error++;
+                                               }
+                                               else {
+                                                       /* Send only once per EOF */
+                                                       awake = 1; /* delay wake_ups */
+
+                                                       /* Find our next frame to fill. This will always succeed, since we
+                                                        * nick a frame from either empty or full list, but if we had to
+                                                        * take it from the full list, it means a frame got dropped.
+                                                        */
+                                                       if (pwc_next_fill_frame(pdev)) {
+                                                               pdev->vframes_dumped++;
+                                                               if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
+                                                                       if (pdev->vframes_dumped < 20)
+                                                                               Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
+                                                                       if (pdev->vframes_dumped == 20)
+                                                                               Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
+                                                               }
+                                                       }
+                                                       fbuf = pdev->fill_frame;
+                                               }
+                                       } /* !drop_frames */
+                                       pdev->vframe_count++;
                                }
                                fbuf->filled = 0;
                                fillptr = fbuf->data;
                                pdev->vsync = 1;
-                       }
-
+                       } /* .. flen < last_packet_size */
                        pdev->vlast_packet_size = flen;
                } /* ..status == 0 */
+#if PWC_DEBUG
+               /* This is normally not interesting to the user, unless you are really debugging something */
                else {
-                       /* This is normally not interesting to the user, unless
-                        * you are really debugging something */
                        static int iso_error = 0;
                        iso_error++;
                        if (iso_error < 20)
-                               PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
+                               Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
                }
+#endif
        }
 
 handler_end:
@@ -803,11 +803,11 @@ handler_end:
        urb->dev = pdev->udev;
        i = usb_submit_urb(urb, GFP_ATOMIC);
        if (i != 0)
-               PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
+               Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
 }
 
 
-int pwc_isoc_init(struct pwc_device *pdev)
+static int pwc_isoc_init(struct pwc_device *pdev)
 {
        struct usb_device *udev;
        struct urb *urb;
@@ -826,6 +826,7 @@ int pwc_isoc_init(struct pwc_device *pdev)
        /* Get the current alternate interface, adjust packet size */
        if (!udev->actconfig)
                return -EFAULT;
+
        intf = usb_ifnum_to_if(udev, 0);
        if (intf)
                idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
@@ -835,21 +836,20 @@ int pwc_isoc_init(struct pwc_device *pdev)
 
        /* Search video endpoint */
        pdev->vmax_packet_size = -1;
-       for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
+       for (i = 0; i < idesc->desc.bNumEndpoints; i++)
                if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
                        pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
                        break;
                }
-       }
 
        if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
-               PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
+               Err("Failed to find packet size for video endpoint in current alternate setting.\n");
                return -ENFILE; /* Odd error, that should be noticeable */
        }
 
        /* Set alternate interface */
        ret = 0;
-       PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
+       Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
        ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
        if (ret < 0)
                return ret;
@@ -857,12 +857,12 @@ int pwc_isoc_init(struct pwc_device *pdev)
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
                if (urb == NULL) {
-                       PWC_ERROR("Failed to allocate urb %d\n", i);
+                       Err("Failed to allocate urb %d\n", i);
                        ret = -ENOMEM;
                        break;
                }
                pdev->sbuf[i].urb = urb;
-               PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
+               Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
        }
        if (ret) {
                /* De-allocate in reverse order */
@@ -899,26 +899,24 @@ int pwc_isoc_init(struct pwc_device *pdev)
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
                if (ret)
-                       PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
+                       Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
                else
-                       PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+                       Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
        }
 
        /* All is done... */
        pdev->iso_init = 1;
-       PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
+       Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
        return 0;
 }
 
-void pwc_isoc_cleanup(struct pwc_device *pdev)
+static void pwc_isoc_cleanup(struct pwc_device *pdev)
 {
        int i;
 
-       PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
+       Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
        if (pdev == NULL)
                return;
-       if (pdev->iso_init == 0)
-               return;
 
        /* Unlinking ISOC buffers one by one */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
@@ -927,10 +925,10 @@ void pwc_isoc_cleanup(struct pwc_device *pdev)
                urb = pdev->sbuf[i].urb;
                if (urb != 0) {
                        if (pdev->iso_init) {
-                               PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
+                               Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
                                usb_kill_urb(urb);
                        }
-                       PWC_DEBUG_MEMORY("Freeing URB\n");
+                       Trace(TRACE_MEMORY, "Freeing URB\n");
                        usb_free_urb(urb);
                        pdev->sbuf[i].urb = NULL;
                }
@@ -940,12 +938,12 @@ void pwc_isoc_cleanup(struct pwc_device *pdev)
           is signalled by EPIPE)
         */
        if (pdev->error_status && pdev->error_status != EPIPE) {
-               PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
+               Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
                usb_set_interface(pdev->udev, 0, 0);
        }
 
        pdev->iso_init = 0;
-       PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
+       Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
 }
 
 int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
@@ -959,18 +957,18 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
        /* Try to set video mode... */
        start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
        if (ret) {
-               PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");
+               Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
                /* That failed... restore old mode (we know that worked) */
                start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
                if (start) {
-                       PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");
+                       Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
                }
        }
        if (start == 0)
        {
                if (pwc_isoc_init(pdev) < 0)
                {
-                       PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+                       Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
                        ret = -EAGAIN; /* let's try again, who knows if it works a second time */
                }
        }
@@ -978,129 +976,54 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
        return ret; /* Return original error code */
 }
 
-/*********
- * sysfs
- *********/
-static struct pwc_device *cd_to_pwc(struct class_device *cd)
-{
-       struct video_device *vdev = to_video_device(cd);
-       return video_get_drvdata(vdev);
-}
-
-static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf)
-{
-       struct pwc_device *pdev = cd_to_pwc(class_dev);
-       return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
-}
-
-static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
-                        size_t count)
-{
-       struct pwc_device *pdev = cd_to_pwc(class_dev);
-       int pan, tilt;
-       int ret = -EINVAL;
-
-       if (strncmp(buf, "reset", 5) == 0)
-               ret = pwc_mpt_reset(pdev, 0x3);
-
-       else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
-               ret = pwc_mpt_set_angle(pdev, pan, tilt);
-
-       if (ret < 0)
-               return ret;
-       return strlen(buf);
-}
-static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
-                        store_pan_tilt);
-
-static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf)
-{
-       struct pwc_device *pdev = cd_to_pwc(class_dev);
-       int status = pdev->snapshot_button_status;
-       pdev->snapshot_button_status = 0;
-       return sprintf(buf, "%d\n", status);
-}
-
-static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
-                        NULL);
-
-static void pwc_create_sysfs_files(struct video_device *vdev)
-{
-       struct pwc_device *pdev = video_get_drvdata(vdev);
-       if (pdev->features & FEATURE_MOTOR_PANTILT)
-               video_device_create_file(vdev, &class_device_attr_pan_tilt);
-       video_device_create_file(vdev, &class_device_attr_button);
-}
-
-static void pwc_remove_sysfs_files(struct video_device *vdev)
-{
-       struct pwc_device *pdev = video_get_drvdata(vdev);
-       if (pdev->features & FEATURE_MOTOR_PANTILT)
-               video_device_remove_file(vdev, &class_device_attr_pan_tilt);
-       video_device_remove_file(vdev, &class_device_attr_button);
-}
-
-#if CONFIG_PWC_DEBUG
-static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
-{
-       switch(sensor_type) {
-               case 0x00:
-                       return "Hyundai CMOS sensor";
-               case 0x20:
-                       return "Sony CCD sensor + TDA8787";
-               case 0x2E:
-                       return "Sony CCD sensor + Exas 98L59";
-               case 0x2F:
-                       return "Sony CCD sensor + ADI 9804";
-               case 0x30:
-                       return "Sharp CCD sensor + TDA8787";
-               case 0x3E:
-                       return "Sharp CCD sensor + Exas 98L59";
-               case 0x3F:
-                       return "Sharp CCD sensor + ADI 9804";
-               case 0x40:
-                       return "UPA 1021 sensor";
-               case 0x100:
-                       return "VGA sensor";
-               case 0x101:
-                       return "PAL MR sensor";
-               default:
-                       return "unknown type of sensor";
-       }
-}
-#endif
 
 /***************************************************************************/
 /* Video4Linux functions */
 
 static int pwc_video_open(struct inode *inode, struct file *file)
 {
-       int i, ret;
+       int i;
        struct video_device *vdev = video_devdata(file);
        struct pwc_device *pdev;
 
-       PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
+       Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
 
        pdev = (struct pwc_device *)vdev->priv;
        if (pdev == NULL)
                BUG();
-       if (pdev->vopen) {
-               PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
+       if (pdev->vopen)
                return -EBUSY;
-       }
 
        down(&pdev->modlock);
        if (!pdev->usb_init) {
-               PWC_DEBUG_OPEN("Doing first time initialization.\n");
+               Trace(TRACE_OPEN, "Doing first time initialization.\n");
                pdev->usb_init = 1;
 
-               /* Query sensor type */
-               ret = pwc_get_cmos_sensor(pdev, &i);
-               if (ret >= 0)
+               if (pwc_trace & TRACE_OPEN)
                {
-                       PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
-                                       pdev->vdev->name,
-                                       pwc_sensor_type_to_string(i), i);
+                       /* Query sensor type */
+                       const char *sensor_type = NULL;
+                       int ret;
+
+                       ret = pwc_get_cmos_sensor(pdev, &i);
+                       if (ret >= 0)
+                       {
+                               switch(i) {
+                               case 0x00:  sensor_type = "Hyundai CMOS sensor"; break;
+                               case 0x20:  sensor_type = "Sony CCD sensor + TDA8787"; break;
+                               case 0x2E:  sensor_type = "Sony CCD sensor + Exas 98L59"; break;
+                               case 0x2F:  sensor_type = "Sony CCD sensor + ADI 9804"; break;
+                               case 0x30:  sensor_type = "Sharp CCD sensor + TDA8787"; break;
+                               case 0x3E:  sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
+                               case 0x3F:  sensor_type = "Sharp CCD sensor + ADI 9804"; break;
+                               case 0x40:  sensor_type = "UPA 1021 sensor"; break;
+                               case 0x100: sensor_type = "VGA sensor"; break;
+                               case 0x101: sensor_type = "PAL MR sensor"; break;
+                               default:    sensor_type = "unknown type of sensor"; break;
+                               }
+                       }
+                       if (sensor_type != NULL)
+                               Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
                }
        }
 
@@ -1108,32 +1031,34 @@ static int pwc_video_open(struct inode *inode, struct file *file)
        if (power_save) {
                i = pwc_camera_power(pdev, 1);
                if (i < 0)
-                       PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i);
+                       Info("Failed to restore power to the camera! (%d)\n", i);
        }
        /* Set LED on/off time */
        if (pwc_set_leds(pdev, led_on, led_off) < 0)
-               PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
+               Info("Failed to set LED on/off time.\n");
 
        pwc_construct(pdev); /* set min/max sizes correct */
 
        /* So far, so good. Allocate memory. */
        i = pwc_allocate_buffers(pdev);
        if (i < 0) {
-               PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
-               pwc_free_buffers(pdev);
+               Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
                up(&pdev->modlock);
                return i;
        }
 
        /* Reset buffers & parameters */
        pwc_reset_buffers(pdev);
-       for (i = 0; i < pwc_mbufs; i++)
+       for (i = 0; i < default_mbufs; i++)
                pdev->image_used[i] = 0;
        pdev->vframe_count = 0;
        pdev->vframes_dumped = 0;
        pdev->vframes_error = 0;
        pdev->visoc_errors = 0;
        pdev->error_status = 0;
+#if PWC_DEBUG
+       pdev->sequence = 0;
+#endif
        pwc_construct(pdev); /* set min/max sizes correct */
 
        /* Set some defaults */
@@ -1145,44 +1070,29 @@ static int pwc_video_open(struct inode *inode, struct file *file)
         */
        i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
        if (i)  {
-               unsigned int default_resolution;
-               PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
-               if (pdev->type>= 730)
-                       default_resolution = PSZ_QSIF;
+               Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
+               if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
+                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);
                else
-                       default_resolution = PSZ_QCIF;
-
-               i = pwc_set_video_mode(pdev,
-                                      pwc_image_sizes[default_resolution].x,
-                                      pwc_image_sizes[default_resolution].y,
-                                      10,
-                                      pdev->vcompression,
-                                      0);
+                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
        }
        if (i) {
-               PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
-               pwc_free_buffers(pdev);
+               Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
                up(&pdev->modlock);
                return i;
        }
 
        i = pwc_isoc_init(pdev);
        if (i) {
-               PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
-               pwc_isoc_cleanup(pdev);
-               pwc_free_buffers(pdev);
+               Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
                up(&pdev->modlock);
                return i;
        }
 
-       /* Initialize the webcam to sane value */
-       pwc_set_brightness(pdev, 0x7fff);
-       pwc_set_agc(pdev, 1, 0);
-
        pdev->vopen++;
        file->private_data = vdev;
        up(&pdev->modlock);
-       PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
+       Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
        return 0;
 }
 
@@ -1193,23 +1103,35 @@ static int pwc_video_close(struct inode *inode, struct file *file)
        struct pwc_device *pdev;
        int i;
 
-       PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
+       Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
 
        pdev = (struct pwc_device *)vdev->priv;
        if (pdev->vopen == 0)
-               PWC_DEBUG_MODULE("video_close() called on closed device?\n");
+               Info("video_close() called on closed device?\n");
 
        /* Dump statistics, but only if a reasonable amount of frames were
           processed (to prevent endless log-entries in case of snap-shot
           programs)
         */
        if (pdev->vframe_count > 20)
-               PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
+               Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
 
-       if (DEVICE_USE_CODEC1(pdev->type))
-           pwc_dec1_exit();
-       else
-           pwc_dec23_exit();
+       switch (pdev->type)
+        {
+         case 675:
+         case 680:
+         case 690:
+         case 720:
+         case 730:
+         case 740:
+         case 750:
+/*         pwc_dec23_exit();   *//* Timon & Kiara */
+           break;
+         case 645:
+         case 646:
+/*         pwc_dec1_exit(); */
+           break;
+        }
 
        pwc_isoc_cleanup(pdev);
        pwc_free_buffers(pdev);
@@ -1218,15 +1140,15 @@ static int pwc_video_close(struct inode *inode, struct file *file)
        if (pdev->error_status != EPIPE) {
                /* Turn LEDs off */
                if (pwc_set_leds(pdev, 0, 0) < 0)
-                       PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
+                       Info("Failed to set LED on/off time.\n");
                if (power_save) {
                        i = pwc_camera_power(pdev, 0);
                        if (i < 0)
-                               PWC_ERROR("Failed to power down camera (%d)\n", i);
+                               Err("Failed to power down camera (%d)\n", i);
                }
        }
-       pdev->vopen--;
-       PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
+       pdev->vopen = 0;
+       Trace(TRACE_OPEN, "<< video_close()\n");
        return 0;
 }
 
@@ -1242,7 +1164,7 @@ static int pwc_video_close(struct inode *inode, struct file *file)
                device is tricky anyhow.
  */
 
-static ssize_t pwc_video_read(struct file *file, char __user *buf,
+static ssize_t pwc_video_read(struct file *file, char __user * buf,
                          size_t count, loff_t *ppos)
 {
        struct video_device *vdev = file->private_data;
@@ -1250,10 +1172,8 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
        int noblock = file->f_flags & O_NONBLOCK;
        DECLARE_WAITQUEUE(wait, current);
        int bytes_to_read;
-       void *image_buffer_addr;
 
-       PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
-                       vdev, buf, count);
+       Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
        if (vdev == NULL)
                return -EFAULT;
        pdev = vdev->priv;
@@ -1294,19 +1214,16 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
                        return -EFAULT;
        }
 
-       PWC_DEBUG_READ("Copying data to user space.\n");
+       Trace(TRACE_READ, "Copying data to user space.\n");
        if (pdev->vpalette == VIDEO_PALETTE_RAW)
-               bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
+               bytes_to_read = pdev->frame_size;
        else
                bytes_to_read = pdev->view.size;
 
        /* copy bytes to user space; we allow for partial reads */
        if (count + pdev->image_read_pos > bytes_to_read)
                count = bytes_to_read - pdev->image_read_pos;
-       image_buffer_addr = pdev->image_data;
-       image_buffer_addr += pdev->images[pdev->fill_image].offset;
-       image_buffer_addr += pdev->image_read_pos;
-       if (copy_to_user(buf, image_buffer_addr, count))
+       if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))
                return -EFAULT;
        pdev->image_read_pos += count;
        if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
@@ -1336,56 +1253,370 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
        return 0;
 }
 
+static int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+                             unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (vdev == NULL)
+               return -EFAULT;
+       pdev = vdev->priv;
+       if (pdev == NULL)
+               return -EFAULT;
+
+       switch (cmd) {
+               /* Query cabapilities */
+               case VIDIOCGCAP:
+               {
+                       struct video_capability *caps = arg;
+
+                       strcpy(caps->name, vdev->name);
+                       caps->type = VID_TYPE_CAPTURE;
+                       caps->channels = 1;
+                       caps->audios = 1;
+                       caps->minwidth  = pdev->view_min.x;
+                       caps->minheight = pdev->view_min.y;
+                       caps->maxwidth  = pdev->view_max.x;
+                       caps->maxheight = pdev->view_max.y;
+                       break;
+               }
+
+               /* Channel functions (simulate 1 channel) */
+               case VIDIOCGCHAN:
+               {
+                       struct video_channel *v = arg;
+
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       v->flags = 0;
+                       v->tuners = 0;
+                       v->type = VIDEO_TYPE_CAMERA;
+                       strcpy(v->name, "Webcam");
+                       return 0;
+               }
+
+               case VIDIOCSCHAN:
+               {
+                       /* The spec says the argument is an integer, but
+                          the bttv driver uses a video_channel arg, which
+                          makes sense becasue it also has the norm flag.
+                        */
+                       struct video_channel *v = arg;
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       return 0;
+               }
+
+
+               /* Picture functions; contrast etc. */
+               case VIDIOCGPICT:
+               {
+                       struct video_picture *p = arg;
+                       int val;
+
+                       val = pwc_get_brightness(pdev);
+                       if (val >= 0)
+                               p->brightness = val;
+                       else
+                               p->brightness = 0xffff;
+                       val = pwc_get_contrast(pdev);
+                       if (val >= 0)
+                               p->contrast = val;
+                       else
+                               p->contrast = 0xffff;
+                       /* Gamma, Whiteness, what's the difference? :) */
+                       val = pwc_get_gamma(pdev);
+                       if (val >= 0)
+                               p->whiteness = val;
+                       else
+                               p->whiteness = 0xffff;
+                       val = pwc_get_saturation(pdev);
+                       if (val >= 0)
+                               p->colour = val;
+                       else
+                               p->colour = 0xffff;
+                       p->depth = 24;
+                       p->palette = pdev->vpalette;
+                       p->hue = 0xFFFF; /* N/A */
+                       break;
+               }
+
+               case VIDIOCSPICT:
+               {
+                       struct video_picture *p = arg;
+                       /*
+                        *      FIXME:  Suppose we are mid read
+                               ANSWER: No problem: the firmware of the camera
+                                       can handle brightness/contrast/etc
+                                       changes at _any_ time, and the palette
+                                       is used exactly once in the uncompress
+                                       routine.
+                        */
+                       pwc_set_brightness(pdev, p->brightness);
+                       pwc_set_contrast(pdev, p->contrast);
+                       pwc_set_gamma(pdev, p->whiteness);
+                       pwc_set_saturation(pdev, p->colour);
+                       if (p->palette && p->palette != pdev->vpalette) {
+                               switch (p->palette) {
+                                       case VIDEO_PALETTE_YUV420P:
+                                       case VIDEO_PALETTE_RAW:
+                                               pdev->vpalette = p->palette;
+                                               return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+                                               break;
+                                       default:
+                                               return -EINVAL;
+                                               break;
+                               }
+                       }
+                       break;
+               }
+
+               /* Window/size parameters */
+               case VIDIOCGWIN:
+               {
+                       struct video_window *vw = arg;
+
+                       vw->x = 0;
+                       vw->y = 0;
+                       vw->width = pdev->view.x;
+                       vw->height = pdev->view.y;
+                       vw->chromakey = 0;
+                       vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
+                                  (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
+                       break;
+               }
+
+               case VIDIOCSWIN:
+               {
+                       struct video_window *vw = arg;
+                       int fps, snapshot, ret;
+
+                       fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+                       snapshot = vw->flags & PWC_FPS_SNAPSHOT;
+                       if (fps == 0)
+                               fps = pdev->vframes;
+                       if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
+                               return 0;
+                       ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
+                       if (ret)
+                               return ret;
+                       break;
+               }
+
+               /* We don't have overlay support (yet) */
+               case VIDIOCGFBUF:
+               {
+                       struct video_buffer *vb = arg;
+
+                       memset(vb,0,sizeof(*vb));
+                       break;
+               }
+
+               /* mmap() functions */
+               case VIDIOCGMBUF:
+               {
+                       /* Tell the user program how much memory is needed for a mmap() */
+                       struct video_mbuf *vm = arg;
+                       int i;
+
+                       memset(vm, 0, sizeof(*vm));
+                       vm->size = default_mbufs * pdev->len_per_image;
+                       vm->frames = default_mbufs; /* double buffering should be enough for most applications */
+                       for (i = 0; i < default_mbufs; i++)
+                               vm->offsets[i] = i * pdev->len_per_image;
+                       break;
+               }
+
+               case VIDIOCMCAPTURE:
+               {
+                       /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
+                       struct video_mmap *vm = arg;
+
+                       Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
+                       if (vm->frame < 0 || vm->frame >= default_mbufs)
+                               return -EINVAL;
+
+                       /* xawtv is nasty. It probes the available palettes
+                          by setting a very small image size and trying
+                          various palettes... The driver doesn't support
+                          such small images, so I'm working around it.
+                        */
+                       if (vm->format)
+                       {
+                               switch (vm->format)
+                               {
+                                       case VIDEO_PALETTE_YUV420P:
+                                       case VIDEO_PALETTE_RAW:
+                                               break;
+                                       default:
+                                               return -EINVAL;
+                                               break;
+                               }
+                       }
+
+                       if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
+                           (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
+                               int ret;
+
+                               Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
+                               ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+                               if (ret)
+                                       return ret;
+                       } /* ... size mismatch */
+
+                       /* FIXME: should we lock here? */
+                       if (pdev->image_used[vm->frame])
+                               return -EBUSY;  /* buffer wasn't available. Bummer */
+                       pdev->image_used[vm->frame] = 1;
+
+                       /* Okay, we're done here. In the SYNC call we wait until a
+                          frame comes available, then expand image into the given
+                          buffer.
+                          In contrast to the CPiA cam the Philips cams deliver a
+                          constant stream, almost like a grabber card. Also,
+                          we have separate buffers for the rawdata and the image,
+                          meaning we can nearly always expand into the requested buffer.
+                        */
+                       Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n");
+                       break;
+               }
+
+               case VIDIOCSYNC:
+               {
+                       /* The doc says: "Whenever a buffer is used it should
+                          call VIDIOCSYNC to free this frame up and continue."
+
+                          The only odd thing about this whole procedure is
+                          that MCAPTURE flags the buffer as "in use", and
+                          SYNC immediately unmarks it, while it isn't
+                          after SYNC that you know that the buffer actually
+                          got filled! So you better not start a CAPTURE in
+                          the same frame immediately (use double buffering).
+                          This is not a problem for this cam, since it has
+                          extra intermediate buffers, but a hardware
+                          grabber card will then overwrite the buffer
+                          you're working on.
+                        */
+                       int *mbuf = arg;
+                       int ret;
+
+                       Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf);
+
+                       /* bounds check */
+                       if (*mbuf < 0 || *mbuf >= default_mbufs)
+                               return -EINVAL;
+                       /* check if this buffer was requested anyway */
+                       if (pdev->image_used[*mbuf] == 0)
+                               return -EINVAL;
+
+                       /* Add ourselves to the frame wait-queue.
+
+                          FIXME: needs auditing for safety.
+                          QUESTION: In what respect? I think that using the
+                                    frameq is safe now.
+                        */
+                       add_wait_queue(&pdev->frameq, &wait);
+                       while (pdev->full_frames == NULL) {
+                               if (pdev->error_status) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -pdev->error_status;
+                               }
+
+                               if (signal_pending(current)) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -ERESTARTSYS;
+                               }
+                               schedule();
+                               set_current_state(TASK_INTERRUPTIBLE);
+                       }
+                       remove_wait_queue(&pdev->frameq, &wait);
+                       set_current_state(TASK_RUNNING);
+
+                       /* The frame is ready. Expand in the image buffer
+                          requested by the user. I don't care if you
+                          mmap() 5 buffers and request data in this order:
+                          buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
+                          Grabber hardware may not be so forgiving.
+                        */
+                       Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n");
+                       pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
+                       /* Decompress, etc */
+                       ret = pwc_handle_frame(pdev);
+                       pdev->image_used[*mbuf] = 0;
+                       if (ret)
+                               return -EFAULT;
+                       break;
+               }
+
+               case VIDIOCGAUDIO:
+               {
+                       struct video_audio *v = arg;
+
+                       strcpy(v->name, "Microphone");
+                       v->audio = -1; /* unknown audio minor */
+                       v->flags = 0;
+                       v->mode = VIDEO_SOUND_MONO;
+                       v->volume = 0;
+                       v->bass = 0;
+                       v->treble = 0;
+                       v->balance = 0x8000;
+                       v->step = 1;
+                       break;
+               }
+
+               case VIDIOCSAUDIO:
+               {
+                       /* Dummy: nothing can be set */
+                       break;
+               }
+
+               case VIDIOCGUNIT:
+               {
+                       struct video_unit *vu = arg;
+
+                       vu->video = pdev->vdev->minor & 0x3F;
+                       vu->audio = -1; /* not known yet */
+                       vu->vbi = -1;
+                       vu->radio = -1;
+                       vu->teletext = -1;
+                       break;
+               }
+               default:
+                       return pwc_ioctl(pdev, cmd, arg);
+       } /* ..switch */
+       return 0;
+}
+
 static int pwc_video_ioctl(struct inode *inode, struct file *file,
                           unsigned int cmd, unsigned long arg)
 {
        return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
 }
 
+
 static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct video_device *vdev = file->private_data;
        struct pwc_device *pdev;
-       unsigned long start;
-       unsigned long size;
-       unsigned long page, pos = 0;
-       int index;
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end-vma->vm_start;
+       unsigned long page, pos;
 
-       PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);
+       Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
        pdev = vdev->priv;
-       size = vma->vm_end - vma->vm_start;
-       start = vma->vm_start;
 
-       /* Find the idx buffer for this mapping */
-       for (index = 0; index < pwc_mbufs; index++) {
-               pos = pdev->images[index].offset;
-               if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
-       }
-       if (index == MAX_IMAGES)
-               return -EINVAL;
-       if (index == 0) {
-               /*
-                * Special case for v4l1. In v4l1, we map only one big buffer,
-                * but in v4l2 each buffer is mapped
-                */
-               unsigned long total_size;
-               total_size = pwc_mbufs * pdev->len_per_image;
-               if (size != pdev->len_per_image && size != total_size) {
-                       PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",
-                                  size, pdev->len_per_image, total_size);
-                       return -EINVAL;
-               }
-       } else if (size > pdev->len_per_image)
-               return -EINVAL;
+       vma->vm_flags |= VM_IO;
 
-       vma->vm_flags |= VM_IO; /* from 2.6.9-acX */
-
-       pos += (unsigned long)pdev->image_data;
+       pos = (unsigned long)pdev->image_data;
        while (size > 0) {
                page = vmalloc_to_pfn((void *)pos);
                if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
                        return -EAGAIN;
+
                start += PAGE_SIZE;
                pos += PAGE_SIZE;
                if (size > PAGE_SIZE)
@@ -1393,6 +1624,7 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
                else
                        size = 0;
        }
+
        return 0;
 }
 
@@ -1413,12 +1645,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        int video_nr = -1; /* default: use next available device */
        char serial_number[30], *name;
 
-       vendor_id = le16_to_cpu(udev->descriptor.idVendor);
-       product_id = le16_to_cpu(udev->descriptor.idProduct);
-
        /* Check if we can handle this device */
-       PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
-               vendor_id, product_id,
+       Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n",
+               le16_to_cpu(udev->descriptor.idVendor),
+               le16_to_cpu(udev->descriptor.idProduct),
                intf->altsetting->desc.bInterfaceNumber);
 
        /* the interfaces are probed one by one. We are only interested in the
@@ -1428,63 +1658,61 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        if (intf->altsetting->desc.bInterfaceNumber > 0)
                return -ENODEV;
 
+       vendor_id = le16_to_cpu(udev->descriptor.idVendor);
+       product_id = le16_to_cpu(udev->descriptor.idProduct);
+
        if (vendor_id == 0x0471) {
                switch (product_id) {
                case 0x0302:
-                       PWC_INFO("Philips PCA645VC USB webcam detected.\n");
+                       Info("Philips PCA645VC USB webcam detected.\n");
                        name = "Philips 645 webcam";
                        type_id = 645;
                        break;
                case 0x0303:
-                       PWC_INFO("Philips PCA646VC USB webcam detected.\n");
+                       Info("Philips PCA646VC USB webcam detected.\n");
                        name = "Philips 646 webcam";
                        type_id = 646;
                        break;
                case 0x0304:
-                       PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
+                       Info("Askey VC010 type 2 USB webcam detected.\n");
                        name = "Askey VC010 webcam";
                        type_id = 646;
                        break;
                case 0x0307:
-                       PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
+                       Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
                        name = "Philips 675 webcam";
                        type_id = 675;
                        break;
                case 0x0308:
-                       PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
+                       Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
                        name = "Philips 680 webcam";
                        type_id = 680;
                        break;
                case 0x030C:
-                       PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
+                       Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
                        name = "Philips 690 webcam";
                        type_id = 690;
                        break;
                case 0x0310:
-                       PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
+                       Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
                        name = "Philips 730 webcam";
                        type_id = 730;
                        break;
                case 0x0311:
-                       PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
+                       Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
                        name = "Philips 740 webcam";
                        type_id = 740;
                        break;
                case 0x0312:
-                       PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
+                       Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
                        name = "Philips 750 webcam";
                        type_id = 750;
                        break;
                case 0x0313:
-                       PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
+                       Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
                        name = "Philips 720K/40 webcam";
                        type_id = 720;
                        break;
-               case 0x0329:
-                       PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
-                       name = "Philips SPC 900NC webcam";
-                       type_id = 720;
-                       break;
                default:
                        return -ENODEV;
                        break;
@@ -1493,7 +1721,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else if (vendor_id == 0x069A) {
                switch(product_id) {
                case 0x0001:
-                       PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
+                       Info("Askey VC010 type 1 USB webcam detected.\n");
                        name = "Askey VC010 webcam";
                        type_id = 645;
                        break;
@@ -1505,33 +1733,32 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else if (vendor_id == 0x046d) {
                switch(product_id) {
                case 0x08b0:
-                       PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+                       Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
                        name = "Logitech QuickCam Pro 3000";
                        type_id = 740; /* CCD sensor */
                        break;
                case 0x08b1:
-                       PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
+                       Info("Logitech QuickCam Notebook Pro USB webcam detected.\n");
                        name = "Logitech QuickCam Notebook Pro";
                        type_id = 740; /* CCD sensor */
                        break;
                case 0x08b2:
-                       PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+                       Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
                        name = "Logitech QuickCam Pro 4000";
                        type_id = 740; /* CCD sensor */
                        break;
                case 0x08b3:
-                       PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
+                       Info("Logitech QuickCam Zoom USB webcam detected.\n");
                        name = "Logitech QuickCam Zoom";
                        type_id = 740; /* CCD sensor */
                        break;
                case 0x08B4:
-                       PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
+                       Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
                        name = "Logitech QuickCam Zoom";
                        type_id = 740; /* CCD sensor */
-                       power_save = 1;
                        break;
                case 0x08b5:
-                       PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
+                       Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
                        name = "Logitech QuickCam Orbit";
                        type_id = 740; /* CCD sensor */
                        features |= FEATURE_MOTOR_PANTILT;
@@ -1539,7 +1766,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                case 0x08b6:
                case 0x08b7:
                case 0x08b8:
-                       PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
+                       Info("Logitech QuickCam detected (reserved ID).\n");
                        name = "Logitech QuickCam (res.)";
                        type_id = 730; /* Assuming CMOS */
                        break;
@@ -1555,20 +1782,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                 */
                switch(product_id) {
                case 0x9000:
-                       PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
+                       Info("Samsung MPC-C10 USB webcam detected.\n");
                        name = "Samsung MPC-C10";
                        type_id = 675;
                        break;
                case 0x9001:
-                       PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
+                       Info("Samsung MPC-C30 USB webcam detected.\n");
                        name = "Samsung MPC-C30";
                        type_id = 675;
                        break;
-               case 0x9002:
-                       PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
-                       name = "Samsung MPC-C30";
-                       type_id = 740;
-                       break;
                default:
                        return -ENODEV;
                        break;
@@ -1577,12 +1799,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else if (vendor_id == 0x041e) {
                switch(product_id) {
                case 0x400c:
-                       PWC_INFO("Creative Labs Webcam 5 detected.\n");
+                       Info("Creative Labs Webcam 5 detected.\n");
                        name = "Creative Labs Webcam 5";
                        type_id = 730;
                        break;
                case 0x4011:
-                       PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
+                       Info("Creative Labs Webcam Pro Ex detected.\n");
                        name = "Creative Labs Webcam Pro Ex";
                        type_id = 740;
                        break;
@@ -1594,7 +1816,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else if (vendor_id == 0x04cc) {
                switch(product_id) {
                case 0x8116:
-                       PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
+                       Info("Sotec Afina Eye USB webcam detected.\n");
                        name = "Sotec Afina Eye";
                        type_id = 730;
                        break;
@@ -1607,7 +1829,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                switch(product_id) {
                case 0x8116:
                        /* This is essentially the same cam as the Sotec Afina Eye */
-                       PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
+                       Info("AME Co. Afina Eye USB webcam detected.\n");
                        name = "AME Co. Afina Eye";
                        type_id = 750;
                        break;
@@ -1620,12 +1842,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else if (vendor_id == 0x0d81) {
                switch(product_id) {
                case 0x1900:
-                       PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
+                       Info("Visionite VCS-UC300 USB webcam detected.\n");
                        name = "Visionite VCS-UC300";
                        type_id = 740; /* CCD sensor */
                        break;
                case 0x1910:
-                       PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
+                       Info("Visionite VCS-UM100 USB webcam detected.\n");
                        name = "Visionite VCS-UM100";
                        type_id = 730; /* CMOS sensor */
                        break;
@@ -1639,15 +1861,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
 
        memset(serial_number, 0, 30);
        usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
-       PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
+       Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
 
        if (udev->descriptor.bNumConfigurations > 1)
-               PWC_WARNING("Warning: more than 1 configuration available.\n");
+               Info("Warning: more than 1 configuration available.\n");
 
        /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
        pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
        if (pdev == NULL) {
-               PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
+               Err("Oops, could not allocate memory for pwc_device.\n");
                return -ENOMEM;
        }
        pdev->type = type_id;
@@ -1678,18 +1900,17 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        pdev->vdev = video_device_alloc();
        if (pdev->vdev == 0)
        {
-               PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
+               Err("Err, cannot allocate video_device struture. Failing probe.");
                kfree(pdev);
                return -ENOMEM;
        }
        memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
-       pdev->vdev->dev = &(udev->dev);
        strcpy(pdev->vdev->name, name);
        pdev->vdev->owner = THIS_MODULE;
        video_set_drvdata(pdev->vdev, pdev);
 
        pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
-       PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
+       Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
 
        /* Now search device_hint[] table for a match, so we can hint a node number. */
        for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
@@ -1697,10 +1918,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                     (device_hint[hint].pdev == NULL)) {
                        /* so far, so good... try serial number */
                        if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
-                               /* match! */
-                               video_nr = device_hint[hint].device_node;
-                               PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
-                               break;
+                               /* match! */
+                               video_nr = device_hint[hint].device_node;
+                               Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
+                               break;
                        }
                }
        }
@@ -1708,27 +1929,21 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        pdev->vdev->release = video_device_release;
        i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
        if (i < 0) {
-               PWC_ERROR("Failed to register as video device (%d).\n", i);
+               Err("Failed to register as video device (%d).\n", i);
                video_device_release(pdev->vdev); /* Drip... drip... drip... */
                kfree(pdev); /* Oops, no memory leaks please */
                return -EIO;
        }
        else {
-               PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
+               Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
        }
 
        /* occupy slot */
        if (hint < MAX_DEV_HINTS)
                device_hint[hint].pdev = pdev;
 
-       PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
+       Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev);
        usb_set_intfdata (intf, pdev);
-       pwc_create_sysfs_files(pdev->vdev);
-
-       /* Set the leds off */
-       pwc_set_leds(pdev, 0, 0);
-       pwc_camera_power(pdev, 0);
-
        return 0;
 }
 
@@ -1742,21 +1957,27 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        pdev = usb_get_intfdata (intf);
        usb_set_intfdata (intf, NULL);
        if (pdev == NULL) {
-               PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
+               Err("pwc_disconnect() Called without private pointer.\n");
                goto disconnect_out;
        }
        if (pdev->udev == NULL) {
-               PWC_ERROR("pwc_disconnect() already called for %p\n", pdev);
+               Err("pwc_disconnect() already called for %p\n", pdev);
                goto disconnect_out;
        }
        if (pdev->udev != interface_to_usbdev(intf)) {
-               PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
+               Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
+               goto disconnect_out;
+       }
+#ifdef PWC_MAGIC
+       if (pdev->magic != PWC_MAGIC) {
+               Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
                goto disconnect_out;
        }
+#endif
 
        /* We got unplugged; this is signalled by an EPIPE error code */
        if (pdev->vopen) {
-               PWC_INFO("Disconnected while webcam is in use!\n");
+               Info("Disconnected while webcam is in use!\n");
                pdev->error_status = EPIPE;
        }
 
@@ -1766,8 +1987,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        while (pdev->vopen)
                schedule();
        /* Device is now closed, so we can safely unregister it */
-       PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
-       pwc_remove_sysfs_files(pdev->vdev);
+       Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
        video_unregister_device(pdev->vdev);
 
        /* Free memory (don't set pdev to 0 just yet) */
@@ -1801,64 +2021,58 @@ static int pwc_atoi(const char *s)
  * Initialization code & module stuff
  */
 
-static char *size;
-static int fps;
-static int fbufs;
-static int mbufs;
+static char size[10];
+static int fps = 0;
+static int fbufs = 0;
+static int mbufs = 0;
+static int trace = -1;
 static int compression = -1;
 static int leds[2] = { -1, -1 };
-static int leds_nargs;
-static char *dev_hint[MAX_DEV_HINTS];
-static int dev_hint_nargs;
-
-module_param(size, charp, 0444);
-module_param(fps, int, 0444);
-module_param(fbufs, int, 0444);
-module_param(mbufs, int, 0444);
-#if CONFIG_PWC_DEBUG
-module_param_named(trace, pwc_trace, int, 0644);
-#endif
-module_param(power_save, int, 0444);
-module_param(compression, int, 0444);
-module_param_array(leds, int, &leds_nargs, 0444);
-module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
+static char *dev_hint[MAX_DEV_HINTS] = { };
 
+module_param_string(size, size, sizeof(size), 0);
 MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
+module_param(fps, int, 0000);
 MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
+module_param(fbufs, int, 0000);
 MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
+module_param(mbufs, int, 0000);
 MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
+module_param(trace, int, 0000);
 MODULE_PARM_DESC(trace, "For debugging purposes");
+module_param(power_save, bool, 0000);
 MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
+module_param(compression, int, 0000);
 MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
+module_param_array(leds, int, NULL, 0000);
 MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
+module_param_array(dev_hint, charp, NULL, 0000);
 MODULE_PARM_DESC(dev_hint, "Device node hints");
 
 MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
 MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("pwcx");
-MODULE_VERSION( PWC_VERSION );
 
 static int __init usb_pwc_init(void)
 {
        int i, sz;
        char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
 
-       PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
-       PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
-       PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
-       PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
+       Info("Philips webcam module version " PWC_VERSION " loaded.\n");
+       Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
+       Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
+       Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
 
        if (fps) {
                if (fps < 4 || fps > 30) {
-                       PWC_ERROR("Framerate out of bounds (4-30).\n");
+                       Err("Framerate out of bounds (4-30).\n");
                        return -EINVAL;
                }
                default_fps = fps;
-               PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
+               Info("Default framerate set to %d.\n", default_fps);
        }
 
-       if (size) {
+       if (size[0]) {
                /* string; try matching with array */
                for (sz = 0; sz < PSZ_MAX; sz++) {
                        if (!strcmp(sizenames[sz], size)) { /* Found! */
@@ -1867,42 +2081,41 @@ static int __init usb_pwc_init(void)
                        }
                }
                if (sz == PSZ_MAX) {
-                       PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
+                       Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
                        return -EINVAL;
                }
-               PWC_DEBUG_MODULE("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
+               Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
        }
        if (mbufs) {
                if (mbufs < 1 || mbufs > MAX_IMAGES) {
-                       PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
+                       Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
                        return -EINVAL;
                }
-               pwc_mbufs = mbufs;
-               PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs);
+               default_mbufs = mbufs;
+               Info("Number of image buffers set to %d.\n", default_mbufs);
        }
        if (fbufs) {
                if (fbufs < 2 || fbufs > MAX_FRAMES) {
-                       PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
+                       Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
                        return -EINVAL;
                }
                default_fbufs = fbufs;
-               PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
+               Info("Number of frame buffers set to %d.\n", default_fbufs);
        }
-#if CONFIG_PWC_DEBUG
-       if (pwc_trace >= 0) {
-               PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
+       if (trace >= 0) {
+               Info("Trace options: 0x%04x\n", trace);
+               pwc_trace = trace;
        }
-#endif
        if (compression >= 0) {
                if (compression > 3) {
-                       PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
+                       Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
                        return -EINVAL;
                }
                pwc_preferred_compression = compression;
-               PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
+               Info("Preferred compression set to %d.\n", pwc_preferred_compression);
        }
        if (power_save)
-               PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
+               Info("Enabling power save on open/close.\n");
        if (leds[0] >= 0)
                led_on = leds[0];
        if (leds[1] >= 0)
@@ -1933,14 +2146,14 @@ static int __init usb_pwc_init(void)
                                dot++;
                        /* Few sanity checks */
                        if (*dot != '\0' && dot > colon) {
-                               PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
+                               Err("Malformed camera hint: the colon must be after the dot.\n");
                                return -EINVAL;
                        }
 
                        if (*colon == '\0') {
                                /* No colon */
                                if (*dot != '\0') {
-                                       PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
+                                       Err("Malformed camera hint: no colon + device node given.\n");
                                        return -EINVAL;
                                }
                                else {
@@ -1965,27 +2178,28 @@ static int __init usb_pwc_init(void)
                                        device_hint[i].serial_number[k] = '\0';
                                }
                        }
-                       PWC_TRACE("device_hint[%d]:\n", i);
-                       PWC_TRACE("  type    : %d\n", device_hint[i].type);
-                       PWC_TRACE("  serial# : %s\n", device_hint[i].serial_number);
-                       PWC_TRACE("  node    : %d\n", device_hint[i].device_node);
+#if PWC_DEBUG
+                       Debug("device_hint[%d]:\n", i);
+                       Debug("  type    : %d\n", device_hint[i].type);
+                       Debug("  serial# : %s\n", device_hint[i].serial_number);
+                       Debug("  node    : %d\n", device_hint[i].device_node);
+#endif
                }
                else
                        device_hint[i].type = 0; /* not filled */
        } /* ..for MAX_DEV_HINTS */
 
-       PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
+       Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
        return usb_register(&pwc_driver);
 }
 
 static void __exit usb_pwc_exit(void)
 {
-       PWC_DEBUG_MODULE("Deregistering driver.\n");
+       Trace(TRACE_MODULE, "Deregistering driver.\n");
        usb_deregister(&pwc_driver);
-       PWC_INFO("Philips webcam module removed.\n");
+       Info("Philips webcam module removed.\n");
 }
 
 module_init(usb_pwc_init);
 module_exit(usb_pwc_exit);
 
-/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */