patch-2.4.20 linux-2.4.20/drivers/media/video/cpia.c

Next file: linux-2.4.20/drivers/media/video/cpia.h
Previous file: linux-2.4.20/drivers/media/video/bttvp.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/drivers/media/video/cpia.c linux-2.4.20/drivers/media/video/cpia.c
@@ -56,7 +56,7 @@
 
 #ifdef MODULE
 MODULE_PARM(video_nr,"i");
-MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
+MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfeld.com>");
 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("video");
@@ -163,6 +163,7 @@
 #define COMMAND_SETAPCOR		0x1000
 #define COMMAND_SETFLICKERCTRL		0x2000
 #define COMMAND_SETVLOFFSET		0x4000
+#define COMMAND_SETLIGHTS		0x8000
 
 /* Developer's Guide Table 5 p 3-34
  * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
@@ -178,50 +179,17 @@
  *
  * Memory management
  *
- * This is a shameless copy from the USB-cpia driver (linux kernel
- * version 2.3.29 or so, I have no idea what this code actually does ;).
- * Actually it seems to be a copy of a shameless copy of the bttv-driver.
- * Or that is a copy of a shameless copy of ... (To the powers: is there
- * no generic kernel-function to do this sort of stuff?)
- *
- * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
- * there will be one, but apparentely not yet - jerdfelt
- *
  **********************************************************************/
 
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-	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));
-			}
-		}
-	}
-	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.
+ * This is used when initializing the contents of the area.
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr)
 {
-	unsigned long va, kva, ret;
+	unsigned long kva, ret;
 
-	va = VMALLOC_VMADDR(adr);
-	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
 	ret = __pa(kva);
 	return ret;
 }
@@ -229,12 +197,9 @@
 static void *rvmalloc(unsigned long size)
 {
 	void *mem;
-	unsigned long adr, page;
-
-	/* Round it off to PAGE_SIZE */
-	size += (PAGE_SIZE - 1);
-	size &= ~(PAGE_SIZE - 1);
+	unsigned long adr;
 
+	size = PAGE_ALIGN(size);
 	mem = vmalloc_32(size);
 	if (!mem)
 		return NULL;
@@ -242,13 +207,9 @@
 	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)));
+		mem_map_reserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 
 	return mem;
@@ -256,23 +217,16 @@
 
 static void rvfree(void *mem, unsigned long size)
 {
-	unsigned long adr, page;
+	unsigned long adr;
 
 	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(virt_to_page(__va(page)));
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
 		adr += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
+		size -= PAGE_SIZE;
 	}
 	vfree(mem);
 }
@@ -291,7 +245,7 @@
 	char *out = page;
 	int len, tmp;
 	struct cam_data *cam = data;
-	char tmpstr[20];
+	char tmpstr[29];
 
 	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
 	 *            or we need to get more sophisticated. */
@@ -328,6 +282,13 @@
 	               cam->params.status.vpStatus);
 	out += sprintf(out, "error_code:               %#04x\n",
 	               cam->params.status.errorCode);
+	/* QX3 specific entries */
+	if (cam->params.qx3.qx3_detected) {
+		out += sprintf(out, "button:                   %4d\n",
+		               cam->params.qx3.button);
+		out += sprintf(out, "cradled:                  %4d\n",
+		               cam->params.qx3.cradled);
+	}
 	out += sprintf(out, "video_size:               %s\n",
 	               cam->params.format.videoSize == VIDEOSIZE_CIF ?
 		       "CIF " : "QCIF");
@@ -392,16 +353,17 @@
 	if (cam->params.version.firmwareVersion == 1 &&
 	   cam->params.version.firmwareRevision == 2)
 		/* 1-02 firmware limits gain to 2 */
-		sprintf(tmpstr, "%8d  %8d", 1, 2);
+		sprintf(tmpstr, "%8d  %8d  %8d", 1, 2, 2);
 	else
-		sprintf(tmpstr, "1,2,4,8");
+		sprintf(tmpstr, "%8d  %8d  %8d", 1, 8, 2);
 
 	if (cam->params.exposure.gainMode == 0)
-		out += sprintf(out, "max_gain:                unknown  %18s"
-		               "  %8d\n", tmpstr, 2); 
+		out += sprintf(out, "max_gain:                unknown  %28s"
+		               "  powers of 2\n", tmpstr); 
 	else
-		out += sprintf(out, "max_gain:               %8d  %18s  %8d\n", 
-		               1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
+		out += sprintf(out, "max_gain:               %8d  %28s"
+			       "  1,2,4 or 8 \n",
+		               1<<(cam->params.exposure.gainMode-1), tmpstr);
 
 	switch(cam->params.exposure.expMode) {
 	case 1:
@@ -528,6 +490,15 @@
 	out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
 	               cam->params.compressionParams.decimationThreshMod,
 		       0, 255, 2);
+	/* QX3 specific entries */
+	if (cam->params.qx3.qx3_detected) {
+		out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n", 
+		               cam->params.qx3.toplight ? "on" : "off",
+			       "off", "on", "off");
+		out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n", 
+		               cam->params.qx3.bottomlight ? "on" : "off",
+			       "off", "on", "off");
+	}
 	
 	len = out - page;
 	len -= off;
