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

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

diff -urN linux-2.4.20/drivers/media/video/cpia.c linux-2.4.21/drivers/media/video/cpia.c
@@ -6,6 +6,7 @@
  * (C) Copyright 1999-2000 Peter Pregler
  * (C) Copyright 1999-2000 Scott J. Bertin
  * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
+ * (C) Copyright 2000 STMicroelectronics
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,7 +23,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-/* #define _CPIA_DEBUG_		define for verbose debug output */
+/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
+/* #define _CPIA_DEBUG_  1 */  
+
 #include <linux/config.h>
 
 #include <linux/module.h>
@@ -512,6 +515,46 @@
 	return len;
 }
 
+static int match(char *checkstr, char **buffer, unsigned long *count,
+                 int *find_colon, int *err)
+{
+	int ret, colon_found = 1;
+	int len = strlen(checkstr);
+	ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
+	if (ret) {
+		*buffer += len;
+		*count -= len;
+		if (*find_colon) {
+			colon_found = 0;
+			while (*count && (**buffer == ' ' || **buffer == '\t' ||
+			       (!colon_found && **buffer == ':'))) {
+				if (**buffer == ':')
+					colon_found = 1;
+				--*count;
+				++*buffer;
+			}
+			if (!*count || !colon_found)
+				*err = -EINVAL;
+			*find_colon = 0;
+		}
+	}
+	return ret;
+}
+
+static unsigned long int value(char **buffer, unsigned long *count, int *err)
+{
+	char *p;
+	unsigned long int ret;
+	ret = simple_strtoul(*buffer, &p, 0);
+	if (p == *buffer)
+		*err = -EINVAL;
+	else {
+		*count -= p - *buffer;
+		*buffer = p;
+	}
+	return ret;
+}
+
 static int cpia_write_proc(struct file *file, const char *buf,
                            unsigned long count, void *data)
 {
@@ -566,44 +609,11 @@
 	memcpy(&new_params, &cam->params, sizeof(struct cam_params));
 	new_mains = cam->mainsFreq;
 	
-#define MATCH(x) \
-	({ \
-		int _len = strlen(x), _ret, _colon_found; \
-		_ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
-		if (_ret) { \
-			buffer += _len; \
-			count -= _len; \
-			if (find_colon) { \
-				_colon_found = 0; \
-				while (count && (*buffer == ' ' || *buffer == '\t' || \
-				       (!_colon_found && *buffer == ':'))) { \
-					if (*buffer == ':')  \
-						_colon_found = 1; \
-					--count; \
-					++buffer; \
-				} \
-				if (!count || !_colon_found) \
-					retval = -EINVAL; \
-				find_colon = 0; \
-			} \
-		} \
-		_ret; \
-	})
+#define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
+#define VALUE (value(&buffer,&count, &retval))
 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
                                new_params.version.firmwareRevision == (y))
-#define VALUE \
-	({ \
-		char *_p; \
-		unsigned long int _ret; \
-		_ret = simple_strtoul(buffer, &_p, 0); \
-		if (_p == buffer) \
-			retval = -EINVAL; \
-		else { \
-			count -= _p - buffer; \
-			buffer = _p; \
-		} \
-		_ret; \
-	})
+
 
 	retval = 0;
 	while (count && !retval) {
@@ -1248,10 +1258,9 @@
 		}
 	}
 #undef MATCH	
-#undef FIRMWARE_VERSION
 #undef VALUE
