patch-2.4.10 linux/drivers/usb/pwc-if.c

Next file: linux/drivers/usb/pwc-ioctl.h
Previous file: linux/drivers/usb/pwc-ctrl.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.9/linux/drivers/usb/pwc-if.c linux/drivers/usb/pwc-if.c
@@ -35,7 +35,12 @@
    udev: struct usb_device *
    vdev: struct video_device *
    pdev: struct pwc_devive *
-*/   
+*/
+
+/* Contributors:
+   - Alvarado: adding whitebalance code
+   - Alistar Moire: QuickCam 3000 Pro testing
+*/
 
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -68,6 +73,7 @@
 	{ USB_DEVICE(0x0471, 0x0311) },
 	{ USB_DEVICE(0x0471, 0x0312) },
 	{ USB_DEVICE(0x069A, 0x0001) },
+	{ USB_DEVICE(0x046D, 0x0b80) },
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, pwc_device_table);
@@ -85,10 +91,10 @@
 
 static int default_size = PSZ_QCIF;
 static int default_fps = 10;
-static int default_palette = VIDEO_PALETTE_YUV420P; /* This is normal for webcams */
+static int default_palette = VIDEO_PALETTE_YUV420P; /* This format is understood by most tools */
 static int default_fbufs = 3;   /* Default number of frame buffers */
 static int default_mbufs = 2;	/* Default number of mmap() buffers */
-       int pwc_trace = TRACE_MODULE | TRACE_FLOW;
+       int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
 static int power_save = 0;
 int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
 
@@ -167,109 +173,90 @@
  */
 static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
 {
-	unsigned long ret = 0UL;
+        unsigned long ret = 0UL;
 	pmd_t *pmd;
 	pte_t *ptep, pte;
-
+  
 	if (!pgd_none(*pgd)) {
-		pmd = pmd_offset(pgd, adr);
-		if (!pmd_none(*pmd)) {
-			ptep = pte_offset(pmd, adr);
-			pte = *ptep;
-			if (pte_present(pte)) {
-				ret = (unsigned long) page_address(pte_page(pte));
-				ret |= (adr & (PAGE_SIZE-1));
+                pmd = pmd_offset(pgd, adr);
+                if (!pmd_none(*pmd)) {
+                        ptep = pte_offset(pmd, adr);
+                        pte = *ptep;
+                        if(pte_present(pte)) {
+				ret  = (unsigned long) page_address(pte_page(pte));
+				ret |= (adr & (PAGE_SIZE - 1));
+				
 			}
-		}
-	}
-	return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
-	unsigned long kva, ret;
-
-	kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-	ret = virt_to_bus((void *)kva);
+                }
+        }
 	return ret;
 }
 
-static inline unsigned long kvirt_to_bus(unsigned long adr)
-{
-	unsigned long va, kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = virt_to_bus((void *)kva);
-	return ret;
-}
 
 /* Here we want the physical address of the memory.
  * This is used when initializing the contents of the
  * area and marking the pages as reserved.
  */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
+static inline unsigned long kvirt_to_pa(unsigned long adr) 
 {
-	unsigned long va, kva, ret;
+        unsigned long va, kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
+        va = VMALLOC_VMADDR(adr);
+        kva = uvirt_to_kva(pgd_offset_k(va), va);
 	ret = __pa(kva);
-	return ret;
+        return ret;
 }
 