@@ -541,18 +512,45 @@
 	return len;
 }
 
-static int cpia_write_proc(struct file *file, const char *buffer,
+static int cpia_write_proc(struct file *file, const char *buf,
                            unsigned long count, void *data)
 {
-	return -EINVAL;
-#if 0
 	struct cam_data *cam = data;
 	struct cam_params new_params;
+	char *page, *buffer;
 	int retval, find_colon;
 	int size = count;
-	unsigned long val;
+	unsigned long val = 0;
 	u32 command_flags = 0;
 	u8 new_mains;
+
+	/*
+	 * This code to copy from buf to page is shamelessly copied
+	 * from the comx driver
+	 */
+	if (count > PAGE_SIZE) {
+		printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
+		return -ENOSPC;
+	}
+
+	if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
+
+	if(copy_from_user(page, buf, count))
+	{
+		retval = -EFAULT;
+		goto out;
+	}
+
+	if (page[count-1] == '\n')
+		page[count-1] = '\0';
+	else if (count < PAGE_SIZE)
+		page[count] = '\0';
+	else if (page[count]) {
+		retval = -EINVAL;
+		goto out;
+	}
+	
+	buffer = page;
 	
 	if (down_interruptible(&cam->param_lock))
 		return -ERESTARTSYS;
@@ -1210,6 +1208,22 @@
 					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("toplight")) {
+		        if (!retval && MATCH("on"))
+				new_params.qx3.toplight = 1;
+			else if (!retval && MATCH("off"))
+				new_params.qx3.toplight = 0;
+			else 
+				retval = -EINVAL;
+			command_flags |= COMMAND_SETLIGHTS;
+		} else if (MATCH("bottomlight")) {
+		        if (!retval && MATCH("on"))
+				new_params.qx3.bottomlight = 1;
+			else if (!retval && MATCH("off"))  
+				new_params.qx3.bottomlight = 0;
+			else 
+				retval = -EINVAL;
+			command_flags |= COMMAND_SETLIGHTS;
 		} else {
 			DBG("No match found\n");
 			retval = -EINVAL;
@@ -1221,7 +1235,10 @@
 				++buffer;
 			}
 			if (count) {
-				if (*buffer != '\n' && *buffer != ';')
+				if (*buffer == '\0' && count != 1)
+					retval = -EINVAL;
+				else if (*buffer != '\n' && *buffer != ';' &&
+					 *buffer != '\0')
 					retval = -EINVAL;
 				else {
 					--count;
@@ -1255,8 +1272,9 @@
 	
 	up(&cam->param_lock);
 	
+out:
+	free_page((unsigned long)page);
 	return retval;
-#endif
 }
 
 static void create_proc_cpia_cam(struct cam_data *cam)
@@ -1276,7 +1294,12 @@
 	ent->data = cam;
 	ent->read_proc = cpia_read_proc;
 	ent->write_proc = cpia_write_proc;
-	ent->size = 3626;
+	/* 
+	   size of the proc entry is 3672 bytes for the standard webcam;
+ 	   the extra features of the QX3 microscope add 188 bytes.
+	   (we have not yet probed the camera to see which type it is).
+	*/
+	ent->size = 3672 + 188;
 	cam->proc_entry = ent;
 }
 
@@ -1570,6 +1593,10 @@
 		down(&cam->param_lock);
 		datasize=8;
 		break;
+	case CPIA_COMMAND_ReadMCPorts: 
+	case CPIA_COMMAND_ReadVCRegs:
+		datasize = 4;
+		break;
 	default:
 		datasize=0;
 		break;
@@ -1667,6 +1694,22 @@
 			  }
 			up(&cam->param_lock);
 			break;
+
+		case CPIA_COMMAND_ReadMCPorts: 
+			if (!cam->params.qx3.qx3_detected) 
+				break;
+			/* test button press */ 
+			cam->params.qx3.button = ((data[1] & 0x02) == 0);
+			if (cam->params.qx3.button) {
+				/* button pressed - unlock the latch */
+				do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
+				do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
+			}
+
+			/* test whether microscope is cradled */
+			cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
+			break;
+
 		default:
 			break;
 		}
@@ -1826,6 +1869,7 @@
 {
 	switch(fmt) {
 	case VIDEO_PALETTE_GREY:
+		return count;
 	case VIDEO_PALETTE_RGB555:
 	case VIDEO_PALETTE_RGB565:
 	case VIDEO_PALETTE_YUV422:
@@ -2106,6 +2150,13 @@
 	if (cam->cmd_queue & COMMAND_RESUME)
 		init_stream_cap(cam);
 
+	if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) {
+		int p1 = (cam->params.qx3.bottomlight == 0) << 1;
+		int p2 = (cam->params.qx3.toplight == 0) << 3;
+		do_command(cam, CPIA_COMMAND_WriteVCReg,  0x90, 0x8F, 0x50, 0);
+		do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
+	}
+
 	up(&cam->param_lock);
 	cam->cmd_queue = COMMAND_NONE;
 	return;
@@ -2182,9 +2233,10 @@
 		/* camera idle now so dispatch queued commands */
 		dispatch_commands(cam);
 
-		/* Update our knowledge of the camera state - FIXME: necessary? */
+		/* Update our knowledge of the camera state */
 		do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
 		do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+		do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
 
 		/* decompress and convert image to by copying it from
 		 * raw_image to decompressed_frame
@@ -2396,7 +2448,11 @@
 	get_version_information(cam);
 	if (cam->params.version.firmwareVersion != 1)
 		return -ENODEV;
-	
+
+	/* set QX3 detected flag */
+	cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
+					cam->params.pnpID.product == 0x0001);
+
 	/* The fatal error checking should be done after
 	 * the camera powers up (developer's guide p 3-38) */
 