-#undef FIND_VALUE
-#undef FIND_END
+#undef FIRMWARE_VERSION
+
 	if (!retval) {
 		if (command_flags & COMMAND_SETCOLOURPARAMS) {
 			/* Adjust cam->vp to reflect these changes */
@@ -1560,7 +1569,7 @@
 }
 
 
-static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
+static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
 {
 	int i;
 
@@ -1745,7 +1754,7 @@
 
 	retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
 	if (retval)
-		LOG("%x - failed\n", command);
+		DBG("%x - failed\n", command);
 
 	return retval;
 }
@@ -1970,7 +1979,7 @@
 	while (size > 0) {
 		size -= (ll+2);
 		if (size < 0) {
-			LOG("Insufficient data in buffer\n");
+			DBG("Insufficient data in buffer\n");
 			return -1;
 		}
 
@@ -1985,7 +1994,7 @@
 				int skipsize = skipcount(*ibuf >> 1, out_fmt);
 				obuf += skipsize;
 				if (obuf > end_obuf) {
-					LOG("Insufficient data in buffer\n");
+					DBG("Insufficient data in buffer\n");
 					return -1;
 				}
 				++ibuf;
@@ -1994,7 +2003,7 @@
 		}
 		if (ll == 1) {
 			if (*ibuf != EOL) {
-				LOG("EOL not found giving up after %d/%d"
+				DBG("EOL not found giving up after %d/%d"
 				    " bytes\n", origsize-size, origsize);
 				return -1;
 			}
@@ -2012,7 +2021,7 @@
 				ibuf += 2; /* skip over line length */
 			}
 		} else {
-			LOG("line length was not 1 but %d after %d/%d bytes\n",
+			DBG("line length was not 1 but %d after %d/%d bytes\n",
 			    ll, origsize-size, origsize);
 			return -1;
 		}
@@ -2501,54 +2510,56 @@
 	return 0;
 }
 
+static void put_cam(struct cpia_camera_ops* ops)
+{
+	if (ops->owner)
+		__MOD_DEC_USE_COUNT(ops->owner);
+}
+
 /* ------------------------- V4L interface --------------------- */
-static int cpia_open(struct video_device *dev, int flags)
+static int cpia_open(struct inode *inode, struct file *file)
 {
-	int i;
+	struct video_device *dev = video_devdata(file);
 	struct cam_data *cam = dev->priv;
+	int err;
 
 	if (!cam) {
 		DBG("Internal error, cam_data not found!\n");
-		return -EBUSY;
+		return -ENODEV;
 	}
-	    
+
 	if (cam->open_count > 0) {
 		DBG("Camera already open\n");
 		return -EBUSY;
 	}
-	
+
+	if (!try_inc_mod_count(cam->ops->owner))
+	  return -ENODEV;
+
+	down(&cam->busy_lock);
+
+	err = -ENOMEM;	
 	if (!cam->raw_image) {
 		cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
 		if (!cam->raw_image)
-			return -ENOMEM;
+			goto oops;
 	}
 
 	if (!cam->decompressed_frame.data) {
 		cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
-		if (!cam->decompressed_frame.data) {
-			rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-			cam->raw_image = NULL;
-			return -ENOMEM;
-		}
+		if (!cam->decompressed_frame.data) 
+			goto oops;
 	}
 	
 	/* open cpia */
-	if (cam->ops->open(cam->lowlevel_data)) {
-		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
-		cam->decompressed_frame.data = NULL;
-		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-		cam->raw_image = NULL;
-		return -ENODEV;
-	}
+	err = -ENODEV;
+	if (cam->ops->open(cam->lowlevel_data)) 
+		goto oops;
 	
 	/* reset the camera */
-	if ((i = reset_camera(cam)) != 0) {
+	if ((err = reset_camera(cam)) != 0) {
 		cam->ops->close(cam->lowlevel_data);
-		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
-		cam->decompressed_frame.data = NULL;
-		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-		cam->raw_image = NULL;
-		return i;
+		goto oops;
 	}
 	
 	/* Set ownership of /proc/cpia/videoX to current user */
@@ -2562,14 +2573,28 @@
 	cam->mmap_kludge = 0;
 	
 	++cam->open_count;
+	file->private_data = dev;
+	up(&cam->busy_lock);
 	return 0;
+
+ oops:
+	if (cam->decompressed_frame.data) {
+		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+		cam->decompressed_frame.data = NULL;
+	}
+	if (cam->raw_image) {
+		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+		cam->raw_image = NULL;
+	}
+	up(&cam->busy_lock);
+	put_cam(cam->ops);
+	return err;
 }
 
-static void cpia_close(struct video_device *dev)
+static int cpia_close(struct inode *inode, struct file *file)
 {
-	struct cam_data *cam;
-
-	cam = dev->priv;
+	struct  video_device *dev = file->private_data;
+	struct cam_data *cam = dev->priv;
 
 	if (cam->ops) {
 	        /* Return ownership of /proc/cpia/videoX to root */
@@ -2590,6 +2615,7 @@
 
 		/* close cpia */
 		cam->ops->close(cam->lowlevel_data);
+		put_cam(cam->ops);
 	}
 
 	if (--cam->open_count == 0) {
@@ -2607,20 +2633,20 @@
 		if (cam->frame_buf)
 			free_frame_buf(cam);
 
-		if (!cam->ops) {
-			video_unregister_device(dev);
+		if (!cam->ops) 
 			kfree(cam);
-		}
 	}
 	
+	file->private_data = NULL;
 
-	return;
+	return 0;
 }
 
-static long cpia_read(struct video_device *dev, char *buf,
-                      unsigned long count, int noblock)
+static int cpia_read(struct file *file, char *buf,
+		     size_t count, loff_t *ppos)
 {
-	struct cam_data *cam = dev->priv;
+	struct video_device *dev = file->private_data;
+ 	struct cam_data *cam = dev->priv;
 
 	/* make this _really_ smp and multithread-safe */
 	if (down_interruptible(&cam->busy_lock))
@@ -2659,7 +2685,7 @@
 	/* copy data to user space */
 	if (cam->decompressed_frame.count > count) {
 		DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
-		    count);
+		    (unsigned long) count);
 		up(&cam->busy_lock);
 		return -EFAULT;
 	}
@@ -2674,8 +2700,10 @@
 	return cam->decompressed_frame.count;
 }
 