-static void *rvmalloc(unsigned long size)
+static void * rvmalloc(signed long size)
 {
-	void *mem;
+	void * mem;
 	unsigned long adr, page;
 
-	/* Round it off to PAGE_SIZE */
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
-
-	mem = vmalloc(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) {
-		page = kvirt_to_pa(adr);
-		mem_map_reserve(MAP_NR(__va(page)));
-		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+        /* Round it off to PAGE_SIZE */
+        size += (PAGE_SIZE - 1);
+        size &= ~(PAGE_SIZE - 1);	
+        
+        mem=vmalloc_32(size);
+	if (mem) 
+	{
+		memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+	        adr=(unsigned long) mem;
+		while (size > 0) 
+                {
+	                page = kvirt_to_pa(adr);
+			mem_map_reserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
 	}
 	return mem;
 }
 
-static void rvfree(void *mem, unsigned long size)
+static void rvfree(void * mem, signed long size)
 {
-	unsigned long adr, page;
-
-	if (!mem)
-		return;
-
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
-
-	adr=(unsigned long) mem;
-	while (size > 0) {
-		page = kvirt_to_pa(adr);
-		mem_map_unreserve(MAP_NR(__va(page)));
-		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+        unsigned long adr, page;
+        
+        /* Round it off to PAGE_SIZE */
+        size += (PAGE_SIZE - 1);
+        size &= ~(PAGE_SIZE - 1);	
+	if (mem) 
+	{
+	        adr=(unsigned long) mem;
+		while (size > 0) 
+                {
+	                page = kvirt_to_pa(adr);
+			mem_map_unreserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+		vfree(mem);
 	}
-	vfree(mem);
 }
 
 
 
+
 static int pwc_allocate_buffers(struct pwc_device *pdev)
 {
 	int i;
@@ -294,6 +281,7 @@
 				Err("Failed to allocate iso buffer %d.\n", i);
 				return -ENOMEM;
 			}
+			Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
 			pdev->sbuf[i].data = kbuf;
 			memset(kbuf, 0, ISO_BUFFER_SIZE);
 		}
@@ -306,19 +294,21 @@
 			Err("Failed to allocate frame buffer structure.\n");
 			return -ENOMEM;
 		}
+		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(FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
+			kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
 			if (kbuf == NULL) {
 				Err("Failed to allocate frame buffer %d.\n", i);
 				return -ENOMEM;
 			}
+			Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
 			pdev->fbuf[i].data = kbuf;
-			memset(kbuf, 0, FRAME_SIZE);
+			memset(kbuf, 128, PWC_FRAME_SIZE);
 		}
 	}
 	
@@ -330,23 +320,24 @@
 			Err("Failed to allocate decompress table.\n");
 			return -ENOMEM;
 		}
+		Trace(TRACE_MEMORY, "Allocated decompress table %p.\n", kbuf);
 	}
 	pdev->decompress_data = kbuf;
 	
 	/* Allocate image buffer; double buffer for mmap() */
-	kbuf = rvmalloc(default_mbufs * pdev->view_max.size * 4);
+	kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
 	if (kbuf == NULL) {
 		Err("Failed to allocate image buffer(s).\n");
 		return -ENOMEM;
 	}
+	Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
 	pdev->image_data = kbuf;
 	for (i = 0; i < default_mbufs; i++)
-		pdev->image_ptr[i] = kbuf + (i * pdev->view_max.size * 4);
+		pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
 	for (; i < MAX_IMAGES; i++)
 		pdev->image_ptr[i] = NULL;
 
 	Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n");
-
 	return 0;
 }
 
@@ -366,18 +357,18 @@
 #endif	
 
 	/* Release Iso-pipe buffers */
-	Trace(TRACE_MEMORY, "Freeing ISO buffers.\n");
 	for (i = 0; i < MAX_ISO_BUFS; i++)
 		if (pdev->sbuf[i].data != NULL) {
+			Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
 			kfree(pdev->sbuf[i].data);
 			pdev->sbuf[i].data = NULL;
 		}
 
 	/* The same for frame buffers */