@@ -2526,7 +2582,7 @@
 		/* GotoLoPower */
 		goto_low_power(cam);
 
-		/* Update the camera ststus */
+		/* Update the camera status */
 		do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
 
 		/* cleanup internal state stuff */
@@ -2566,7 +2622,7 @@
 {
 	struct cam_data *cam = dev->priv;
 
-	/* make this _really_ smp and multithredi-safe */
+	/* make this _really_ smp and multithread-safe */
 	if (down_interruptible(&cam->busy_lock))
 		return -EINTR;
 
@@ -2793,7 +2849,6 @@
 			cam->cmd_queue |= COMMAND_SETFORMAT;
 		}
 
-		// FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw));
 		up(&cam->param_lock);
 
 		/* setformat ignored by camera during streaming,
@@ -2835,10 +2890,8 @@
 			retval = -EFAULT;
 			break;
 		}
-#if 1
 		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
 		    vm.width, vm.height);
-#endif
 		if (vm.frame<0||vm.frame>=FRAME_NUM) {
 			retval = -EINVAL;
 			break;
@@ -2848,6 +2901,8 @@
 		cam->vp.palette = vm.format;
 		switch(vm.format) {
 		case VIDEO_PALETTE_GREY:
+			cam->vp.depth=8;
+			break;
 		case VIDEO_PALETTE_RGB555:
 		case VIDEO_PALETTE_RGB565:
 		case VIDEO_PALETTE_YUV422:
@@ -2880,10 +2935,6 @@
 			cam->cmd_queue |= COMMAND_SETFORMAT;
 			dispatch_commands(cam);
 		}
-#if 0
-		DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size,
-		    cam->vw.width, cam->vw.height);
-#endif
 		/* according to v4l-spec we must start streaming here */
 		cam->mmap_kludge = 1;
 		retval = capture_frame(cam, &vm);
@@ -3035,7 +3086,7 @@
 	owner:		THIS_MODULE,
 	name:		"CPiA Camera",
 	type:		VID_TYPE_CAPTURE,
-	hardware:	VID_HARDWARE_CPIA,      /* FIXME */
+	hardware:	VID_HARDWARE_CPIA,
 	open:		cpia_open,
 	close:		cpia_close,
 	read:		cpia_read,
@@ -3100,8 +3151,8 @@
 	cam->params.sensorFps.divisor = 1;
 	cam->params.sensorFps.baserate = 1;
 	
-	cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */
-	cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */
+	cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
+	cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
 	
 	cam->params.format.subSample = SUBSAMPLE_422;
 	cam->params.format.yuvOrder = YUVORDER_YUYV;
@@ -3109,8 +3160,14 @@
 	cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
 	cam->params.compressionTarget.frTargeting =
 		CPIA_COMPRESSION_TARGET_QUALITY;
-	cam->params.compressionTarget.targetFR = 7; /* FIXME? */
-	cam->params.compressionTarget.targetQ = 10; /* FIXME? */
+	cam->params.compressionTarget.targetFR = 15; /* From windows driver */
+	cam->params.compressionTarget.targetQ = 5; /* From windows driver */
+
+	cam->params.qx3.qx3_detected = 0;
+	cam->params.qx3.toplight = 0;
+	cam->params.qx3.bottomlight = 0;
+	cam->params.qx3.button = 0;
+	cam->params.qx3.cradled = 0;
 
 	cam->video_size = VIDEOSIZE_CIF;
 	
@@ -3119,8 +3176,8 @@
 	cam->vp.brightness = 32768;  /* 50% */
 	cam->vp.contrast = 32768;    /* 50% */
 	cam->vp.whiteness = 0;       /* not used -> grayscale only */
-	cam->vp.depth = 0;           /* FIXME: to be set by user? */
-	cam->vp.palette = VIDEO_PALETTE_RGB24;         /* FIXME: to be set by user? */
+	cam->vp.depth = 24;          /* to be set by user */
+	cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
 
 	cam->vw.x = 0;
 	cam->vw.y = 0;
@@ -3209,12 +3266,6 @@
 	/* close cpia */
 	camera->ops->close(camera->lowlevel_data);
 
-/* Eh? Feeling happy? - jerdfelt */
-/*
-	camera->ops->open(camera->lowlevel_data);
-	camera->ops->close(camera->lowlevel_data);
-*/
-	
 	printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
 	       camera->params.version.firmwareVersion,
 	       camera->params.version.firmwareRevision,

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