-static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
+static int cpia_do_ioctl(struct inode *inode, struct file *file,
+			 unsigned int ioctlnr, void *arg)
 {
+	struct video_device *dev = file->private_data;
 	struct cam_data *cam = dev->priv;
 	int retval = 0;
 
@@ -2692,20 +2720,17 @@
 	/* query capabilites */
 	case VIDIOCGCAP:
 	{
-		struct video_capability b;
+		struct video_capability *b = arg;
 
 		DBG("VIDIOCGCAP\n");
-		strcpy(b.name, "CPiA Camera");
-		b.type = VID_TYPE_CAPTURE;
-		b.channels = 1;
-		b.audios = 0;
-		b.maxwidth = 352;	/* VIDEOSIZE_CIF */
-		b.maxheight = 288;
-		b.minwidth = 48;	/* VIDEOSIZE_48_48 */
-		b.minheight = 48;
-
-		if (copy_to_user(arg, &b, sizeof(b)))
-			retval = -EFAULT;
+		strcpy(b->name, "CPiA Camera");
+		b->type = VID_TYPE_CAPTURE;
+		b->channels = 1;
+		b->audios = 0;
+		b->maxwidth = 352;	/* VIDEOSIZE_CIF */
+		b->maxheight = 288;
+		b->minwidth = 48;	/* VIDEOSIZE_48_48 */
+		b->minheight = 48;
 
 		break;
 	}
@@ -2713,39 +2738,30 @@
 	/* get/set video source - we are a camera and nothing else */
 	case VIDIOCGCHAN:
 	{
-		struct video_channel v;
+		struct video_channel *v = arg;
 
 		DBG("VIDIOCGCHAN\n");
-		if (copy_from_user(&v, arg, sizeof(v))) {
-			retval = -EFAULT;
-			break;
-		}
-		if (v.channel != 0) {
+		if (v->channel != 0) {
 			retval = -EINVAL;
 			break;
 		}
 
-		v.channel = 0;
-		strcpy(v.name, "Camera");
-		v.tuners = 0;
-		v.flags = 0;
-		v.type = VIDEO_TYPE_CAMERA;
-		v.norm = 0;
+		v->channel = 0;
+		strcpy(v->name, "Camera");
+		v->tuners = 0;
+		v->flags = 0;
+		v->type = VIDEO_TYPE_CAMERA;
+		v->norm = 0;
 
-		if (copy_to_user(arg, &v, sizeof(v)))
-			retval = -EFAULT;
 		break;
 	}
 	
 	case VIDIOCSCHAN:
 	{
-		int v;
+		struct video_channel *v = arg;
 
 		DBG("VIDIOCSCHAN\n");
-		if (copy_from_user(&v, arg, sizeof(v)))
-			retval = -EFAULT;
-
-		if (retval == 0 && v != 0)
+		if (v->channel != 0)
 			retval = -EINVAL;
 
 		break;
@@ -2753,38 +2769,35 @@
 
 	/* image properties */
 	case VIDIOCGPICT:
+	{
+ 		struct video_picture *pic = arg;
+
 		DBG("VIDIOCGPICT\n");
-		if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture)))
-			retval = -EFAULT;
+ 		*pic = cam->vp;
 		break;
-	
+	}
+
 	case VIDIOCSPICT:
 	{
-		struct video_picture vp;
+		struct video_picture *vp = arg;
 
 		DBG("VIDIOCSPICT\n");
 
-		/* copy_from_user */
-		if (copy_from_user(&vp, arg, sizeof(vp))) {
-			retval = -EFAULT;
-			break;
-		}
-
 		/* check validity */
-		DBG("palette: %d\n", vp.palette);
-		DBG("depth: %d\n", vp.depth);
-		if (!valid_mode(vp.palette, vp.depth)) {
+		DBG("palette: %d\n", vp->palette);
+		DBG("depth: %d\n", vp->depth);
+		if (!valid_mode(vp->palette, vp->depth)) {
 			retval = -EINVAL;
 			break;
 		}
 
 		down(&cam->param_lock);
 		/* brightness, colour, contrast need no check 0-65535 */
-		memcpy( &cam->vp, &vp, sizeof(vp) );
+		cam->vp = *vp;
 		/* update cam->params.colourParams */
-		cam->params.colourParams.brightness = vp.brightness*100/65535;
-		cam->params.colourParams.contrast = vp.contrast*100/65535;
-		cam->params.colourParams.saturation = vp.colour*100/65535;
+		cam->params.colourParams.brightness = vp->brightness*100/65535;
+		cam->params.colourParams.contrast = vp->contrast*100/65535;
+		cam->params.colourParams.saturation = vp->colour*100/65535;
 		/* contrast is in steps of 8, so round */
 		cam->params.colourParams.contrast =
 			((cam->params.colourParams.contrast + 3) / 8) * 8;
@@ -2799,34 +2812,33 @@
 		cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
 		up(&cam->param_lock);
 		DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
-		    vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour,
-		    vp.contrast);
+		    vp->depth, vp->palette, vp->brightness, vp->hue, 
+		    vp->colour, vp->contrast);
 		break;
 	}
 
 	/* get/set capture window */
 	case VIDIOCGWIN:
+	{
+		struct video_window *vw = arg;
+
 		DBG("VIDIOCGWIN\n");
 
-		if (copy_to_user(arg, &cam->vw, sizeof(struct video_window)))
-			retval = -EFAULT;
+		*vw = cam->vw;
 		break;
-	
+	}	
+
 	case VIDIOCSWIN:
 	{
 		/* copy_from_user, check validity, copy to internal structure */
-		struct video_window vw;
+		struct video_window *vw = arg;
 		DBG("VIDIOCSWIN\n");
-		if (copy_from_user(&vw, arg, sizeof(vw))) {
-			retval = -EFAULT;
-			break;
-		}
 
-		if (vw.clipcount != 0) {    /* clipping not supported */
+		if (vw->clipcount != 0) {    /* clipping not supported */
 			retval = -EINVAL;
 			break;
 		}
-		if (vw.clips != NULL) {     /* clipping not supported */
+		if (vw->clips != NULL) {     /* clipping not supported */
 			retval = -EINVAL;
 			break;
 		}
@@ -2835,8 +2847,8 @@
 		* is requested by the user???
 		*/
 		down(&cam->param_lock);
-		if (vw.width != cam->vw.width || vw.height != cam->vw.height) {
-			int video_size = match_videosize(vw.width, vw.height);
+		if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
+			int video_size = match_videosize(vw->width, vw->height);
 
 			if (video_size < 0) {
 				retval = -EINVAL;
@@ -2865,41 +2877,34 @@
 	/* mmap interface */
 	case VIDIOCGMBUF:
 	{
-		struct video_mbuf vm;
+		struct video_mbuf *vm = arg;
 		int i;
 
 		DBG("VIDIOCGMBUF\n");
-		memset(&vm, 0, sizeof(vm));
-		vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
-		vm.frames = FRAME_NUM;
+		memset(vm, 0, sizeof(*vm));
+		vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
+		vm->frames = FRAME_NUM;
 		for (i = 0; i < FRAME_NUM; i++)
-			vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i;
-
-		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-			retval = -EFAULT;
+			vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
 
 		break;
 	}
 	
 	case VIDIOCMCAPTURE:
 	{
-		struct video_mmap vm;
+		struct video_mmap *vm = arg;
 		int video_size;
 
-		if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
-			retval = -EFAULT;
-			break;
-		}
-		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
-		    vm.width, vm.height);
-		if (vm.frame<0||vm.frame>=FRAME_NUM) {
+		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
+		    vm->width, vm->height);
+		if (vm->frame<0||vm->frame>=FRAME_NUM) {
 			retval = -EINVAL;
 			break;
 		}
 
 		/* set video format */
-		cam->vp.palette = vm.format;
-		switch(vm.format) {
+		cam->vp.palette = vm->format;
+		switch(vm->format) {
 		case VIDEO_PALETTE_GREY:
 			cam->vp.depth=8;
 			break;
@@ -2924,7 +2929,7 @@
 			break;
 
 		/* set video size */
-		video_size = match_videosize(vm.width, vm.height);
+		video_size = match_videosize(vm->width, vm->height);
 		if (video_size < 0) {
 			retval = -EINVAL;
 			break;
@@ -2937,37 +2942,33 @@
 		}
 		/* according to v4l-spec we must start streaming here */
 		cam->mmap_kludge = 1;
-		retval = capture_frame(cam, &vm);
+		retval = capture_frame(cam, vm);
 
 		break;
 	}
 	
 	case VIDIOCSYNC:
 	{
-		int frame;
+		int *frame = arg;
 
-		if (copy_from_user((void *)&frame, arg, sizeof(int))) {
-			retval = -EFAULT;
-			break;
-		}
-		//DBG("VIDIOCSYNC: %d\n", frame);
+		//DBG("VIDIOCSYNC: %d\n", *frame);
 
-		if (frame<0 || frame >= FRAME_NUM) {
+		if (*frame<0 || *frame >= FRAME_NUM) {
 			retval = -EINVAL;
 			break;
 		}
 
-		switch (cam->frame[frame].state) {
+		switch (cam->frame[*frame].state) {
 		case FRAME_UNUSED:
 		case FRAME_READY:
 		case FRAME_GRABBING:
-			DBG("sync to unused frame %d\n", frame);
+			DBG("sync to unused frame %d\n", *frame);
 			retval = -EINVAL;
 			break;
 
 		case FRAME_DONE:
-			cam->frame[frame].state = FRAME_UNUSED;
-			//DBG("VIDIOCSYNC: %d synced\n", frame);
+			cam->frame[*frame].state = FRAME_UNUSED;
+			//DBG("VIDIOCSYNC: %d synced\n", *frame);
 			break;
 		}
 		if (retval == -EINTR) {
@@ -2979,36 +2980,22 @@
 
 	/* pointless to implement overlay with this camera */
 	case VIDIOCCAPTURE:
-		retval = -EINVAL;
-		break;
 	case VIDIOCGFBUF:
-		retval = -EINVAL;
-		break;
 	case VIDIOCSFBUF:
-		retval = -EINVAL;
-		break;
 	case VIDIOCKEY:
 		retval = -EINVAL;
 		break;
 
 	/* tuner interface - we have none */
 	case VIDIOCGTUNER:
-		retval = -EINVAL;
-		break;
 	case VIDIOCSTUNER:
-		retval = -EINVAL;
-		break;
 	case VIDIOCGFREQ:
-		retval = -EINVAL;
-		break;
 	case VIDIOCSFREQ:
 		retval = -EINVAL;
 		break;
 
 	/* audio interface - we have none */
 	case VIDIOCGAUDIO:
-		retval = -EINVAL;
-		break;
 	case VIDIOCSAUDIO:
 		retval = -EINVAL;
 		break;
@@ -3017,16 +3004,23 @@
 		break;
 	}
 
-	up(&cam->param_lock);
 	up(&cam->busy_lock);
 	return retval;
 } 
 
+static int cpia_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
+}
+
+
 /* FIXME */
-static int cpia_mmap(struct video_device *dev, const char *adr,
-                     unsigned long size)
+static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	unsigned long start = (unsigned long)adr;
+	struct video_device *dev = file->private_data;
+	unsigned long start = vma->vm_start;
+	unsigned long size  = vma->vm_end - vma->vm_start;
 	unsigned long page, pos;
 	struct cam_data *cam = dev->priv;
 	int retval;
@@ -3074,25 +3068,22 @@
 	return 0;
 }
 
-int cpia_video_init(struct video_device *vdev)
-{
-#ifdef CONFIG_PROC_FS
-	create_proc_cpia_cam(vdev->priv);
-#endif
-	return 0;
-}
+static struct file_operations cpia_fops = {
+	owner:		THIS_MODULE,
+	open:		cpia_open,
+	release:	cpia_close,
+	read:		cpia_read,
+	mmap:		cpia_mmap,
+	ioctl:		cpia_ioctl,
+	llseek:         no_llseek,
+};
 
 static struct video_device cpia_template = {
 	owner:		THIS_MODULE,
 	name:		"CPiA Camera",
 	type:		VID_TYPE_CAPTURE,
 	hardware:	VID_HARDWARE_CPIA,
-	open:		cpia_open,
-	close:		cpia_close,
-	read:		cpia_read,
-	ioctl:		cpia_ioctl,
-	mmap:		cpia_mmap,
-	initialize:	cpia_video_init,
+	fops:           &cpia_fops,
 	minor:		-1,
 };
 
@@ -3229,16 +3220,10 @@
 
 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
 {
-        struct cam_data *camera;
-	
-	/* Need a lock when adding/removing cameras.  This doesn't happen
-	 * often and doesn't take very long, so grabbing the kernel lock
-	 * should be OK. */
+	struct cam_data *camera;
 	
-	if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
-		unlock_kernel();
+	if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
 		return NULL;
-	}
 	
 	init_camera_struct( camera, ops );
 	camera->lowlevel_data = lowlevel;
@@ -3246,7 +3231,6 @@
 	/* register v4l device */
 	if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
 		kfree(camera);
-		unlock_kernel();
 		printk(KERN_DEBUG "video_register_device failed\n");
 		return NULL;
 	}
@@ -3266,6 +3250,10 @@
 	/* close cpia */
 	camera->ops->close(camera->lowlevel_data);
 
+#ifdef CONFIG_PROC_FS
+	create_proc_cpia_cam(camera);
+#endif
+
 	printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
 	       camera->params.version.firmwareVersion,
 	       camera->params.version.firmwareRevision,
@@ -3285,12 +3273,10 @@
 
 void cpia_unregister_camera(struct cam_data *cam)
 {
-	if (!cam->open_count) {
-		DBG("unregistering video\n");
-		video_unregister_device(&cam->vdev);
-	} else {
-		LOG("/dev/video%d removed while open, "
-		    "deferring video_unregister_device\n", cam->vdev.minor);
+	DBG("unregistering video\n");
+	video_unregister_device(&cam->vdev);
+	if (cam->open_count) {
+		put_cam(cam->ops);
 		DBG("camera open -- setting ops to NULL\n");
 		cam->ops = NULL;
 	}
@@ -3313,9 +3299,6 @@
 	proc_cpia_create();
 #endif
 
-#ifdef CONFIG_VIDEO_CPIA_PP
-	cpia_pp_init();
-#endif
 #ifdef CONFIG_KMOD
 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
 	request_module("cpia_pp");
@@ -3325,6 +3308,10 @@
 	request_module("cpia_usb");
 #endif
 #endif	/* CONFIG_KMOD */
+
+#ifdef CONFIG_VIDEO_CPIA_PP
+	cpia_pp_init();
+#endif
 #ifdef CONFIG_VIDEO_CPIA_USB
 	cpia_usb_init();
 #endif

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