-	Trace(TRACE_MEMORY, "Freeing frame buffers.\n");
 	if (pdev->fbuf != NULL) {
 		for (i = 0; i < default_fbufs; i++) {
 			if (pdev->fbuf[i].data != NULL) {
+				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;
 			}
@@ -387,17 +378,18 @@
 	}
 
 	/* Intermediate decompression buffer & tables */
-	Trace(TRACE_MEMORY, "Freeing decompression buffer\n");
 	if (pdev->decompress_data != NULL) {
+		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 */
-	Trace(TRACE_MEMORY, "Freeing image buffers\n");
-	if (pdev->image_data != NULL)
-		rvfree(pdev->image_data, default_mbufs * pdev->view_max.size * 4);
+	if (pdev->image_data != NULL) {
+		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;
 	Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
 }
@@ -461,7 +453,8 @@
  */
 static inline int pwc_next_fill_frame(struct pwc_device *pdev)
 {
-	int ret, flags;
+	int ret;
+	unsigned long flags;
 	
 	ret = 0;
 	spin_lock_irqsave(&pdev->ptrlock, flags);
@@ -512,7 +505,8 @@
  */
 static void pwc_reset_buffers(struct pwc_device *pdev)
 {
-	int i, flags;
+	int i;
+	unsigned long flags;
 
 	spin_lock_irqsave(&pdev->ptrlock, flags);
 	pdev->full_frames = NULL;
@@ -541,7 +535,8 @@
  */
 static int pwc_handle_frame(struct pwc_device *pdev)
 {
-	int ret = 0, flags;
+	int ret = 0;
+	unsigned long flags;
 	
 	spin_lock_irqsave(&pdev->ptrlock, flags);
 	/* First grab our read_frame; this is removed from all lists, so
@@ -610,6 +605,7 @@
 		pwc_set_image_buffer_size(pdev);
 		return 0;
 	}
+	Trace(TRACE_READ, "Palette %d not supported.\n", pal);
 	return -1;
 }
 
@@ -642,7 +638,17 @@
 		return;
 	}
 	if (urb->status != -EINPROGRESS && urb->status != 0) {
-		Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d.\n", urb->status);
+		char *errmsg;
+		
+		errmsg = "Unknown";
+		switch(urb->status) {
+			case -ENOSR:		errmsg = "Buffer error (overrun)"; break;
+			case -EPIPE:		errmsg = "Babble/stalled (bad cable?)"; break;
+			case -EPROTO:		errmsg = "Bit-stuff error (bad cable?)"; break;
+			case -EILSEQ:		errmsg = "CRC/Timeout"; break;
+			case -ETIMEDOUT:	errmsg = "NAK (device does not respond)"; break;
+		}
+		Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
 		return;
 	}
 
@@ -739,9 +745,9 @@
 								pdev->vframes_dumped++;
 								if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
 									if (pdev->vframes_dumped < 20)
-										Info("Dumping frame %d.\n", pdev->vframe_count);
+										Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
 									if (pdev->vframes_dumped == 20)
-										Info("Dumping frame %d (last message).\n", pdev->vframe_count);
+										Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
 								}
 							}
 							fbuf = pdev->fill_frame;
@@ -1104,7 +1110,7 @@
 	if (pdev == NULL)
 		return -EFAULT;
 	if (pdev->unplugged) {
-		Debug("pwc_video_read: Device got unplugged (1).\n");
+		Info("pwc_video_read: Device got unplugged (1).\n");
 		return -EPIPE; /* unplugged device! */
 	}
 
@@ -1166,7 +1172,7 @@
 	
 	poll_wait(file, &pdev->frameq, wait);
 	if (pdev->unplugged) {
-		Debug("pwc_video_poll: Device got unplugged.\n");
+		Info("pwc_video_poll: Device got unplugged.\n");
 		return POLLERR;
 	}		
 	if (pdev->full_frames != NULL) /* we have frames waiting */
@@ -1370,10 +1376,10 @@
 			int i;
 
 			memset(&vm, 0, sizeof(vm));
-			vm.size = default_mbufs * pdev->view_max.size * 4;
-			vm.frames = default_mbufs; /* double buffering should be enough */
+			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->view_max.size * 4;
+				vm.offsets[i] = i * pdev->len_per_image;
 
 			if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
 				return -EFAULT;
@@ -1546,11 +1552,10 @@
 	unsigned long start = (unsigned long)adr;
 	unsigned long page, pos;
 	
-	Trace(TRACE_READ, "mmap(0x%p, 0x%p, %lu) called.\n", vdev, adr, size);
+	Trace(TRACE_MEMORY, "mmap(0x%p, 0x%p, %lu) called.\n", vdev, adr, size);
 	pdev = vdev->priv;
 
 	/* FIXME - audit mmap during a read */		
-
 	pos = (unsigned long)pdev->image_data;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
@@ -1651,7 +1656,18 @@
 			break;
 		}
 	}
-	else return NULL; /* Not Philips or Askey, for sure. */
+        else if (vendor_id == 0x046d) {
+        	switch(product_id) {
+        	case 0x08b0:
+        		Info("Logitech QuickCam 3000 Pro detected.\n");
+        		type_id = 730;
+        		break;
+        	default:
+        		return NULL;
+        		break;
+        	}
+        }
+        else return NULL; /* Not Philips or Askey, for sure. */
 
 	if (udev->descriptor.bNumConfigurations > 1)
 		Info("Warning: more than 1 configuration available.\n");
@@ -1718,6 +1734,7 @@
 {
 	struct pwc_device *pdev;
 
+	lock_kernel();
 	free_mem_leak();
 
 	pdev = (struct pwc_device *)ptr;
@@ -1770,6 +1787,7 @@
 		}
 	}
 	pdev->udev = NULL;
+	unlock_kernel();
 	kfree(pdev);
 }
 
@@ -1807,6 +1825,7 @@
 
 MODULE_DESCRIPTION("Philips USB webcam driver");
 MODULE_AUTHOR("Nemosoft Unv. <nemosoft@smcc.demon.nl>");
+MODULE_LICENSE("GPL");
 
 static int __init usb_pwc_init(void)
 {
@@ -1847,8 +1866,6 @@
 			default_palette = VIDEO_PALETTE_YUV420P;
 		else {
 			Err("Palette not recognized: try palette=yuv420 or yuv420p.\n");
-			Info("Download the driver from http://www.smcc.demon.nl/webcam/ for in kernel\n");
-			Info("format conversion support.\n");
 			return -EINVAL;
 		}
 		Info("Default palette set to %d.\n", default_palette);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)