linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/8] V4L/DVB: radio-si470x: remove the BKL lock used internally at the driver
       [not found] <cover.1284597566.git.mchehab@redhat.com>
@ 2010-09-16  0:56 ` Mauro Carvalho Chehab
  2010-09-16  0:56 ` [PATCH 3/8] V4L/DVB: bttv-driver: document functions using mutex_lock Mauro Carvalho Chehab
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2010-09-16  0:56 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Arnd Bergmann, Tobias Lorenz, Joonyoung Shim

diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index 5ec13e5..392e84f 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -517,7 +517,7 @@ int si470x_fops_open(struct file *file)
 	struct si470x_device *radio = video_drvdata(file);
 	int retval;
 
-	lock_kernel();
+	mutex_lock(&radio->lock);
 	radio->users++;
 
 	retval = usb_autopm_get_interface(radio->intf);
@@ -558,7 +558,7 @@ int si470x_fops_open(struct file *file)
 	}
 
 done:
-	unlock_kernel();
+	mutex_unlock(&radio->lock);
 	return retval;
 }
 
@@ -577,7 +577,7 @@ int si470x_fops_release(struct file *file)
 		goto done;
 	}
 
-	mutex_lock(&radio->disconnect_lock);
+	mutex_lock(&radio->lock);
 	radio->users--;
 	if (radio->users == 0) {
 		/* shutdown interrupt handler */
@@ -591,7 +591,7 @@ int si470x_fops_release(struct file *file)
 			video_unregister_device(radio->videodev);
 			kfree(radio->int_in_buffer);
 			kfree(radio->buffer);
-			mutex_unlock(&radio->disconnect_lock);
+			mutex_unlock(&radio->lock);
 			kfree(radio);
 			goto done;
 		}
@@ -603,7 +603,7 @@ int si470x_fops_release(struct file *file)
 		retval = si470x_stop(radio);
 		usb_autopm_put_interface(radio->intf);
 	}
-	mutex_unlock(&radio->disconnect_lock);
+	mutex_unlock(&radio->lock);
 done:
 	return retval;
 }
@@ -661,7 +661,6 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
 	radio->disconnected = 0;
 	radio->usbdev = interface_to_usbdev(intf);
 	radio->intf = intf;
-	mutex_init(&radio->disconnect_lock);
 	mutex_init(&radio->lock);
 
 	iface_desc = intf->cur_altsetting;
@@ -830,7 +829,7 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
 {
 	struct si470x_device *radio = usb_get_intfdata(intf);
 
-	mutex_lock(&radio->disconnect_lock);
+	mutex_lock(&radio->lock);
 	radio->disconnected = 1;
 	usb_set_intfdata(intf, NULL);
 	if (radio->users == 0) {
@@ -843,10 +842,10 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
 		kfree(radio->int_in_buffer);
 		video_unregister_device(radio->videodev);
 		kfree(radio->buffer);
-		mutex_unlock(&radio->disconnect_lock);
+		mutex_unlock(&radio->lock);
 		kfree(radio);
 	} else {
-		mutex_unlock(&radio->disconnect_lock);
+		mutex_unlock(&radio->lock);
 	}
 }
 
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h
index 3cd0a29..d3d86ba 100644
--- a/drivers/media/radio/si470x/radio-si470x.h
+++ b/drivers/media/radio/si470x/radio-si470x.h
@@ -177,7 +177,6 @@ struct si470x_device {
 
 	/* driver management */
 	unsigned char disconnected;
-	struct mutex disconnect_lock;
 #endif
 
 #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/8] V4L/DVB: bttv-driver: document functions using mutex_lock
       [not found] <cover.1284597566.git.mchehab@redhat.com>
  2010-09-16  0:56 ` [PATCH 1/8] V4L/DVB: radio-si470x: remove the BKL lock used internally at the driver Mauro Carvalho Chehab
@ 2010-09-16  0:56 ` Mauro Carvalho Chehab
  2010-09-16  0:56 ` [PATCH 4/8] V4L/DVB: bttv: fix driver lock and remove explicit calls to BKL Mauro Carvalho Chehab
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2010-09-16  0:56 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Arnd Bergmann

There are a few ancillary static routines used by ioctl functions
that takes bttv lock internally. As we'll be adding the same lock
for all ioctl's that need, we need to properly document them, to
avoid doing double locks

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 38c7f78..fcafe2f 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -842,7 +842,7 @@ static const struct v4l2_queryctrl *ctrl_by_id(int id)
 			 RESOURCE_OVERLAY)
 
 static
-int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
+int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
 {
 	int xbits; /* mutual exclusive resources */
 
@@ -935,7 +935,7 @@ disclaim_video_lines(struct bttv *btv)
 }
 
 static
-void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
+void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)
 {
 	if ((fh->resources & bits) != bits) {
 		/* trying to free ressources not allocated by us ... */
@@ -1682,7 +1682,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
 		kfree(old);
 	}
 	if (NULL == new)
-		free_btres(btv,fh,RESOURCE_OVERLAY);
+		free_btres_lock(btv,fh,RESOURCE_OVERLAY);
 	dprintk("switch_overlay: done\n");
 	return retval;
 }
@@ -2124,7 +2124,7 @@ bttv_crop_adjust	(struct bttv_crop *             c,
    also adjust the current cropping parameters to get closer to the
    desired image size. */
 static int
-limit_scaled_size       (struct bttv_fh *               fh,
+limit_scaled_size_lock       (struct bttv_fh *               fh,
 			 __s32 *                        width,
 			 __s32 *                        height,
 			 enum v4l2_field                field,
@@ -2238,7 +2238,7 @@ limit_scaled_size       (struct bttv_fh *               fh,
    may also adjust the current cropping parameters to get closer
    to the desired window size. */
 static int
-verify_window		(struct bttv_fh *               fh,
+verify_window_lock		(struct bttv_fh *               fh,
 			 struct v4l2_window *           win,
 			 int                            adjust_size,
 			 int                            adjust_crop)
@@ -2292,7 +2292,7 @@ verify_window		(struct bttv_fh *               fh,
 	win->w.width -= win->w.left & ~width_mask;
 	win->w.left = (win->w.left - width_mask - 1) & width_mask;
 
-	rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
+	rc = limit_scaled_size_lock(fh, &win->w.width, &win->w.height,
 			       field, width_mask,
 			       /* width_bias: round down */ 0,
 			       adjust_size, adjust_crop);
@@ -2303,7 +2303,7 @@ verify_window		(struct bttv_fh *               fh,
 	return 0;
 }
 
-static int setup_window(struct bttv_fh *fh, struct bttv *btv,
+static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
 			struct v4l2_window *win, int fixup)
 {
 	struct v4l2_clip *clips = NULL;
@@ -2313,7 +2313,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
 		return -EINVAL;
 	if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
 		return -EINVAL;
-	retval = verify_window(fh, win,
+	retval = verify_window_lock(fh, win,
 			       /* adjust_size */ fixup,
 			       /* adjust_crop */ fixup);
 	if (0 != retval)
@@ -2516,7 +2516,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
 	width = f->fmt.pix.width;
 	height = f->fmt.pix.height;
 
-	rc = limit_scaled_size(fh, &width, &height, field,
+	rc = limit_scaled_size_lock(fh, &width, &height, field,
 			       /* width_mask: 4 pixels */ ~3,
 			       /* width_bias: nearest */ 2,
 			       /* adjust_size */ 1,
@@ -2536,7 +2536,7 @@ static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,
 {
 	struct bttv_fh *fh = priv;
 
-	return verify_window(fh, &f->fmt.win,
+	return verify_window_lock(fh, &f->fmt.win,
 			/* adjust_size */ 1,
 			/* adjust_crop */ 0);
 }
@@ -2563,7 +2563,7 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
 	height = f->fmt.pix.height;
 	field = f->fmt.pix.field;
 
-	retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field,
+	retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field,
 			       /* width_mask: 4 pixels */ ~3,
 			       /* width_bias: nearest */ 2,
 			       /* adjust_size */ 1,
@@ -2601,7 +2601,7 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
 		return -EINVAL;
 	}
 
-	return setup_window(fh, btv, &f->fmt.win, 1);
+	return setup_window_lock(fh, btv, &f->fmt.win, 1);
 }
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -2742,7 +2742,7 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
 		}
 	}
 
-	if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY))
+	if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY))
 		return -EBUSY;
 
 	mutex_lock(&fh->cap.vb_lock);
@@ -2785,7 +2785,7 @@ static int bttv_s_fbuf(struct file *file, void *f,
 		__s32 width = fb->fmt.width;
 		__s32 height = fb->fmt.height;
 
-		retval = limit_scaled_size(fh, &width, &height,
+		retval = limit_scaled_size_lock(fh, &width, &height,
 					   V4L2_FIELD_INTERLACED,
 					   /* width_mask */ ~3,
 					   /* width_bias */ 2,
@@ -2852,7 +2852,7 @@ static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
 	struct bttv *btv = fh->btv;
 	int res = bttv_resource(fh);
 
-	if (!check_alloc_btres(btv, fh, res))
+	if (!check_alloc_btres_lock(btv, fh, res))
 		return -EBUSY;
 
 	return videobuf_qbuf(bttv_queue(fh), b);
@@ -2872,7 +2872,7 @@ static int bttv_streamon(struct file *file, void *priv,
 	struct bttv *btv = fh->btv;
 	int res = bttv_resource(fh);
 
-	if (!check_alloc_btres(btv, fh, res))
+	if (!check_alloc_btres_lock(btv, fh, res))
 		return -EBUSY;
 	return videobuf_streamon(bttv_queue(fh));
 }
@@ -2890,7 +2890,7 @@ static int bttv_streamoff(struct file *file, void *priv,
 	retval = videobuf_streamoff(bttv_queue(fh));
 	if (retval < 0)
 		return retval;
-	free_btres(btv, fh, res);
+	free_btres_lock(btv, fh, res);
 	return 0;
 }
 
@@ -3030,7 +3030,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
 
 	/* Make sure tvnorm, vbi_end and the current cropping
 	   parameters remain consistent until we're done. Note
-	   read() may change vbi_end in check_alloc_btres(). */
+	   read() may change vbi_end in check_alloc_btres_lock(). */
 	mutex_lock(&btv->lock);
 
 	retval = -EBUSY;
@@ -3128,17 +3128,17 @@ static ssize_t bttv_read(struct file *file, char __user *data,
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
+		if (!check_alloc_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ)) {
 			/* VIDEO_READ in use by another fh,
 			   or VIDEO_STREAM by any fh. */
 			return -EBUSY;
 		}
 		retval = videobuf_read_one(&fh->cap, data, count, ppos,
 					   file->f_flags & O_NONBLOCK);
-		free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
+		free_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ);
 		break;
 	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
+		if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
 			return -EBUSY;
 		retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
 					      file->f_flags & O_NONBLOCK);
@@ -3157,7 +3157,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
 	unsigned int rc = POLLERR;
 
 	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
-		if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
+		if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
 			return POLLERR;
 		return videobuf_poll_stream(file, &fh->vbi, wait);
 	}
@@ -3288,20 +3288,20 @@ static int bttv_release(struct file *file)
 	/* stop video capture */
 	if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
 		videobuf_streamoff(&fh->cap);
-		free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
+		free_btres_lock(btv,fh,RESOURCE_VIDEO_STREAM);
 	}
 	if (fh->cap.read_buf) {
 		buffer_release(&fh->cap,fh->cap.read_buf);
 		kfree(fh->cap.read_buf);
 	}
 	if (check_btres(fh, RESOURCE_VIDEO_READ)) {
-		free_btres(btv, fh, RESOURCE_VIDEO_READ);
+		free_btres_lock(btv, fh, RESOURCE_VIDEO_READ);
 	}
 
 	/* stop vbi capture */
 	if (check_btres(fh, RESOURCE_VBI)) {
 		videobuf_stop(&fh->vbi);
-		free_btres(btv,fh,RESOURCE_VBI);
+		free_btres_lock(btv,fh,RESOURCE_VBI);
 	}
 
 	/* free stuff */
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/8] V4L/DVB: bttv: fix driver lock and remove explicit calls to BKL
       [not found] <cover.1284597566.git.mchehab@redhat.com>
  2010-09-16  0:56 ` [PATCH 1/8] V4L/DVB: radio-si470x: remove the BKL lock used internally at the driver Mauro Carvalho Chehab
  2010-09-16  0:56 ` [PATCH 3/8] V4L/DVB: bttv-driver: document functions using mutex_lock Mauro Carvalho Chehab
@ 2010-09-16  0:56 ` Mauro Carvalho Chehab
  2010-09-16  0:56 ` [PATCH 5/8] V4L/DVB: bttv: use unlocked ioctl Mauro Carvalho Chehab
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2010-09-16  0:56 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Arnd Bergmann

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index fcafe2f..5f5cd4a 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -1859,21 +1859,25 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
 	unsigned int i;
 	int err;
 
+	mutex_lock(&btv->lock);
 	err = v4l2_prio_check(&btv->prio, fh->prio);
-	if (0 != err)
-		return err;
+	if (err)
+		goto err;
 
 	for (i = 0; i < BTTV_TVNORMS; i++)
 		if (*id & bttv_tvnorms[i].v4l2_id)
 			break;
-	if (i == BTTV_TVNORMS)
-		return -EINVAL;
+	if (i == BTTV_TVNORMS) {
+		err = -EINVAL;
+		goto err;
+	}
 
-	mutex_lock(&btv->lock);
 	set_tvnorm(btv, i);
+
+err:
 	mutex_unlock(&btv->lock);
 
-	return 0;
+	return err;
 }
 
 static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
@@ -1893,10 +1897,13 @@ static int bttv_enum_input(struct file *file, void *priv,
 {
 	struct bttv_fh *fh = priv;
 	struct bttv *btv = fh->btv;
-	int n;
+	int rc = 0;
 
-	if (i->index >= bttv_tvcards[btv->c.type].video_inputs)
-		return -EINVAL;
+	mutex_lock(&btv->lock);
+	if (i->index >= bttv_tvcards[btv->c.type].video_inputs) {
+		rc = -EINVAL;
+		goto err;
+	}
 
 	i->type     = V4L2_INPUT_TYPE_CAMERA;
 	i->audioset = 1;
@@ -1919,10 +1926,12 @@ static int bttv_enum_input(struct file *file, void *priv,
 			i->status |= V4L2_IN_ST_NO_H_LOCK;
 	}
 
-	for (n = 0; n < BTTV_TVNORMS; n++)
-		i->std |= bttv_tvnorms[n].v4l2_id;
+	i->std = BTTV_NORMS;
 
-	return 0;
+err:
+	mutex_unlock(&btv->lock);
+
+	return rc;
 }
 
 static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
@@ -1930,7 +1939,10 @@ static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
 	struct bttv_fh *fh = priv;
 	struct bttv *btv = fh->btv;
 
+	mutex_lock(&btv->lock);
 	*i = btv->input;
+	mutex_unlock(&btv->lock);
+
 	return 0;
 }
 
@@ -1941,15 +1953,19 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i)
 
 	int err;
 
-	err = v4l2_prio_check(&btv->prio, fh->prio);
-	if (0 != err)
-		return err;
-
-	if (i > bttv_tvcards[btv->c.type].video_inputs)
-		return -EINVAL;
-
 	mutex_lock(&btv->lock);
+	err = v4l2_prio_check(&btv->prio, fh->prio);
+	if (unlikely(err))
+		goto err;
+
+	if (i > bttv_tvcards[btv->c.type].video_inputs) {
+		err = -EINVAL;
+		goto err;
+	}
+
 	set_input(btv, i, btv->tvnorm);
+
+err:
 	mutex_unlock(&btv->lock);
 	return 0;
 }
@@ -1961,22 +1977,25 @@ static int bttv_s_tuner(struct file *file, void *priv,
 	struct bttv *btv = fh->btv;
 	int err;
 
-	err = v4l2_prio_check(&btv->prio, fh->prio);
-	if (0 != err)
-		return err;
-
-	if (btv->tuner_type == TUNER_ABSENT)
-		return -EINVAL;
-
-	if (0 != t->index)
+	if (unlikely(0 != t->index))
 		return -EINVAL;
 
 	mutex_lock(&btv->lock);
+	if (unlikely(btv->tuner_type == TUNER_ABSENT)) {
+		err = -EINVAL;
+		goto err;
+	}
+
+	err = v4l2_prio_check(&btv->prio, fh->prio);
+	if (unlikely(err))
+		goto err;
+
 	bttv_call_all(btv, tuner, s_tuner, t);
 
 	if (btv->audio_mode_gpio)
 		btv->audio_mode_gpio(btv, t, 1);
 
+err:
 	mutex_unlock(&btv->lock);
 
 	return 0;
@@ -1988,8 +2007,10 @@ static int bttv_g_frequency(struct file *file, void *priv,
 	struct bttv_fh *fh  = priv;
 	struct bttv *btv = fh->btv;
 
+	mutex_lock(&btv->lock);
 	f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
 	f->frequency = btv->freq;
+	mutex_unlock(&btv->lock);
 
 	return 0;
 }
@@ -2001,21 +2022,26 @@ static int bttv_s_frequency(struct file *file, void *priv,
 	struct bttv *btv = fh->btv;
 	int err;
 
-	err = v4l2_prio_check(&btv->prio, fh->prio);
-	if (0 != err)
-		return err;
-
 	if (unlikely(f->tuner != 0))
 		return -EINVAL;
+
+	mutex_lock(&btv->lock);
+	err = v4l2_prio_check(&btv->prio, fh->prio);
+	if (unlikely(err))
+		goto err;
+
 	if (unlikely(f->type != (btv->radio_user
-		? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV)))
-		return -EINVAL;
-	mutex_lock(&btv->lock);
+		? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) {
+		err = -EINVAL;
+		goto err;
+	}
 	btv->freq = f->frequency;
 	bttv_call_all(btv, tuner, s_frequency, f);
 	if (btv->has_matchbox && btv->radio_user)
 		tea5757_set_freq(btv, btv->freq);
+err:
 	mutex_unlock(&btv->lock);
+
 	return 0;
 }
 
@@ -2257,7 +2283,9 @@ verify_window_lock		(struct bttv_fh *               fh,
 	if (V4L2_FIELD_ANY == field) {
 		__s32 height2;
 
+		mutex_lock(&fh->btv->lock);
 		height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
+		mutex_unlock(&fh->btv->lock);
 		field = (win->w.height > height2)
 			? V4L2_FIELD_INTERLACED
 			: V4L2_FIELD_TOP;
@@ -2332,6 +2360,8 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
 			return -EFAULT;
 		}
 	}
+
+	mutex_lock(&fh->cap.vb_lock);
 	/* clip against screen */
 	if (NULL != btv->fbuf.base)
 		n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
@@ -2354,7 +2384,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
 		BUG();
 	}
 
-	mutex_lock(&fh->cap.vb_lock);
 	kfree(fh->ov.clips);
 	fh->ov.clips    = clips;
 	fh->ov.nclips   = n;
@@ -2362,6 +2391,14 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
 	fh->ov.w        = win->w;
 	fh->ov.field    = win->field;
 	fh->ov.setup_ok = 1;
+
+	/*
+	 * FIXME: btv is protected by btv->lock mutex, while btv->init
+	 *	  is protected by fh->cap.vb_lock. This seems to open the
+	 *	  possibility for some race situations. Maybe the better would
+	 *	  be to unify those locks or to use another way to store the
+	 *	  init values that will be consumed by videobuf callbacks
+	 */
 	btv->init.ov.w.width   = win->w.width;
 	btv->init.ov.w.height  = win->w.height;
 	btv->init.ov.field     = win->field;
@@ -2490,7 +2527,9 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
 	if (V4L2_FIELD_ANY == field) {
 		__s32 height2;
 
+		mutex_lock(&btv->lock);
 		height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+		mutex_unlock(&btv->lock);
 		field = (f->fmt.pix.height > height2)
 			? V4L2_FIELD_INTERLACED
 			: V4L2_FIELD_BOTTOM;
@@ -2651,11 +2690,15 @@ static int bttv_querycap(struct file *file, void  *priv,
 		V4L2_CAP_VBI_CAPTURE |
 		V4L2_CAP_READWRITE |
 		V4L2_CAP_STREAMING;
-	if (btv->has_saa6588)
-		cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
 	if (no_overlay <= 0)
 		cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
 
+	/*
+	 * No need to lock here: those vars are initialized during board
+	 * probe and remains untouched during the rest of the driver lifecycle
+	 */
+	if (btv->has_saa6588)
+		cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
 	if (btv->tuner_type != TUNER_ABSENT)
 		cap->capabilities |= V4L2_CAP_TUNER;
 	return 0;
@@ -2730,16 +2773,22 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
 	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
 	struct bttv_buffer *new;
-	int retval;
+	int retval = 0;
 
 	if (on) {
+		mutex_lock(&fh->cap.vb_lock);
 		/* verify args */
-		if (NULL == btv->fbuf.base)
+		if (unlikely(!btv->fbuf.base)) {
+			mutex_unlock(&fh->cap.vb_lock);
 			return -EINVAL;
-		if (!fh->ov.setup_ok) {
+		}
+		if (unlikely(!fh->ov.setup_ok)) {
 			dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
-			return -EINVAL;
+			retval = -EINVAL;
 		}
+		if (retval)
+			return retval;
+		mutex_unlock(&fh->cap.vb_lock);
 	}
 
 	if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY))
@@ -2907,6 +2956,7 @@ static int bttv_queryctrl(struct file *file, void *priv,
 	     c->id >= V4L2_CID_PRIVATE_LASTP1))
 		return -EINVAL;
 
+	mutex_lock(&btv->lock);
 	if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
 		*c = no_ctl;
 	else {
@@ -2914,6 +2964,7 @@ static int bttv_queryctrl(struct file *file, void *priv,
 
 		*c = (NULL != ctrl) ? *ctrl : no_ctl;
 	}
+	mutex_unlock(&btv->lock);
 
 	return 0;
 }
@@ -2924,8 +2975,11 @@ static int bttv_g_parm(struct file *file, void *f,
 	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
 
+	mutex_lock(&btv->lock);
 	v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
 				    &parm->parm.capture.timeperframe);
+	mutex_unlock(&btv->lock);
+
 	return 0;
 }
 
@@ -2961,7 +3015,9 @@ static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
 	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
 
+	mutex_lock(&btv->lock);
 	*p = v4l2_prio_max(&btv->prio);
+	mutex_unlock(&btv->lock);
 
 	return 0;
 }
@@ -2971,8 +3027,13 @@ static int bttv_s_priority(struct file *file, void *f,
 {
 	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
+	int	rc;
 
-	return v4l2_prio_change(&btv->prio, &fh->prio, prio);
+	mutex_lock(&btv->lock);
+	rc = v4l2_prio_change(&btv->prio, &fh->prio, prio);
+	mutex_unlock(&btv->lock);
+
+	return rc;
 }
 
 static int bttv_cropcap(struct file *file, void *priv,
@@ -2985,7 +3046,9 @@ static int bttv_cropcap(struct file *file, void *priv,
 	    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
 		return -EINVAL;
 
+	mutex_lock(&btv->lock);
 	*cap = bttv_tvnorms[btv->tvnorm].cropcap;
+	mutex_unlock(&btv->lock);
 
 	return 0;
 }
@@ -3003,7 +3066,9 @@ static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
 	   inconsistent with fh->width or fh->height and apps
 	   do not expect a change here. */
 
+	mutex_lock(&btv->lock);
 	crop->c = btv->crop[!!fh->do_crop].rect;
+	mutex_unlock(&btv->lock);
 
 	return 0;
 }
@@ -3024,14 +3089,15 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
 	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
 		return -EINVAL;
 
-	retval = v4l2_prio_check(&btv->prio, fh->prio);
-	if (0 != retval)
-		return retval;
-
 	/* Make sure tvnorm, vbi_end and the current cropping
 	   parameters remain consistent until we're done. Note
 	   read() may change vbi_end in check_alloc_btres_lock(). */
 	mutex_lock(&btv->lock);
+	retval = v4l2_prio_check(&btv->prio, fh->prio);
+	if (0 != retval) {
+		mutex_unlock(&btv->lock);
+		return retval;
+	}
 
 	retval = -EBUSY;
 
@@ -3221,21 +3287,32 @@ static int bttv_open(struct file *file)
 		return -ENODEV;
 	}
 
-	lock_kernel();
-
 	dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
 		btv->c.nr,v4l2_type_names[type]);
 
 	/* allocate per filehandle data */
-	fh = kmalloc(sizeof(*fh),GFP_KERNEL);
-	if (NULL == fh) {
-		unlock_kernel();
+	fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+	if (unlikely(!fh))
 		return -ENOMEM;
-	}
 	file->private_data = fh;
+
+	/*
+	 * btv is protected by btv->lock mutex, while btv->init and other
+	 * streaming vars are protected by fh->cap.vb_lock. We need to take
+	 * care of both locks to avoid troubles. However, vb_lock is used also
+	 * inside videobuf, without calling buf->lock. So, it is a very bad
+	 * idea to hold both locks at the same time.
+	 * Let's first copy btv->init at fh, holding cap.vb_lock, and then work
+	 * with the rest of init, holding btv->lock.
+	 */
+	mutex_lock(&fh->cap.vb_lock);
 	*fh = btv->init;
+	mutex_unlock(&fh->cap.vb_lock);
+
 	fh->type = type;
 	fh->ov.setup_ok = 0;
+
+	mutex_lock(&btv->lock);
 	v4l2_prio_open(&btv->prio, &fh->prio);
 
 	videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
@@ -3272,7 +3349,7 @@ static int bttv_open(struct file *file)
 	bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
 
 	bttv_field_count(btv);
-	unlock_kernel();
+	mutex_unlock(&btv->lock);
 	return 0;
 }
 
@@ -3281,6 +3358,7 @@ static int bttv_release(struct file *file)
 	struct bttv_fh *fh = file->private_data;
 	struct bttv *btv = fh->btv;
 
+	mutex_lock(&btv->lock);
 	/* turn off overlay */
 	if (check_btres(fh, RESOURCE_OVERLAY))
 		bttv_switch_overlay(btv,fh,NULL);
@@ -3305,8 +3383,15 @@ static int bttv_release(struct file *file)
 	}
 
 	/* free stuff */
+
+	/*
+	 * videobuf uses cap.vb_lock - we should avoid holding btv->lock,
+	 * otherwise we may have dead lock conditions
+	 */
+	mutex_unlock(&btv->lock);
 	videobuf_mmap_free(&fh->cap);
 	videobuf_mmap_free(&fh->vbi);
+	mutex_lock(&btv->lock);
 	v4l2_prio_close(&btv->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
@@ -3316,6 +3401,7 @@ static int bttv_release(struct file *file)
 
 	if (!btv->users)
 		audio_mute(btv, 1);
+	mutex_unlock(&btv->lock);
 
 	return 0;
 }
@@ -3412,21 +3498,19 @@ static int radio_open(struct file *file)
 
 	dprintk("bttv: open dev=%s\n", video_device_node_name(vdev));
 
-	lock_kernel();
-
 	dprintk("bttv%d: open called (radio)\n",btv->c.nr);
 
 	/* allocate per filehandle data */
 	fh = kmalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh) {
-		unlock_kernel();
+	if (unlikely(!fh))
 		return -ENOMEM;
-	}
 	file->private_data = fh;
+	mutex_lock(&fh->cap.vb_lock);
 	*fh = btv->init;
-	v4l2_prio_open(&btv->prio, &fh->prio);
+	mutex_unlock(&fh->cap.vb_lock);
 
 	mutex_lock(&btv->lock);
+	v4l2_prio_open(&btv->prio, &fh->prio);
 
 	btv->radio_user++;
 
@@ -3434,7 +3518,6 @@ static int radio_open(struct file *file)
 	audio_input(btv,TVAUDIO_INPUT_RADIO);
 
 	mutex_unlock(&btv->lock);
-	unlock_kernel();
 	return 0;
 }
 
@@ -3444,6 +3527,7 @@ static int radio_release(struct file *file)
 	struct bttv *btv = fh->btv;
 	struct rds_command cmd;
 
+	mutex_lock(&btv->lock);
 	v4l2_prio_close(&btv->prio, fh->prio);
 	file->private_data = NULL;
 	kfree(fh);
@@ -3451,6 +3535,7 @@ static int radio_release(struct file *file)
 	btv->radio_user--;
 
 	bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd);
+	mutex_unlock(&btv->lock);
 
 	return 0;
 }
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 5/8] V4L/DVB: bttv: use unlocked ioctl
       [not found] <cover.1284597566.git.mchehab@redhat.com>
                   ` (2 preceding siblings ...)
  2010-09-16  0:56 ` [PATCH 4/8] V4L/DVB: bttv: fix driver lock and remove explicit calls to BKL Mauro Carvalho Chehab
@ 2010-09-16  0:56 ` Mauro Carvalho Chehab
  2010-09-16  0:56 ` [PATCH 2/8] V4L/DVB: radio-si470x: " Mauro Carvalho Chehab
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2010-09-16  0:56 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Arnd Bergmann

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 5f5cd4a..8d1b222 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -3419,13 +3419,13 @@ bttv_mmap(struct file *file, struct vm_area_struct *vma)
 
 static const struct v4l2_file_operations bttv_fops =
 {
-	.owner	  = THIS_MODULE,
-	.open	  = bttv_open,
-	.release  = bttv_release,
-	.ioctl	  = video_ioctl2,
-	.read	  = bttv_read,
-	.mmap	  = bttv_mmap,
-	.poll     = bttv_poll,
+	.owner		  = THIS_MODULE,
+	.open		  = bttv_open,
+	.release	  = bttv_release,
+	.unlocked_ioctl	  = video_ioctl2,
+	.read		  = bttv_read,
+	.mmap		  = bttv_mmap,
+	.poll		  = bttv_poll,
 };
 
 static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/8] V4L/DVB: radio-si470x: use unlocked ioctl
       [not found] <cover.1284597566.git.mchehab@redhat.com>
                   ` (3 preceding siblings ...)
  2010-09-16  0:56 ` [PATCH 5/8] V4L/DVB: bttv: use unlocked ioctl Mauro Carvalho Chehab
@ 2010-09-16  0:56 ` Mauro Carvalho Chehab
  2010-09-16  0:56 ` [PATCH 6/8] V4L/DVB: cx88: Remove BKL Mauro Carvalho Chehab
  2010-09-16  0:56 ` [PATCH 8/8] V4L/DVB: Deprecate stradis driver Mauro Carvalho Chehab
  6 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2010-09-16  0:56 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Arnd Bergmann, Tobias Lorenz, Joonyoung Shim

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 9927a59..61be988 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -408,17 +408,15 @@ done:
 /*
  * si470x_rds_on - switch on rds reception
  */
-int si470x_rds_on(struct si470x_device *radio)
+static int si470x_rds_on(struct si470x_device *radio)
 {
 	int retval;
 
 	/* sysconfig 1 */
-	mutex_lock(&radio->lock);
 	radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
 	retval = si470x_set_register(radio, SYSCONFIG1);
 	if (retval < 0)
 		radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
-	mutex_unlock(&radio->lock);
 
 	return retval;
 }
@@ -440,6 +438,7 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
 	unsigned int block_count = 0;
 
 	/* switch on rds reception */
+	mutex_lock(&radio->lock);
 	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
 		si470x_rds_on(radio);
 
@@ -480,9 +479,9 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
 		buf += 3;
 		retval += 3;
 	}
-	mutex_unlock(&radio->lock);
 
 done:
+	mutex_unlock(&radio->lock);
 	return retval;
 }
 
@@ -497,8 +496,11 @@ static unsigned int si470x_fops_poll(struct file *file,
 	int retval = 0;
 
 	/* switch on rds reception */
+
+	mutex_lock(&radio->lock);
 	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
 		si470x_rds_on(radio);
+	mutex_unlock(&radio->lock);
 
 	poll_wait(file, &radio->read_queue, pts);
 
@@ -516,7 +518,7 @@ static const struct v4l2_file_operations si470x_fops = {
 	.owner			= THIS_MODULE,
 	.read			= si470x_fops_read,
 	.poll			= si470x_fops_poll,
-	.ioctl			= video_ioctl2,
+	.unlocked_ioctl		= video_ioctl2,
 	.open			= si470x_fops_open,
 	.release		= si470x_fops_release,
 };
@@ -572,6 +574,7 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
 	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
+	mutex_lock(&radio->lock);
 	/* safety checks */
 	retval = si470x_disconnect_check(radio);
 	if (retval)
@@ -594,6 +597,8 @@ done:
 	if (retval < 0)
 		dev_warn(&radio->videodev->dev,
 			"get control failed with %d\n", retval);
+
+	mutex_unlock(&radio->lock);
 	return retval;
 }
 
@@ -607,6 +612,7 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
 	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
+	mutex_lock(&radio->lock);
 	/* safety checks */
 	retval = si470x_disconnect_check(radio);
 	if (retval)
@@ -633,6 +639,7 @@ done:
 	if (retval < 0)
 		dev_warn(&radio->videodev->dev,
 			"set control failed with %d\n", retval);
+	mutex_unlock(&radio->lock);
 	return retval;
 }
 
@@ -662,6 +669,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
 	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
+	mutex_lock(&radio->lock);
 	/* safety checks */
 	retval = si470x_disconnect_check(radio);
 	if (retval)
@@ -737,6 +745,7 @@ done:
 	if (retval < 0)
 		dev_warn(&radio->videodev->dev,
 			"get tuner failed with %d\n", retval);
+	mutex_unlock(&radio->lock);
 	return retval;
 }
 
@@ -750,6 +759,7 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
 	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
+	mutex_lock(&radio->lock);
 	/* safety checks */
 	retval = si470x_disconnect_check(radio);
 	if (retval)
@@ -776,6 +786,7 @@ done:
 	if (retval < 0)
 		dev_warn(&radio->videodev->dev,
 			"set tuner failed with %d\n", retval);
+	mutex_unlock(&radio->lock);
 	return retval;
 }
 
@@ -790,6 +801,7 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
 	int retval = 0;
 
 	/* safety checks */
+	mutex_lock(&radio->lock);
 	retval = si470x_disconnect_check(radio);
 	if (retval)
 		goto done;
@@ -806,6 +818,7 @@ done:
 	if (retval < 0)
 		dev_warn(&radio->videodev->dev,
 			"get frequency failed with %d\n", retval);
+	mutex_unlock(&radio->lock);
 	return retval;
 }
 
@@ -819,6 +832,7 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
 	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
+	mutex_lock(&radio->lock);
 	/* safety checks */
 	retval = si470x_disconnect_check(radio);
 	if (retval)
@@ -835,6 +849,7 @@ done:
 	if (retval < 0)
 		dev_warn(&radio->videodev->dev,
 			"set frequency failed with %d\n", retval);
+	mutex_unlock(&radio->lock);
 	return retval;
 }
 
@@ -848,6 +863,7 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
 	struct si470x_device *radio = video_drvdata(file);
 	int retval = 0;
 
+	mutex_lock(&radio->lock);
 	/* safety checks */
 	retval = si470x_disconnect_check(radio);
 	if (retval)
@@ -864,6 +880,7 @@ done:
 	if (retval < 0)
 		dev_warn(&radio->videodev->dev,
 			"set hardware frequency seek failed with %d\n", retval);
+	mutex_unlock(&radio->lock);
 	return retval;
 }
 
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h
index d3d86ba..ea12782 100644
--- a/drivers/media/radio/si470x/radio-si470x.h
+++ b/drivers/media/radio/si470x/radio-si470x.h
@@ -220,7 +220,6 @@ int si470x_disconnect_check(struct si470x_device *radio);
 int si470x_set_freq(struct si470x_device *radio, unsigned int freq);
 int si470x_start(struct si470x_device *radio);
 int si470x_stop(struct si470x_device *radio);
-int si470x_rds_on(struct si470x_device *radio);
 int si470x_fops_open(struct file *file);
 int si470x_fops_release(struct file *file);
 int si470x_vidioc_querycap(struct file *file, void *priv,
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 6/8] V4L/DVB: cx88: Remove BKL
       [not found] <cover.1284597566.git.mchehab@redhat.com>
                   ` (4 preceding siblings ...)
  2010-09-16  0:56 ` [PATCH 2/8] V4L/DVB: radio-si470x: " Mauro Carvalho Chehab
@ 2010-09-16  0:56 ` Mauro Carvalho Chehab
  2010-09-16  0:56 ` [PATCH 8/8] V4L/DVB: Deprecate stradis driver Mauro Carvalho Chehab
  6 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2010-09-16  0:56 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Arnd Bergmann

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index e46e1ce..ec32995 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -1057,7 +1057,7 @@ static int mpeg_open(struct file *file)
 
 	dprintk( 1, "%s\n", __func__);
 
-	lock_kernel();
+	mutex_lock(&dev->core->lock);
 
 	/* Make sure we can acquire the hardware */
 	drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
@@ -1065,7 +1065,7 @@ static int mpeg_open(struct file *file)
 		err = drv->request_acquire(drv);
 		if(err != 0) {
 			dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
-			unlock_kernel();
+			mutex_unlock(&dev->core->lock);;
 			return err;
 		}
 	}
@@ -1073,7 +1073,7 @@ static int mpeg_open(struct file *file)
 	if (!atomic_read(&dev->core->mpeg_users) && blackbird_initialize_codec(dev) < 0) {
 		if (drv)
 			drv->request_release(drv);
-		unlock_kernel();
+		mutex_unlock(&dev->core->lock);
 		return -EINVAL;
 	}
 	dprintk(1, "open dev=%s\n", video_device_node_name(vdev));
@@ -1083,7 +1083,7 @@ static int mpeg_open(struct file *file)
 	if (NULL == fh) {
 		if (drv)
 			drv->request_release(drv);
-		unlock_kernel();
+		mutex_unlock(&dev->core->lock);
 		return -ENOMEM;
 	}
 	file->private_data = fh;
@@ -1099,10 +1099,9 @@ static int mpeg_open(struct file *file)
 	/* FIXME: locking against other video device */
 	cx88_set_scale(dev->core, dev->width, dev->height,
 			fh->mpegq.field);
-	unlock_kernel();
 
 	atomic_inc(&dev->core->mpeg_users);
-
+	mutex_unlock(&dev->core->lock);
 	return 0;
 }
 
@@ -1120,8 +1119,11 @@ static int mpeg_release(struct file *file)
 	videobuf_stop(&fh->mpegq);
 
 	videobuf_mmap_free(&fh->mpegq);
+
+	mutex_lock(&dev->core->lock);
 	file->private_data = NULL;
 	kfree(fh);
+	mutex_unlock(&dev->core->lock);
 
 	/* Make sure we release the hardware */
 	drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 0fab65c..381398d 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -769,19 +769,14 @@ static int video_open(struct file *file)
 		break;
 	}
 
-	lock_kernel();
-
-	core = dev->core;
-
 	dprintk(1, "open dev=%s radio=%d type=%s\n",
 		video_device_node_name(vdev), radio, v4l2_type_names[type]);
 
 	/* allocate + initialize per filehandle data */
 	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
-	if (NULL == fh) {
-		unlock_kernel();
+	if (unlikely(!fh))
 		return -ENOMEM;
-	}
+
 	file->private_data = fh;
 	fh->dev      = dev;
 	fh->radio    = radio;
@@ -790,6 +785,9 @@ static int video_open(struct file *file)
 	fh->height   = 240;
 	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
 
+	mutex_lock(&core->lock);
+	core = dev->core;
+
 	videobuf_queue_sg_init(&fh->vidq, &cx8800_video_qops,
 			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
@@ -826,9 +824,9 @@ static int video_open(struct file *file)
 		}
 		call_all(core, tuner, s_radio);
 	}
-	unlock_kernel();
 
 	atomic_inc(&core->users);
+	mutex_unlock(&core->lock);
 
 	return 0;
 }
@@ -920,10 +918,11 @@ static int video_release(struct file *file)
 
 	videobuf_mmap_free(&fh->vidq);
 	videobuf_mmap_free(&fh->vbiq);
+
+	mutex_lock(&dev->core->lock);
 	file->private_data = NULL;
 	kfree(fh);
 
-	mutex_lock(&dev->core->lock);
 	if(atomic_dec_and_test(&dev->core->users))
 		call_all(dev->core, core, s_power, 0);
 	mutex_unlock(&dev->core->lock);
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 8/8] V4L/DVB: Deprecate stradis driver
       [not found] <cover.1284597566.git.mchehab@redhat.com>
                   ` (5 preceding siblings ...)
  2010-09-16  0:56 ` [PATCH 6/8] V4L/DVB: cx88: Remove BKL Mauro Carvalho Chehab
@ 2010-09-16  0:56 ` Mauro Carvalho Chehab
  6 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2010-09-16  0:56 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Arnd Bergmann, Hans Verkuil

The driver author seems to not worked on this driver since its conversion
from 2.2 to 2.4. Nobody is known to have a stradis hardware for testing. As
it still uses V4L1 API, BKL and probably some other old stuff, someone would
need to work on it to preserve the driver. Instead of investing time and
efforts to keep porting it to work with new API's, it seems better to just
drop the driver.

So, let's move it to drivers/staging and label it to die at 2.6.38, if nobody
cares enough to port parallel port support to gspca or to create a new driver
that uses the same gspca-cpia sub-driver.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

 delete mode 100644 drivers/media/video/stradis.c
 create mode 100644 drivers/staging/stradis/Kconfig
 create mode 100644 drivers/staging/stradis/Makefile
 create mode 100644 drivers/staging/stradis/TODO
 create mode 100644 drivers/staging/stradis/stradis.c

diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 8052768..465b412 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -118,8 +118,8 @@ Who:	Mauro Carvalho Chehab <mchehab@infradead.org>
 
 What:	Video4Linux obsolete drivers using V4L1 API
 When:	kernel 2.6.38
-Files:	drivers/staging/cpia/*
-Check:	drivers/staging/cpia/cpia.c
+Files:	drivers/staging/cpia/* drivers/staging/stradis/*
+Check:	drivers/staging/cpia/cpia.c drivers/staging/stradis/stradis.c
 Why:	There are some drivers still using V4L1 API, despite all efforts we've done
 	to migrate. Those drivers are for obsolete hardware that the old maintainer
 	didn't care (or not have the hardware anymore), and that no other developer
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index e417bc0..d50b111 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -629,14 +629,6 @@ config VIDEO_VINO
 	  Say Y here to build in support for the Vino video input system found
 	  on SGI Indy machines.
 
-config VIDEO_STRADIS
-	tristate "Stradis 4:2:2 MPEG-2 video driver  (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
-	help
-	  Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
-	  driver for PCI.  There is a product page at
-	  <http://www.stradis.com/>.
-
 source "drivers/media/video/zoran/Kconfig"
 
 config VIDEO_MEYE
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 6751b32..46938f9 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -93,7 +93,6 @@ obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
 obj-$(CONFIG_VIDEO_W9966) += w9966.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_VINO) += vino.o
-obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
 obj-$(CONFIG_VIDEO_MEYE) += meye.o
 obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
deleted file mode 100644
index a057824..0000000
--- a/drivers/media/video/stradis.c
+++ /dev/null
@@ -1,2213 +0,0 @@
-/*
- * stradis.c - stradis 4:2:2 mpeg decoder driver
- *
- * Stradis 4:2:2 MPEG-2 Decoder Driver
- * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/pci.h>
-#include <linux/signal.h>
-#include <asm/io.h>
-#include <linux/ioport.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <asm/types.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <asm/uaccess.h>
-#include <linux/vmalloc.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-
-#include "saa7146.h"
-#include "saa7146reg.h"
-#include "ibmmpeg2.h"
-#include "saa7121.h"
-#include "cs8420.h"
-
-#define DEBUG(x)		/* debug driver */
-#undef  IDEBUG			/* debug irq handler */
-#undef  MDEBUG			/* debug memory management */
-
-#define SAA7146_MAX 6
-
-static struct saa7146 saa7146s[SAA7146_MAX];
-
-static int saa_num;		/* number of SAA7146s in use */
-
-static int video_nr = -1;
-module_param(video_nr, int, 0);
-MODULE_LICENSE("GPL");
-
-#define nDebNormal	0x00480000
-#define nDebNoInc	0x00480000
-#define nDebVideo	0xd0480000
-#define nDebAudio	0xd0400000
-#define nDebDMA		0x02c80000
-
-#define oDebNormal	0x13c80000
-#define oDebNoInc	0x13c80000
-#define oDebVideo	0xd1080000
-#define oDebAudio	0xd1080000
-#define oDebDMA		0x03080000
-
-#define NewCard		(saa->boardcfg[3])
-#define ChipControl	(saa->boardcfg[1])
-#define NTSCFirstActive	(saa->boardcfg[4])
-#define PALFirstActive	(saa->boardcfg[5])
-#define NTSCLastActive	(saa->boardcfg[54])
-#define PALLastActive	(saa->boardcfg[55])
-#define Have2MB		(saa->boardcfg[18] & 0x40)
-#define HaveCS8420	(saa->boardcfg[18] & 0x04)
-#define IBMMPEGCD20	(saa->boardcfg[18] & 0x20)
-#define HaveCS3310	(saa->boardcfg[18] & 0x01)
-#define CS3310MaxLvl	((saa->boardcfg[30] << 8) | saa->boardcfg[31])
-#define HaveCS4341	(saa->boardcfg[40] == 2)
-#define SDIType		(saa->boardcfg[27])
-#define CurrentMode	(saa->boardcfg[2])
-
-#define debNormal	(NewCard ? nDebNormal : oDebNormal)
-#define debNoInc	(NewCard ? nDebNoInc : oDebNoInc)
-#define debVideo	(NewCard ? nDebVideo : oDebVideo)
-#define debAudio	(NewCard ? nDebAudio : oDebAudio)
-#define debDMA		(NewCard ? nDebDMA : oDebDMA)
-
-#ifdef USE_RESCUE_EEPROM_SDM275
-static unsigned char rescue_eeprom[64] = {
-	0x00, 0x01, 0x04, 0x13, 0x26, 0x0f, 0x10, 0x00, 0x00, 0x00, 0x43, 0x63,
-	0x22, 0x01, 0x29, 0x15, 0x73, 0x00, 0x1f,  'd',  'e',  'c',  'x',  'l',
-	 'd',  'v',  'a', 0x02, 0x00, 0x01, 0x00, 0xcc, 0xa4, 0x63, 0x09, 0xe2,
-	0x10, 0x00, 0x0a, 0x00, 0x02, 0x02,  'd',  'e',  'c',  'x',  'l',  'a',
-	0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00,
-};
-#endif
-
-/* ----------------------------------------------------------------------- */
-/* Hardware I2C functions */
-static void I2CWipe(struct saa7146 *saa)
-{
-	int i;
-	/* set i2c to ~=100kHz, abort transfer, clear busy */
-	saawrite(0x600 | SAA7146_I2C_ABORT, SAA7146_I2C_STATUS);
-	saawrite((SAA7146_MC2_UPLD_I2C << 16) |
-		 SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
-	/* wait for i2c registers to be programmed */
-	for (i = 0; i < 1000 &&
-	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
-		schedule();
-	saawrite(0x600, SAA7146_I2C_STATUS);
-	saawrite((SAA7146_MC2_UPLD_I2C << 16) |
-		 SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
-	/* wait for i2c registers to be programmed */
-	for (i = 0; i < 1000 &&
-	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
-		schedule();
-	saawrite(0x600, SAA7146_I2C_STATUS);
-	saawrite((SAA7146_MC2_UPLD_I2C << 16) |
-		 SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
-	/* wait for i2c registers to be programmed */
-	for (i = 0; i < 1000 &&
-	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
-		schedule();
-}
-
-/* read I2C */
-static int I2CRead(struct saa7146 *saa, unsigned char addr,
-		   unsigned char subaddr, int dosub)
-{
-	int i;
-
-	if (saaread(SAA7146_I2C_STATUS) & 0x3c)
-		I2CWipe(saa);
-	for (i = 0;
-		i < 1000 && (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY);
-		i++)
-		schedule();
-	if (i == 1000)
-		I2CWipe(saa);
-	if (dosub)
-		saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 8) |
-			((subaddr & 0xff) << 16) | 0xed, SAA7146_I2C_TRANSFER);
-	else
-		saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 16) |
-			0xf1, SAA7146_I2C_TRANSFER);
-	saawrite((SAA7146_MC2_UPLD_I2C << 16) |
-		 SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
-	/* wait for i2c registers to be programmed */
-	for (i = 0; i < 1000 &&
-	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
-		schedule();
-	/* wait for valid data */
-	for (i = 0; i < 1000 &&
-	     (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
-		schedule();
-	if (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_ERR)
-		return -1;
-	if (i == 1000)
-		printk("i2c setup read timeout\n");
-	saawrite(0x41, SAA7146_I2C_TRANSFER);
-	saawrite((SAA7146_MC2_UPLD_I2C << 16) |
-		 SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
-	/* wait for i2c registers to be programmed */
-	for (i = 0; i < 1000 &&
-	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
-		schedule();
-	/* wait for valid data */
-	for (i = 0; i < 1000 &&
-	     (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_BUSY); i++)
-		schedule();
-	if (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_ERR)
-		return -1;
-	if (i == 1000)
-		printk("i2c read timeout\n");
-	return ((saaread(SAA7146_I2C_TRANSFER) >> 24) & 0xff);
-}
-
-/* set both to write both bytes, reset it to write only b1 */
-
-static int I2CWrite(struct saa7146 *saa, unsigned char addr, unsigned char b1,
-		    unsigned char b2, int both)
-{
-	int i;
-	u32 data;
-
-	if (saaread(SAA7146_I2C_STATUS) & 0x3c)
-		I2CWipe(saa);
-	for (i = 0; i < 1000 &&
-	     (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
-		schedule();
-	if (i == 1000)
-		I2CWipe(saa);
-	data = ((addr & 0xfe) << 24) | ((b1 & 0xff) << 16);
-	if (both)
-		data |= ((b2 & 0xff) << 8) | 0xe5;
-	else
-		data |= 0xd1;
-	saawrite(data, SAA7146_I2C_TRANSFER);
-	saawrite((SAA7146_MC2_UPLD_I2C << 16) | SAA7146_MC2_UPLD_I2C,
-		 SAA7146_MC2);
-	return 0;
-}
-
-static void attach_inform(struct saa7146 *saa, int id)
-{
-	int i;
-
-	DEBUG(printk(KERN_DEBUG "stradis%d: i2c: device found=%02x\n", saa->nr,
-		id));
-	if (id == 0xa0) {	/* we have rev2 or later board, fill in info */
-		for (i = 0; i < 64; i++)
-			saa->boardcfg[i] = I2CRead(saa, 0xa0, i, 1);
-#ifdef USE_RESCUE_EEPROM_SDM275
-		if (saa->boardcfg[0] != 0) {
-			printk("stradis%d: WARNING: EEPROM STORED VALUES HAVE "
-				"BEEN IGNORED\n", saa->nr);
-			for (i = 0; i < 64; i++)
-				saa->boardcfg[i] = rescue_eeprom[i];
-		}
-#endif
-		printk("stradis%d: config =", saa->nr);
-		for (i = 0; i < 51; i++) {
-			printk(" %02x", saa->boardcfg[i]);
-		}
-		printk("\n");
-	}
-}
-
-static void I2CBusScan(struct saa7146 *saa)
-{
-	int i;
-	for (i = 0; i < 0xff; i += 2)
-		if ((I2CRead(saa, i, 0, 0)) >= 0)
-			attach_inform(saa, i);
-}
-
-static int debiwait_maxwait;
-
-static int wait_for_debi_done(struct saa7146 *saa)
-{
-	int i;
-
-	/* wait for registers to be programmed */
-	for (i = 0; i < 100000 &&
-	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_DEBI); i++)
-		saaread(SAA7146_MC2);
-	/* wait for transfer to complete */
-	for (i = 0; i < 500000 &&
-	     (saaread(SAA7146_PSR) & SAA7146_PSR_DEBI_S); i++)
-		saaread(SAA7146_MC2);
-
-	if (i > debiwait_maxwait)
-		printk("wait-for-debi-done maxwait: %d\n",
-			debiwait_maxwait = i);
-
-	if (i == 500000)
-		return -1;
-
-	return 0;
-}
-
-static int debiwrite(struct saa7146 *saa, u32 config, int addr,
-	u32 val, int count)
-{
-	u32 cmd;
-	if (count <= 0 || count > 32764)
-		return -1;
-	if (wait_for_debi_done(saa) < 0)
-		return -1;
-	saawrite(config, SAA7146_DEBI_CONFIG);
-	if (count <= 4)		/* immediate transfer */
-		saawrite(val, SAA7146_DEBI_AD);
-	else			/* block transfer */
-		saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
-	saawrite((cmd = (count << 17) | (addr & 0xffff)), SAA7146_DEBI_COMMAND);
-	saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
-		 SAA7146_MC2);
-	return 0;
-}
-
-static u32 debiread(struct saa7146 *saa, u32 config, int addr, int count)
-{
-	u32 result = 0;
-
-	if (count > 32764 || count <= 0)
-		return 0;
-	if (wait_for_debi_done(saa) < 0)
-		return 0;
-	saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
-	saawrite((count << 17) | 0x10000 | (addr & 0xffff),
-		 SAA7146_DEBI_COMMAND);
-	saawrite(config, SAA7146_DEBI_CONFIG);
-	saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
-		 SAA7146_MC2);
-	if (count > 4)		/* not an immediate transfer */
-		return count;
-	wait_for_debi_done(saa);
-	result = saaread(SAA7146_DEBI_AD);
-	if (count == 1)
-		result &= 0xff;
-	if (count == 2)
-		result &= 0xffff;
-	if (count == 3)
-		result &= 0xffffff;
-	return result;
-}
-
-static void do_irq_send_data(struct saa7146 *saa)
-{
-	int split, audbytes, vidbytes;
-
-	saawrite(SAA7146_PSR_PIN1, SAA7146_IER);
-	/* if special feature mode in effect, disable audio sending */
-	if (saa->playmode != VID_PLAY_NORMAL)
-		saa->audtail = saa->audhead = 0;
-	if (saa->audhead <= saa->audtail)
-		audbytes = saa->audtail - saa->audhead;
-	else
-		audbytes = 65536 - (saa->audhead - saa->audtail);
-	if (saa->vidhead <= saa->vidtail)
-		vidbytes = saa->vidtail - saa->vidhead;
-	else
-		vidbytes = 524288 - (saa->vidhead - saa->vidtail);
-	if (audbytes == 0 && vidbytes == 0 && saa->osdtail == saa->osdhead) {
-		saawrite(0, SAA7146_IER);
-		return;
-	}
-	/* if at least 1 block audio waiting and audio fifo isn't full */
-	if (audbytes >= 2048 && (debiread(saa, debNormal, IBM_MP2_AUD_FIFO, 2)
-			& 0xff) < 60) {
-		if (saa->audhead > saa->audtail)
-			split = 65536 - saa->audhead;
-		else
-			split = 0;
-		audbytes = 2048;
-		if (split > 0 && split < 2048) {
-			memcpy(saa->dmadebi, saa->audbuf + saa->audhead, split);
-			saa->audhead = 0;
-			audbytes -= split;
-		} else
-			split = 0;
-		memcpy(saa->dmadebi + split, saa->audbuf + saa->audhead,
-			audbytes);
-		saa->audhead += audbytes;
-		saa->audhead &= 0xffff;
-		debiwrite(saa, debAudio, (NewCard ? IBM_MP2_AUD_FIFO :
-			IBM_MP2_AUD_FIFOW), 0, 2048);
-		wake_up_interruptible(&saa->audq);
-		/* if at least 1 block video waiting and video fifo isn't full */
-	} else if (vidbytes >= 30720 && (debiread(saa, debNormal,
-						  IBM_MP2_FIFO, 2)) < 16384) {
-		if (saa->vidhead > saa->vidtail)
-			split = 524288 - saa->vidhead;
-		else
-			split = 0;
-		vidbytes = 30720;
-		if (split > 0 && split < 30720) {
-			memcpy(saa->dmadebi, saa->vidbuf + saa->vidhead, split);
-			saa->vidhead = 0;
-			vidbytes -= split;
-		} else
-			split = 0;
-		memcpy(saa->dmadebi + split, saa->vidbuf + saa->vidhead,
-			vidbytes);
-		saa->vidhead += vidbytes;
-		saa->vidhead &= 0x7ffff;
-		debiwrite(saa, debVideo, (NewCard ? IBM_MP2_FIFO :
-					  IBM_MP2_FIFOW), 0, 30720);
-		wake_up_interruptible(&saa->vidq);
-	}
-	saawrite(SAA7146_PSR_DEBI_S | SAA7146_PSR_PIN1, SAA7146_IER);
-}
-
-static void send_osd_data(struct saa7146 *saa)
-{
-	int size = saa->osdtail - saa->osdhead;
-	if (size > 30720)
-		size = 30720;
-	/* ensure some multiple of 8 bytes is transferred */
-	size = 8 * ((size + 8) >> 3);
-	if (size) {
-		debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR,
-			  (saa->osdhead >> 3), 2);
-		memcpy(saa->dmadebi, &saa->osdbuf[saa->osdhead], size);
-		saa->osdhead += size;
-		/* block transfer of next 8 bytes to ~32k bytes */
-		debiwrite(saa, debNormal, IBM_MP2_OSD_DATA, 0, size);
-	}
-	if (saa->osdhead >= saa->osdtail) {
-		saa->osdhead = saa->osdtail = 0;
-		debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
-	}
-}
-
-static irqreturn_t saa7146_irq(int irq, void *dev_id)
-{
-	struct saa7146 *saa = dev_id;
-	u32 stat, astat;
-	int count;
-	int handled = 0;
-
-	count = 0;
-	while (1) {
-		/* get/clear interrupt status bits */
-		stat = saaread(SAA7146_ISR);
-		astat = stat & saaread(SAA7146_IER);
-		if (!astat)
-			break;
-		handled = 1;
-		saawrite(astat, SAA7146_ISR);
-		if (astat & SAA7146_PSR_DEBI_S) {
-			do_irq_send_data(saa);
-		}
-		if (astat & SAA7146_PSR_PIN1) {
-			int istat;
-			/* the following read will trigger DEBI_S */
-			istat = debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
-			if (istat & 1) {
-				saawrite(0, SAA7146_IER);
-				send_osd_data(saa);
-				saawrite(SAA7146_PSR_DEBI_S |
-					 SAA7146_PSR_PIN1, SAA7146_IER);
-			}
-			if (istat & 0x20) {	/* Video Start */
-				saa->vidinfo.frame_count++;
-			}
-			if (istat & 0x400) {	/* Picture Start */
-				/* update temporal reference */
-			}
-			if (istat & 0x200) {	/* Picture Resolution Change */
-				/* read new resolution */
-			}
-			if (istat & 0x100) {	/* New User Data found */
-				/* read new user data */
-			}
-			if (istat & 0x1000) {	/* new GOP/SMPTE */
-				/* read new SMPTE */
-			}
-			if (istat & 0x8000) {	/* Sequence Start Code */
-				/* reset frame counter, load sizes */
-				saa->vidinfo.frame_count = 0;
-				saa->vidinfo.h_size = 704;
-				saa->vidinfo.v_size = 480;
-#if 0
-				if (saa->endmarkhead != saa->endmarktail) {
-					saa->audhead =
-						saa->endmark[saa->endmarkhead];
-					saa->endmarkhead++;
-					if (saa->endmarkhead >= MAX_MARKS)
-						saa->endmarkhead = 0;
-				}
-#endif
-			}
-			if (istat & 0x4000) {	/* Sequence Error Code */
-				if (saa->endmarkhead != saa->endmarktail) {
-					saa->audhead =
-						saa->endmark[saa->endmarkhead];
-					saa->endmarkhead++;
-					if (saa->endmarkhead >= MAX_MARKS)
-						saa->endmarkhead = 0;
-				}
-			}
-		}
-#ifdef IDEBUG
-		if (astat & SAA7146_PSR_PPEF) {
-			IDEBUG(printk("stradis%d irq: PPEF\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_PABO) {
-			IDEBUG(printk("stradis%d irq: PABO\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_PPED) {
-			IDEBUG(printk("stradis%d irq: PPED\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_RPS_I1) {
-			IDEBUG(printk("stradis%d irq: RPS_I1\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_RPS_I0) {
-			IDEBUG(printk("stradis%d irq: RPS_I0\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_RPS_LATE1) {
-			IDEBUG(printk("stradis%d irq: RPS_LATE1\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_RPS_LATE0) {
-			IDEBUG(printk("stradis%d irq: RPS_LATE0\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_RPS_E1) {
-			IDEBUG(printk("stradis%d irq: RPS_E1\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_RPS_E0) {
-			IDEBUG(printk("stradis%d irq: RPS_E0\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_RPS_TO1) {
-			IDEBUG(printk("stradis%d irq: RPS_TO1\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_RPS_TO0) {
-			IDEBUG(printk("stradis%d irq: RPS_TO0\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_UPLD) {
-			IDEBUG(printk("stradis%d irq: UPLD\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_DEBI_E) {
-			IDEBUG(printk("stradis%d irq: DEBI_E\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_I2C_S) {
-			IDEBUG(printk("stradis%d irq: I2C_S\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_I2C_E) {
-			IDEBUG(printk("stradis%d irq: I2C_E\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_A2_IN) {
-			IDEBUG(printk("stradis%d irq: A2_IN\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_A2_OUT) {
-			IDEBUG(printk("stradis%d irq: A2_OUT\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_A1_IN) {
-			IDEBUG(printk("stradis%d irq: A1_IN\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_A1_OUT) {
-			IDEBUG(printk("stradis%d irq: A1_OUT\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_AFOU) {
-			IDEBUG(printk("stradis%d irq: AFOU\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_V_PE) {
-			IDEBUG(printk("stradis%d irq: V_PE\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_VFOU) {
-			IDEBUG(printk("stradis%d irq: VFOU\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_FIDA) {
-			IDEBUG(printk("stradis%d irq: FIDA\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_FIDB) {
-			IDEBUG(printk("stradis%d irq: FIDB\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_PIN3) {
-			IDEBUG(printk("stradis%d irq: PIN3\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_PIN2) {
-			IDEBUG(printk("stradis%d irq: PIN2\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_PIN0) {
-			IDEBUG(printk("stradis%d irq: PIN0\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_ECS) {
-			IDEBUG(printk("stradis%d irq: ECS\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_EC3S) {
-			IDEBUG(printk("stradis%d irq: EC3S\n", saa->nr));
-		}
-		if (astat & SAA7146_PSR_EC0S) {
-			IDEBUG(printk("stradis%d irq: EC0S\n", saa->nr));
-		}
-#endif
-		count++;
-		if (count > 15)
-			printk(KERN_WARNING "stradis%d: irq loop %d\n",
-			       saa->nr, count);
-		if (count > 20) {
-			saawrite(0, SAA7146_IER);
-			printk(KERN_ERR
-			       "stradis%d: IRQ loop cleared\n", saa->nr);
-		}
-	}
-	return IRQ_RETVAL(handled);
-}
-
-static int ibm_send_command(struct saa7146 *saa,
-			    int command, int data, int chain)
-{
-	int i;
-
-	if (chain)
-		debiwrite(saa, debNormal, IBM_MP2_COMMAND, (command << 1)| 1,2);
-	else
-		debiwrite(saa, debNormal, IBM_MP2_COMMAND, command << 1, 2);
-	debiwrite(saa, debNormal, IBM_MP2_CMD_DATA, data, 2);
-	debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 1, 2);
-	for (i = 0; i < 100 &&
-	     (debiread(saa, debNormal, IBM_MP2_CMD_STAT, 2) & 1); i++)
-		schedule();
-	if (i == 100)
-		return -1;
-	return 0;
-}
-
-static void cs4341_setlevel(struct saa7146 *saa, int left, int right)
-{
-	I2CWrite(saa, 0x22, 0x03, left > 94 ? 94 : left, 2);
-	I2CWrite(saa, 0x22, 0x04, right > 94 ? 94 : right, 2);
-}
-
-static void initialize_cs4341(struct saa7146 *saa)
-{
-	int i;
-	for (i = 0; i < 200; i++) {
-		/* auto mute off, power on, no de-emphasis */
-		/* I2S data up to 24-bit 64xFs internal SCLK */
-		I2CWrite(saa, 0x22, 0x01, 0x11, 2);
-		/* ATAPI mixer settings */
-		I2CWrite(saa, 0x22, 0x02, 0x49, 2);
-		/* attenuation left 3db */
-		I2CWrite(saa, 0x22, 0x03, 0x00, 2);
-		/* attenuation right 3db */
-		I2CWrite(saa, 0x22, 0x04, 0x00, 2);
-		I2CWrite(saa, 0x22, 0x01, 0x10, 2);
-		if (I2CRead(saa, 0x22, 0x02, 1) == 0x49)
-			break;
-		schedule();
-	}
-	printk("stradis%d: CS4341 initialized (%d)\n", saa->nr, i);
-	return;
-}
-
-static void initialize_cs8420(struct saa7146 *saa, int pro)
-{
-	int i;
-	u8 *sequence;
-	if (pro)
-		sequence = mode8420pro;
-	else
-		sequence = mode8420con;
-	for (i = 0; i < INIT8420LEN; i++)
-		I2CWrite(saa, 0x20, init8420[i * 2], init8420[i * 2 + 1], 2);
-	for (i = 0; i < MODE8420LEN; i++)
-		I2CWrite(saa, 0x20, sequence[i * 2], sequence[i * 2 + 1], 2);
-	printk("stradis%d: CS8420 initialized\n", saa->nr);
-}
-
-static void initialize_saa7121(struct saa7146 *saa, int dopal)
-{
-	int i, mod;
-	u8 *sequence;
-	if (dopal)
-		sequence = init7121pal;
-	else
-		sequence = init7121ntsc;
-	mod = saaread(SAA7146_PSR) & 0x08;
-	/* initialize PAL/NTSC video encoder */
-	for (i = 0; i < INIT7121LEN; i++) {
-		if (NewCard) {	/* handle new card encoder differences */
-			if (sequence[i * 2] == 0x3a)
-				I2CWrite(saa, 0x88, 0x3a, 0x13, 2);
-			else if (sequence[i * 2] == 0x6b)
-				I2CWrite(saa, 0x88, 0x6b, 0x20, 2);
-			else if (sequence[i * 2] == 0x6c)
-				I2CWrite(saa, 0x88, 0x6c,
-					 dopal ? 0x09 : 0xf5, 2);
-			else if (sequence[i * 2] == 0x6d)
-				I2CWrite(saa, 0x88, 0x6d,
-					 dopal ? 0x20 : 0x00, 2);
-			else if (sequence[i * 2] == 0x7a)
-				I2CWrite(saa, 0x88, 0x7a,
-					 dopal ? (PALFirstActive - 1) :
-					 (NTSCFirstActive - 4), 2);
-			else if (sequence[i * 2] == 0x7b)
-				I2CWrite(saa, 0x88, 0x7b,
-					 dopal ? PALLastActive :
-					 NTSCLastActive, 2);
-			else
-				I2CWrite(saa, 0x88, sequence[i * 2],
-					 sequence[i * 2 + 1], 2);
-		} else {
-			if (sequence[i * 2] == 0x6b && mod)
-				I2CWrite(saa, 0x88, 0x6b,
-					 (sequence[i * 2 + 1] ^ 0x09), 2);
-			else if (sequence[i * 2] == 0x7a)
-				I2CWrite(saa, 0x88, 0x7a,
-					 dopal ? (PALFirstActive - 1) :
-					 (NTSCFirstActive - 4), 2);
-			else if (sequence[i * 2] == 0x7b)
-				I2CWrite(saa, 0x88, 0x7b,
-					 dopal ? PALLastActive :
-					 NTSCLastActive, 2);
-			else
-				I2CWrite(saa, 0x88, sequence[i * 2],
-					 sequence[i * 2 + 1], 2);
-		}
-	}
-}
-
-static void set_genlock_offset(struct saa7146 *saa, int noffset)
-{
-	int nCode;
-	int PixelsPerLine = 858;
-	if (CurrentMode == VIDEO_MODE_PAL)
-		PixelsPerLine = 864;
-	if (noffset > 500)
-		noffset = 500;
-	else if (noffset < -500)
-		noffset = -500;
-	nCode = noffset + 0x100;
-	if (nCode == 1)
-		nCode = 0x401;
-	else if (nCode < 1)
-		nCode = 0x400 + PixelsPerLine + nCode;
-	debiwrite(saa, debNormal, XILINX_GLDELAY, nCode, 2);
-}
-
-static void set_out_format(struct saa7146 *saa, int mode)
-{
-	initialize_saa7121(saa, (mode == VIDEO_MODE_NTSC ? 0 : 1));
-	saa->boardcfg[2] = mode;
-	/* do not adjust analog video parameters here, use saa7121 init */
-	/* you will affect the SDI output on the new card */
-	if (mode == VIDEO_MODE_PAL) {	/* PAL */
-		debiwrite(saa, debNormal, XILINX_CTL0, 0x0808, 2);
-		mdelay(50);
-		saawrite(0x012002c0, SAA7146_NUM_LINE_BYTE1);
-		if (NewCard) {
-			debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, 0xe100, 2);
-			mdelay(50);
-		}
-		debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
-			  NewCard ? 0xe500 : 0x6500, 2);
-		debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
-			  (1 << 8) |
-			  (NewCard ? PALFirstActive : PALFirstActive - 6), 2);
-	} else {		/* NTSC */
-		debiwrite(saa, debNormal, XILINX_CTL0, 0x0800, 2);
-		mdelay(50);
-		saawrite(0x00f002c0, SAA7146_NUM_LINE_BYTE1);
-		debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
-			  NewCard ? 0xe100 : 0x6100, 2);
-		debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
-			  (1 << 8) |
-			  (NewCard ? NTSCFirstActive : NTSCFirstActive - 6), 2);
-	}
-}
-
-/* Intialize bitmangler to map from a byte value to the mangled word that
- * must be output to program the Xilinx part through the DEBI port.
- * Xilinx Data Bit->DEBI Bit: 0->15 1->7 2->6 3->12 4->11 5->2 6->1 7->0
- * transfer FPGA code, init IBM chip, transfer IBM microcode
- * rev2 card mangles: 0->7 1->6 2->5 3->4 4->3 5->2 6->1 7->0
- */
-static u16 bitmangler[256];
-
-static int initialize_fpga(struct video_code *bitdata)
-{
-	int i, num, startindex, failure = 0, loadtwo, loadfile = 0;
-	u16 *dmabuf;
-	u8 *newdma;
-	struct saa7146 *saa;
-
-	/* verify fpga code */
-	for (startindex = 0; startindex < bitdata->datasize; startindex++)
-		if (bitdata->data[startindex] == 255)
-			break;
-	if (startindex == bitdata->datasize) {
-		printk(KERN_INFO "stradis: bad fpga code\n");
-		return -1;
-	}
-	/* initialize all detected cards */
-	for (num = 0; num < saa_num; num++) {
-		saa = &saa7146s[num];
-		if (saa->boardcfg[0] > 20)
-			continue;	/* card was programmed */
-		loadtwo = (saa->boardcfg[18] & 0x10);
-		if (!NewCard)	/* we have an old board */
-			for (i = 0; i < 256; i++)
-				bitmangler[i] = ((i & 0x01) << 15) |
-					((i & 0x02) << 6) | ((i & 0x04) << 4) |
-					((i & 0x08) << 9) | ((i & 0x10) << 7) |
-					((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
-					((i & 0x80) >> 7);
-		else		/* else we have a new board */
-			for (i = 0; i < 256; i++)
-				bitmangler[i] = ((i & 0x01) << 7) |
-					((i & 0x02) << 5) | ((i & 0x04) << 3) |
-					((i & 0x08) << 1) | ((i & 0x10) >> 1) |
-					((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
-					((i & 0x80) >> 7);
-
-		dmabuf = (u16 *) saa->dmadebi;
-		newdma = (u8 *) saa->dmadebi;
-		if (NewCard) {	/* SDM2xxx */
-			if (!strncmp(bitdata->loadwhat, "decoder2", 8))
-				continue;	/* fpga not for this card */
-			if (!strncmp(&saa->boardcfg[42], bitdata->loadwhat, 8))
-				loadfile = 1;
-			else if (loadtwo && !strncmp(&saa->boardcfg[19],
-				       bitdata->loadwhat, 8))
-				loadfile = 2;
-			else if (!saa->boardcfg[42] && !strncmp("decxl",
-					bitdata->loadwhat, 8))
-				loadfile = 1;	/* special */
-			else
-				continue;	/* fpga not for this card */
-			if (loadfile != 1 && loadfile != 2)
-				continue;	/* skip to next card */
-			if (saa->boardcfg[0] && loadfile == 1)
-				continue;	/* skip to next card */
-			if (saa->boardcfg[0] != 1 && loadfile == 2)
-				continue;	/* skip to next card */
-			saa->boardcfg[0]++;	/* mark fpga handled */
-			printk("stradis%d: loading %s\n", saa->nr,
-				bitdata->loadwhat);
-			if (loadtwo && loadfile == 2)
-				goto send_fpga_stuff;
-			/* turn on the Audio interface to set PROG low */
-			saawrite(0x00400040, SAA7146_GPIO_CTRL);
-			saaread(SAA7146_PSR);	/* ensure posted write */
-			/* wait for everyone to reset */
-			mdelay(10);
-			saawrite(0x00400000, SAA7146_GPIO_CTRL);
-		} else {	/* original card */
-			if (strncmp(bitdata->loadwhat, "decoder2", 8))
-				continue;	/* fpga not for this card */
-			/* Pull the Xilinx PROG signal WS3 low */
-			saawrite(0x02000200, SAA7146_MC1);
-			/* Turn on the Audio interface so can set PROG low */
-			saawrite(0x000000c0, SAA7146_ACON1);
-			/* Pull the Xilinx INIT signal (GPIO2) low */
-			saawrite(0x00400000, SAA7146_GPIO_CTRL);
-			/* Make sure everybody resets */
-			saaread(SAA7146_PSR);	/* ensure posted write */
-			mdelay(10);
-			/* Release the Xilinx PROG signal */
-			saawrite(0x00000000, SAA7146_ACON1);
-			/* Turn off the Audio interface */
-			saawrite(0x02000000, SAA7146_MC1);
-		}
-		/* Release Xilinx INIT signal (WS2) */
-		saawrite(0x00000000, SAA7146_GPIO_CTRL);
-		/* Wait for the INIT to go High */
-		for (i = 0;
-			i < 10000 && !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2);
-			i++)
-			schedule();
-		if (i == 1000) {
-			printk(KERN_INFO "stradis%d: no fpga INIT\n", saa->nr);
-			return -1;
-		}
-send_fpga_stuff:
-		if (NewCard) {
-			for (i = startindex; i < bitdata->datasize; i++)
-				newdma[i - startindex] =
-				    bitmangler[bitdata->data[i]];
-			debiwrite(saa, 0x01420000, 0, 0,
-				((bitdata->datasize - startindex) + 5));
-			if (loadtwo && loadfile == 1) {
-				printk("stradis%d: awaiting 2nd FPGA bitfile\n",
-				       saa->nr);
-				continue;	/* skip to next card */
-			}
-		} else {
-			for (i = startindex; i < bitdata->datasize; i++)
-				dmabuf[i - startindex] =
-					bitmangler[bitdata->data[i]];
-			debiwrite(saa, 0x014a0000, 0, 0,
-				((bitdata->datasize - startindex) + 5) * 2);
-		}
-		for (i = 0;
-			i < 1000 && !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2);
-			i++)
-			schedule();
-		if (i == 1000) {
-			printk(KERN_INFO "stradis%d: FPGA load failed\n",
-			       saa->nr);
-			failure++;
-			continue;
-		}
-		if (!NewCard) {
-			/* Pull the Xilinx INIT signal (GPIO2) low */
-			saawrite(0x00400000, SAA7146_GPIO_CTRL);
-			saaread(SAA7146_PSR);	/* ensure posted write */
-			mdelay(2);
-			saawrite(0x00000000, SAA7146_GPIO_CTRL);
-			mdelay(2);
-		}
-		printk(KERN_INFO "stradis%d: FPGA Loaded\n", saa->nr);
-		saa->boardcfg[0] = 26;	/* mark fpga programmed */
-		/* set VXCO to its lowest frequency */
-		debiwrite(saa, debNormal, XILINX_PWM, 0, 2);
-		if (NewCard) {
-			/* mute CS3310 */
-			if (HaveCS3310)
-				debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
-					0, 2);
-			/* set VXCO to PWM mode, release reset, blank on */
-			debiwrite(saa, debNormal, XILINX_CTL0, 0xffc4, 2);
-			mdelay(10);
-			/* unmute CS3310 */
-			if (HaveCS3310)
-				debiwrite(saa, debNormal, XILINX_CTL0,
-					0x2020, 2);
-		}
-		/* set source Black */
-		debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
-		saa->boardcfg[4] = 22;	/* set NTSC First Active Line */
-		saa->boardcfg[5] = 23;	/* set PAL First Active Line */
-		saa->boardcfg[54] = 2;	/* set NTSC Last Active Line - 256 */
-		saa->boardcfg[55] = 54;	/* set PAL Last Active Line - 256 */
-		set_out_format(saa, VIDEO_MODE_NTSC);
-		mdelay(50);
-		/* begin IBM chip init */
-		debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
-		saaread(SAA7146_PSR);	/* wait for reset */
-		mdelay(5);
-		debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
-		debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
-		debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0x10, 2);
-		debiwrite(saa, debNormal, IBM_MP2_CMD_ADDR, 0, 2);
-		debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
-		if (NewCard) {
-			mdelay(5);
-			/* set i2s rate converter to 48KHz */
-			debiwrite(saa, debNormal, 0x80c0, 6, 2);
-			/* we must init CS8420 first since rev b pulls i2s */
-			/* master clock low and CS4341 needs i2s master to */
-			/* run the i2c port. */
-			if (HaveCS8420)
-				/* 0=consumer, 1=pro */
-				initialize_cs8420(saa, 0);
-
-			mdelay(5);
-			if (HaveCS4341)
-				initialize_cs4341(saa);
-		}
-		debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
-		debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
-		debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
-		debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
-		if (NewCard)
-			set_genlock_offset(saa, 0);
-		debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
-#if 0
-		/* enable genlock */
-		debiwrite(saa, debNormal, XILINX_CTL0, 0x8000, 2);
-#else
-		/* disable genlock */
-		debiwrite(saa, debNormal, XILINX_CTL0, 0x8080, 2);
-#endif
-	}
-
-	return failure;
-}
-
-static int do_ibm_reset(struct saa7146 *saa)
-{
-	/* failure if decoder not previously programmed */
-	if (saa->boardcfg[0] < 37)
-		return -EIO;
-	/* mute CS3310 */
-	if (HaveCS3310)
-		debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, 0, 2);
-	/* disable interrupts */
-	saawrite(0, SAA7146_IER);
-	saa->audhead = saa->audtail = 0;
-	saa->vidhead = saa->vidtail = 0;
-	/* tristate debi bus, disable debi transfers */
-	saawrite(0x00880000, SAA7146_MC1);
-	/* ensure posted write */
-	saaread(SAA7146_MC1);
-	mdelay(50);
-	/* re-enable debi transfers */
-	saawrite(0x00880088, SAA7146_MC1);
-	/* set source Black */
-	debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
-	/* begin IBM chip init */
-	set_out_format(saa, CurrentMode);
-	debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
-	saaread(SAA7146_PSR);	/* wait for reset */
-	mdelay(5);
-	debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
-	debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
-	debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
-	debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
-	if (NewCard) {
-		mdelay(5);
-		/* set i2s rate converter to 48KHz */
-		debiwrite(saa, debNormal, 0x80c0, 6, 2);
-		/* we must init CS8420 first since rev b pulls i2s */
-		/* master clock low and CS4341 needs i2s master to */
-		/* run the i2c port. */
-		if (HaveCS8420)
-			/* 0=consumer, 1=pro */
-			initialize_cs8420(saa, 1);
-
-		mdelay(5);
-		if (HaveCS4341)
-			initialize_cs4341(saa);
-	}
-	debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
-	debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
-	debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
-	debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
-	if (NewCard)
-		set_genlock_offset(saa, 0);
-	debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
-	debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
-	debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
-	if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
-			(ChipControl == 0x43 ? 0xe800 : 0xe000), 1)) {
-		printk(KERN_ERR "stradis%d: IBM config failed\n", saa->nr);
-	}
-	if (HaveCS3310) {
-		int i = CS3310MaxLvl;
-		debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, ((i << 8)| i),2);
-	}
-	/* start video decoder */
-	debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
-	/* 256k vid, 3520 bytes aud */
-	debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037, 2);
-	debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
-	ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
-	/* enable buffer threshold irq */
-	debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
-	/* clear pending interrupts */
-	debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
-	debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
-
-	return 0;
-}
-
-/* load the decoder microcode */
-static int initialize_ibmmpeg2(struct video_code *microcode)
-{
-	int i, num;
-	struct saa7146 *saa;
-
-	for (num = 0; num < saa_num; num++) {
-		saa = &saa7146s[num];
-		/* check that FPGA is loaded */
-		debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0xa55a, 2);
-		i = debiread(saa, debNormal, IBM_MP2_OSD_SIZE, 2);
-		if (i != 0xa55a) {
-			printk(KERN_INFO "stradis%d: %04x != 0xa55a\n",
-				saa->nr, i);
-#if 0
-			return -1;
-#endif
-		}
-		if (!strncmp(microcode->loadwhat, "decoder.vid", 11)) {
-			if (saa->boardcfg[0] > 27)
-				continue;	/* skip to next card */
-			/* load video control store */
-			saa->boardcfg[1] = 0x13;	/* no-sync default */
-			debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
-			debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
-			for (i = 0; i < microcode->datasize / 2; i++)
-				debiwrite(saa, debNormal, IBM_MP2_PROC_IDATA,
-					(microcode->data[i * 2] << 8) |
-					microcode->data[i * 2 + 1], 2);
-			debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
-			debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
-			debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
-				ChipControl, 2);
-			saa->boardcfg[0] = 28;
-		}
-		if (!strncmp(microcode->loadwhat, "decoder.aud", 11)) {
-			if (saa->boardcfg[0] > 35)
-				continue;	/* skip to next card */
-			/* load audio control store */
-			debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
-			debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
-			for (i = 0; i < microcode->datasize; i++)
-				debiwrite(saa, debNormal, IBM_MP2_AUD_IDATA,
-					microcode->data[i], 1);
-			debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
-			debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
-			debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
-			debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
-			if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
-					0xe000, 1)) {
-				printk(KERN_ERR "stradis%d: IBM config "
-					"failed\n", saa->nr);
-				return -1;
-			}
-			/* set PWM to center value */
-			if (NewCard) {
-				debiwrite(saa, debNormal, XILINX_PWM,
-					saa->boardcfg[14] +
-					(saa->boardcfg[13] << 8), 2);
-			} else
-				debiwrite(saa, debNormal, XILINX_PWM, 0x46, 2);
-
-			if (HaveCS3310) {
-				i = CS3310MaxLvl;
-				debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
-					(i << 8) | i, 2);
-			}
-			printk(KERN_INFO "stradis%d: IBM MPEGCD%d Inited\n",
-				saa->nr, 18 + (debiread(saa, debNormal,
-				IBM_MP2_CHIP_CONTROL, 2) >> 12));
-			/* start video decoder */
-			debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
-				ChipControl, 2);
-			debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037,
-				2);	/* 256k vid, 3520 bytes aud */
-			debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
-			ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
-			/* enable buffer threshold irq */
-			debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
-			debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
-			/* enable gpio irq */
-			saawrite(0x00002000, SAA7146_GPIO_CTRL);
-			/* enable decoder output to HPS */
-			debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
-			saa->boardcfg[0] = 37;
-		}
-	}
-
-	return 0;
-}
-
-static u32 palette2fmt[] = {	/* some of these YUV translations are wrong */
-	0xffffffff, 0x86000000, 0x87000000, 0x80000000, 0x8100000, 0x82000000,
-	0x83000000, 0x00000000, 0x03000000, 0x03000000, 0x0a00000, 0x03000000,
-	0x06000000, 0x00000000, 0x03000000, 0x0a000000, 0x0300000
-};
-static int bpp2fmt[4] = {
-	VIDEO_PALETTE_HI240, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB24,
-	VIDEO_PALETTE_RGB32
-};
-
-/* I wish I could find a formula to calculate these... */
-static u32 h_prescale[64] = {
-	0x10000000, 0x18040202, 0x18080000, 0x380c0606, 0x38100204, 0x38140808,
-	0x38180000, 0x381c0000, 0x3820161c, 0x38242a3b, 0x38281230, 0x382c4460,
-	0x38301040, 0x38340080, 0x38380000, 0x383c0000, 0x3840fefe, 0x3844ee9f,
-	0x3848ee9f, 0x384cee9f, 0x3850ee9f, 0x38542a3b, 0x38581230, 0x385c0000,
-	0x38600000, 0x38640000, 0x38680000, 0x386c0000, 0x38700000, 0x38740000,
-	0x38780000, 0x387c0000, 0x30800000, 0x38840000, 0x38880000, 0x388c0000,
-	0x38900000, 0x38940000, 0x38980000, 0x389c0000, 0x38a00000, 0x38a40000,
-	0x38a80000, 0x38ac0000, 0x38b00000, 0x38b40000, 0x38b80000, 0x38bc0000,
-	0x38c00000, 0x38c40000, 0x38c80000, 0x38cc0000, 0x38d00000, 0x38d40000,
-	0x38d80000, 0x38dc0000, 0x38e00000, 0x38e40000, 0x38e80000, 0x38ec0000,
-	0x38f00000, 0x38f40000, 0x38f80000, 0x38fc0000,
-};
-static u32 v_gain[64] = {
-	0x016000ff, 0x016100ff, 0x016100ff, 0x016200ff, 0x016200ff, 0x016200ff,
-	0x016200ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff,
-	0x016300ff, 0x016300ff, 0x016300ff, 0x016400ff, 0x016400ff, 0x016400ff,
-	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
-	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
-	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
-	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
-	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
-	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
-	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
-	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
-};
-
-static void saa7146_set_winsize(struct saa7146 *saa)
-{
-	u32 format;
-	int offset, yacl, ysci;
-	saa->win.color_fmt = format =
-	    (saa->win.depth == 15) ? palette2fmt[VIDEO_PALETTE_RGB555] :
-	    palette2fmt[bpp2fmt[(saa->win.bpp - 1) & 3]];
-	offset = saa->win.x * saa->win.bpp + saa->win.y * saa->win.bpl;
-	saawrite(saa->win.vidadr + offset, SAA7146_BASE_EVEN1);
-	saawrite(saa->win.vidadr + offset + saa->win.bpl, SAA7146_BASE_ODD1);
-	saawrite(saa->win.bpl * 2, SAA7146_PITCH1);
-	saawrite(saa->win.vidadr + saa->win.bpl * saa->win.sheight,
-		 SAA7146_PROT_ADDR1);
-	saawrite(0, SAA7146_PAGE1);
-	saawrite(format | 0x60, SAA7146_CLIP_FORMAT_CTRL);
-	offset = (704 / (saa->win.width - 1)) & 0x3f;
-	saawrite(h_prescale[offset], SAA7146_HPS_H_PRESCALE);
-	offset = (720896 / saa->win.width) / (offset + 1);
-	saawrite((offset << 12) | 0x0c, SAA7146_HPS_H_SCALE);
-	if (CurrentMode == VIDEO_MODE_NTSC) {
-		yacl = /*(480 / saa->win.height - 1) & 0x3f */ 0;
-		ysci = 1024 - (saa->win.height * 1024 / 480);
-	} else {
-		yacl = /*(576 / saa->win.height - 1) & 0x3f */ 0;
-		ysci = 1024 - (saa->win.height * 1024 / 576);
-	}
-	saawrite((1 << 31) | (ysci << 21) | (yacl << 15), SAA7146_HPS_V_SCALE);
-	saawrite(v_gain[yacl], SAA7146_HPS_V_GAIN);
-	saawrite(((SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_HPS_V |
-		SAA7146_MC2_UPLD_HPS_H) << 16) | (SAA7146_MC2_UPLD_DMA1 |
-		SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_HPS_H), SAA7146_MC2);
-}
-
-/* clip_draw_rectangle(cm,x,y,w,h) -- handle clipping an area
- * bitmap is fixed width, 128 bytes (1024 pixels represented)
- * arranged most-sigificant-bit-left in 32-bit words
- * based on saa7146 clipping hardware, it swaps bytes if LE
- * much of this makes up for egcs brain damage -- so if you
- * are wondering "why did he do this?" it is because the C
- * was adjusted to generate the optimal asm output without
- * writing non-portable __asm__ directives.
- */
-
-static void clip_draw_rectangle(u32 *clipmap, int x, int y, int w, int h)
-{
-	register int startword, endword;
-	register u32 bitsleft, bitsright;
-	u32 *temp;
-	if (x < 0) {
-		w += x;
-		x = 0;
-	}
-	if (y < 0) {
-		h += y;
-		y = 0;
-	}
-	if (w <= 0 || h <= 0 || x > 1023 || y > 639)
-		return;		/* throw away bad clips */
-	if (x + w > 1024)
-		w = 1024 - x;
-	if (y + h > 640)
-		h = 640 - y;
-	startword = (x >> 5);
-	endword = ((x + w) >> 5);
-	bitsleft = (0xffffffff >> (x & 31));
-	bitsright = (0xffffffff << (~((x + w) - (endword << 5))));
-	temp = &clipmap[(y << 5) + startword];
-	w = endword - startword;
-	if (!w) {
-		bitsleft |= bitsright;
-		for (y = 0; y < h; y++) {
-			*temp |= bitsleft;
-			temp += 32;
-		}
-	} else {
-		for (y = 0; y < h; y++) {
-			*temp++ |= bitsleft;
-			for (x = 1; x < w; x++)
-				*temp++ = 0xffffffff;
-			*temp |= bitsright;
-			temp += (32 - w);
-		}
-	}
-}
-
-static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr)
-{
-	int i, width, height;
-	u32 *clipmap;
-
-	clipmap = saa->dmavid2;
-	if ((width = saa->win.width) > 1023)
-		width = 1023;	/* sanity check */
-	if ((height = saa->win.height) > 640)
-		height = 639;	/* sanity check */
-	if (ncr > 0) {		/* rectangles pased */
-		/* convert rectangular clips to a bitmap */
-		memset(clipmap, 0, VIDEO_CLIPMAP_SIZE);	/* clear map */
-		for (i = 0; i < ncr; i++)
-			clip_draw_rectangle(clipmap, cr[i].x, cr[i].y,
-				cr[i].width, cr[i].height);
-	}
-	/* clip against viewing window AND screen
-	   so we do not have to rely on the user program
-	 */
-	clip_draw_rectangle(clipmap, (saa->win.x + width > saa->win.swidth) ?
-		(saa->win.swidth - saa->win.x) : width, 0, 1024, 768);
-	clip_draw_rectangle(clipmap, 0,
-		(saa->win.y + height > saa->win.sheight) ?
-		(saa->win.sheight - saa->win.y) : height, 1024, 768);
-	if (saa->win.x < 0)
-		clip_draw_rectangle(clipmap, 0, 0, -saa->win.x, 768);
-	if (saa->win.y < 0)
-		clip_draw_rectangle(clipmap, 0, 0, 1024, -saa->win.y);
-}
-
-static long saa_ioctl(struct file *file,
-		     unsigned int cmd, unsigned long argl)
-{
-	struct saa7146 *saa = file->private_data;
-	void __user *arg = (void __user *)argl;
-
-	switch (cmd) {
-	case VIDIOCGCAP:
-		{
-			struct video_capability b;
-			strcpy(b.name, saa->video_dev.name);
-			b.type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY |
-				VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
-				VID_TYPE_SCALES;
-			b.channels = 1;
-			b.audios = 1;
-			b.maxwidth = 768;
-			b.maxheight = 576;
-			b.minwidth = 32;
-			b.minheight = 32;
-			if (copy_to_user(arg, &b, sizeof(b)))
-				return -EFAULT;
-			return 0;
-		}
-	case VIDIOCGPICT:
-		{
-			struct video_picture p = saa->picture;
-			if (saa->win.depth == 8)
-				p.palette = VIDEO_PALETTE_HI240;
-			if (saa->win.depth == 15)
-				p.palette = VIDEO_PALETTE_RGB555;
-			if (saa->win.depth == 16)
-				p.palette = VIDEO_PALETTE_RGB565;
-			if (saa->win.depth == 24)
-				p.palette = VIDEO_PALETTE_RGB24;
-			if (saa->win.depth == 32)
-				p.palette = VIDEO_PALETTE_RGB32;
-			if (copy_to_user(arg, &p, sizeof(p)))
-				return -EFAULT;
-			return 0;
-		}
-	case VIDIOCSPICT:
-		{
-			struct video_picture p;
-			u32 format;
-			if (copy_from_user(&p, arg, sizeof(p)))
-				return -EFAULT;
-			if (p.palette < ARRAY_SIZE(palette2fmt)) {
-				format = palette2fmt[p.palette];
-				saa->win.color_fmt = format;
-				saawrite(format | 0x60,
-					SAA7146_CLIP_FORMAT_CTRL);
-			}
-			saawrite(((p.brightness & 0xff00) << 16) |
-				((p.contrast & 0xfe00) << 7) |
-				((p.colour & 0xfe00) >> 9), SAA7146_BCS_CTRL);
-			saa->picture = p;
-			/* upload changed registers */
-			saawrite(((SAA7146_MC2_UPLD_HPS_H |
-				SAA7146_MC2_UPLD_HPS_V) << 16) |
-				SAA7146_MC2_UPLD_HPS_H |
-				SAA7146_MC2_UPLD_HPS_V, SAA7146_MC2);
-			return 0;
-		}
-	case VIDIOCSWIN:
-		{
-			struct video_window vw;
-			struct video_clip *vcp = NULL;
-
-			if (copy_from_user(&vw, arg, sizeof(vw)))
-				return -EFAULT;
-
-			/* stop capture */
-			if (vw.flags || vw.width < 16 || vw.height < 16) {
-				saawrite((SAA7146_MC1_TR_E_1 << 16),
-					SAA7146_MC1);
-				return -EINVAL;
-			}
-			/* 32-bit align start and adjust width */
-			if (saa->win.bpp < 4) {
-				int i = vw.x;
-				vw.x = (vw.x + 3) & ~3;
-				i = vw.x - i;
-				vw.width -= i;
-			}
-			saa->win.x = vw.x;
-			saa->win.y = vw.y;
-			saa->win.width = vw.width;
-			if (saa->win.width > 768)
-				saa->win.width = 768;
-			saa->win.height = vw.height;
-			if (CurrentMode == VIDEO_MODE_NTSC) {
-				if (saa->win.height > 480)
-					saa->win.height = 480;
-			} else {
-				if (saa->win.height > 576)
-					saa->win.height = 576;
-			}
-
-			/* stop capture */
-			saawrite((SAA7146_MC1_TR_E_1 << 16), SAA7146_MC1);
-			saa7146_set_winsize(saa);
-
-			/*
-			 *    Do any clips.
-			 */
-			if (vw.clipcount < 0) {
-				if (copy_from_user(saa->dmavid2, vw.clips,
-						VIDEO_CLIPMAP_SIZE))
-					return -EFAULT;
-			} else if (vw.clipcount > 16384) {
-				return -EINVAL;
-			} else if (vw.clipcount > 0) {
-				vcp = vmalloc(sizeof(struct video_clip) *
-					vw.clipcount);
-				if (vcp == NULL)
-					return -ENOMEM;
-				if (copy_from_user(vcp, vw.clips,
-						sizeof(struct video_clip) *
-						vw.clipcount)) {
-					vfree(vcp);
-					return -EFAULT;
-				}
-			} else	/* nothing clipped */
-				memset(saa->dmavid2, 0, VIDEO_CLIPMAP_SIZE);
-
-			make_clip_tab(saa, vcp, vw.clipcount);
-			if (vw.clipcount > 0)
-				vfree(vcp);
-
-			/* start capture & clip dma if we have an address */
-			if ((saa->cap & 3) && saa->win.vidadr != 0)
-				saawrite(((SAA7146_MC1_TR_E_1 |
-					SAA7146_MC1_TR_E_2) << 16) | 0xffff,
-					SAA7146_MC1);
-			return 0;
-		}
-	case VIDIOCGWIN:
-		{
-			struct video_window vw;
-			vw.x = saa->win.x;
-			vw.y = saa->win.y;
-			vw.width = saa->win.width;
-			vw.height = saa->win.height;
-			vw.chromakey = 0;
-			vw.flags = 0;
-			if (copy_to_user(arg, &vw, sizeof(vw)))
-				return -EFAULT;
-			return 0;
-		}
-	case VIDIOCCAPTURE:
-		{
-			int v;
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			if (v == 0) {
-				saa->cap &= ~1;
-				saawrite((SAA7146_MC1_TR_E_1 << 16),
-					SAA7146_MC1);
-			} else {
-				if (saa->win.vidadr == 0 || saa->win.width == 0
-						|| saa->win.height == 0)
-					return -EINVAL;
-				saa->cap |= 1;
-				saawrite((SAA7146_MC1_TR_E_1 << 16) | 0xffff,
-					SAA7146_MC1);
-			}
-			return 0;
-		}
-	case VIDIOCGFBUF:
-		{
-			struct video_buffer v;
-			v.base = (void *)saa->win.vidadr;
-			v.height = saa->win.sheight;
-			v.width = saa->win.swidth;
-			v.depth = saa->win.depth;
-			v.bytesperline = saa->win.bpl;
-			if (copy_to_user(arg, &v, sizeof(v)))
-				return -EFAULT;
-			return 0;
-
-		}
-	case VIDIOCSFBUF:
-		{
-			struct video_buffer v;
-			if (!capable(CAP_SYS_ADMIN))
-				return -EPERM;
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			if (v.depth != 8 && v.depth != 15 && v.depth != 16 &&
-			    v.depth != 24 && v.depth != 32 && v.width > 16 &&
-			    v.height > 16 && v.bytesperline > 16)
-				return -EINVAL;
-			if (v.base)
-				saa->win.vidadr = (unsigned long)v.base;
-			saa->win.sheight = v.height;
-			saa->win.swidth = v.width;
-			saa->win.bpp = ((v.depth + 7) & 0x38) / 8;
-			saa->win.depth = v.depth;
-			saa->win.bpl = v.bytesperline;
-
-			DEBUG(printk("Display at %p is %d by %d, bytedepth %d, "
-					"bpl %d\n", v.base, v.width, v.height,
-					saa->win.bpp, saa->win.bpl));
-			saa7146_set_winsize(saa);
-			return 0;
-		}
-	case VIDIOCKEY:
-		{
-			/* Will be handled higher up .. */
-			return 0;
-		}
-
-	case VIDIOCGAUDIO:
-		{
-			struct video_audio v;
-			v = saa->audio_dev;
-			v.flags &= ~(VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
-			v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
-			strcpy(v.name, "MPEG");
-			v.mode = VIDEO_SOUND_STEREO;
-			if (copy_to_user(arg, &v, sizeof(v)))
-				return -EFAULT;
-			return 0;
-		}
-	case VIDIOCSAUDIO:
-		{
-			struct video_audio v;
-			int i;
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			i = (~(v.volume >> 8)) & 0xff;
-			if (!HaveCS4341) {
-				if (v.flags & VIDEO_AUDIO_MUTE)
-					debiwrite(saa, debNormal,
-						IBM_MP2_FRNT_ATTEN, 0xffff, 2);
-				if (!(v.flags & VIDEO_AUDIO_MUTE))
-					debiwrite(saa, debNormal,
-						IBM_MP2_FRNT_ATTEN, 0x0000, 2);
-				if (v.flags & VIDEO_AUDIO_VOLUME)
-					debiwrite(saa, debNormal,
-						IBM_MP2_FRNT_ATTEN,
-						(i << 8) | i, 2);
-			} else {
-				if (v.flags & VIDEO_AUDIO_MUTE)
-					cs4341_setlevel(saa, 0xff, 0xff);
-				if (!(v.flags & VIDEO_AUDIO_MUTE))
-					cs4341_setlevel(saa, 0, 0);
-				if (v.flags & VIDEO_AUDIO_VOLUME)
-					cs4341_setlevel(saa, i, i);
-			}
-			saa->audio_dev = v;
-			return 0;
-		}
-
-	case VIDIOCGUNIT:
-		{
-			struct video_unit vu;
-			vu.video = saa->video_dev.minor;
-			vu.vbi = VIDEO_NO_UNIT;
-			vu.radio = VIDEO_NO_UNIT;
-			vu.audio = VIDEO_NO_UNIT;
-			vu.teletext = VIDEO_NO_UNIT;
-			if (copy_to_user(arg, &vu, sizeof(vu)))
-				return -EFAULT;
-			return 0;
-		}
-	case VIDIOCSPLAYMODE:
-		{
-			struct video_play_mode pmode;
-			if (copy_from_user((void *)&pmode, arg,
-					sizeof(struct video_play_mode)))
-				return -EFAULT;
-			switch (pmode.mode) {
-			case VID_PLAY_VID_OUT_MODE:
-				if (pmode.p1 != VIDEO_MODE_NTSC &&
-						pmode.p1 != VIDEO_MODE_PAL)
-					return -EINVAL;
-				set_out_format(saa, pmode.p1);
-				return 0;
-			case VID_PLAY_GENLOCK:
-				debiwrite(saa, debNormal, XILINX_CTL0,
-					pmode.p1 ? 0x8000 : 0x8080, 2);
-				if (NewCard)
-					set_genlock_offset(saa, pmode.p2);
-				return 0;
-			case VID_PLAY_NORMAL:
-				debiwrite(saa, debNormal,
-					IBM_MP2_CHIP_CONTROL, ChipControl, 2);
-				ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
-				saa->playmode = pmode.mode;
-				return 0;
-			case VID_PLAY_PAUSE:
-				/* IBM removed the PAUSE command */
-				/* they say use SINGLE_FRAME now */
-			case VID_PLAY_SINGLE_FRAME:
-				ibm_send_command(saa, IBM_MP2_SINGLE_FRAME,0,0);
-				if (saa->playmode == pmode.mode) {
-					debiwrite(saa, debNormal,
-						IBM_MP2_CHIP_CONTROL,
-						ChipControl, 2);
-				}
-				saa->playmode = pmode.mode;
-				return 0;
-			case VID_PLAY_FAST_FORWARD:
-				ibm_send_command(saa, IBM_MP2_FAST_FORWARD,0,0);
-				saa->playmode = pmode.mode;
-				return 0;
-			case VID_PLAY_SLOW_MOTION:
-				ibm_send_command(saa, IBM_MP2_SLOW_MOTION,
-					pmode.p1, 0);
-				saa->playmode = pmode.mode;
-				return 0;
-			case VID_PLAY_IMMEDIATE_NORMAL:
-				/* ensure transfers resume */
-				debiwrite(saa, debNormal,
-					IBM_MP2_CHIP_CONTROL, ChipControl, 2);
-				ibm_send_command(saa, IBM_MP2_IMED_NORM_PLAY,
-					0, 0);
-				saa->playmode = VID_PLAY_NORMAL;
-				return 0;
-			case VID_PLAY_SWITCH_CHANNELS:
-				saa->audhead = saa->audtail = 0;
-				saa->vidhead = saa->vidtail = 0;
-				ibm_send_command(saa, IBM_MP2_FREEZE_FRAME,0,1);
-				ibm_send_command(saa, IBM_MP2_RESET_AUD_RATE,
-					0, 1);
-				debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
-					0, 2);
-				ibm_send_command(saa, IBM_MP2_CHANNEL_SWITCH,
-					0, 1);
-				debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
-					ChipControl, 2);
-				ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
-				saa->playmode = VID_PLAY_NORMAL;
-				return 0;
-			case VID_PLAY_FREEZE_FRAME:
-				ibm_send_command(saa, IBM_MP2_FREEZE_FRAME,0,0);
-				saa->playmode = pmode.mode;
-				return 0;
-			case VID_PLAY_STILL_MODE:
-				ibm_send_command(saa, IBM_MP2_SET_STILL_MODE,
-					0, 0);
-				saa->playmode = pmode.mode;
-				return 0;
-			case VID_PLAY_MASTER_MODE:
-				if (pmode.p1 == VID_PLAY_MASTER_NONE)
-					saa->boardcfg[1] = 0x13;
-				else if (pmode.p1 == VID_PLAY_MASTER_VIDEO)
-					saa->boardcfg[1] = 0x23;
-				else if (pmode.p1 == VID_PLAY_MASTER_AUDIO)
-					saa->boardcfg[1] = 0x43;
-				else
-					return -EINVAL;
-				debiwrite(saa, debNormal,
-					  IBM_MP2_CHIP_CONTROL, ChipControl, 2);
-				return 0;
-			case VID_PLAY_ACTIVE_SCANLINES:
-				if (CurrentMode == VIDEO_MODE_PAL) {
-					if (pmode.p1 < 1 || pmode.p2 > 625)
-						return -EINVAL;
-					saa->boardcfg[5] = pmode.p1;
-					saa->boardcfg[55] = (pmode.p1 +
-						(pmode.p2 / 2) - 1) & 0xff;
-				} else {
-					if (pmode.p1 < 4 || pmode.p2 > 525)
-						return -EINVAL;
-					saa->boardcfg[4] = pmode.p1;
-					saa->boardcfg[54] = (pmode.p1 +
-						(pmode.p2 / 2) - 4) & 0xff;
-				}
-				set_out_format(saa, CurrentMode);
-			case VID_PLAY_RESET:
-				return do_ibm_reset(saa);
-			case VID_PLAY_END_MARK:
-				if (saa->endmarktail < saa->endmarkhead) {
-					if (saa->endmarkhead -
-							saa->endmarktail < 2)
-						return -ENOSPC;
-				} else if (saa->endmarkhead <=saa->endmarktail){
-					if (saa->endmarktail - saa->endmarkhead
-							> (MAX_MARKS - 2))
-						return -ENOSPC;
-				} else
-					return -ENOSPC;
-				saa->endmark[saa->endmarktail] = saa->audtail;
-				saa->endmarktail++;
-				if (saa->endmarktail >= MAX_MARKS)
-					saa->endmarktail = 0;
-			}
-			return -EINVAL;
-		}
-	case VIDIOCSWRITEMODE:
-		{
-			int mode;
-			if (copy_from_user((void *)&mode, arg, sizeof(int)))
-				return -EFAULT;
-			if (mode == VID_WRITE_MPEG_AUD ||
-					mode == VID_WRITE_MPEG_VID ||
-					mode == VID_WRITE_CC ||
-					mode == VID_WRITE_TTX ||
-					mode == VID_WRITE_OSD) {
-				saa->writemode = mode;
-				return 0;
-			}
-			return -EINVAL;
-		}
-	case VIDIOCSMICROCODE:
-		{
-			struct video_code ucode;
-			__u8 *udata;
-			int i;
-			if (copy_from_user(&ucode, arg, sizeof(ucode)))
-				return -EFAULT;
-			if (ucode.datasize > 65536 || ucode.datasize < 1024 ||
-					strncmp(ucode.loadwhat, "dec", 3))
-				return -EINVAL;
-			if ((udata = vmalloc(ucode.datasize)) == NULL)
-				return -ENOMEM;
-			if (copy_from_user(udata, ucode.data, ucode.datasize)) {
-				vfree(udata);
-				return -EFAULT;
-			}
-			ucode.data = udata;
-			if (!strncmp(ucode.loadwhat, "decoder.aud", 11) ||
-				!strncmp(ucode.loadwhat, "decoder.vid", 11))
-				i = initialize_ibmmpeg2(&ucode);
-			else
-				i = initialize_fpga(&ucode);
-			vfree(udata);
-			if (i)
-				return -EINVAL;
-			return 0;
-
-		}
-	case VIDIOCGCHAN:	/* this makes xawtv happy */
-		{
-			struct video_channel v;
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			v.flags = VIDEO_VC_AUDIO;
-			v.tuners = 0;
-			v.type = VID_TYPE_MPEG_DECODER;
-			v.norm = CurrentMode;
-			strcpy(v.name, "MPEG2");
-			if (copy_to_user(arg, &v, sizeof(v)))
-				return -EFAULT;
-			return 0;
-		}
-	case VIDIOCSCHAN:	/* this makes xawtv happy */
-		{
-			struct video_channel v;
-			if (copy_from_user(&v, arg, sizeof(v)))
-				return -EFAULT;
-			/* do nothing */
-			return 0;
-		}
-	default:
-		return -ENOIOCTLCMD;
-	}
-	return 0;
-}
-
-static int saa_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct saa7146 *saa = file->private_data;
-	printk(KERN_DEBUG "stradis%d: saa_mmap called\n", saa->nr);
-	return -EINVAL;
-}
-
-static ssize_t saa_read(struct file *file, char __user * buf,
-	size_t count, loff_t * ppos)
-{
-	return -EINVAL;
-}
-
-static ssize_t saa_write(struct file *file, const char __user * buf,
-	size_t count, loff_t * ppos)
-{
-	struct saa7146 *saa = file->private_data;
-	unsigned long todo = count;
-	int blocksize, split;
-	unsigned long flags;
-
-	while (todo > 0) {
-		if (saa->writemode == VID_WRITE_MPEG_AUD) {
-			spin_lock_irqsave(&saa->lock, flags);
-			if (saa->audhead <= saa->audtail)
-				blocksize = 65536 -
-					(saa->audtail - saa->audhead);
-			else
-				blocksize = saa->audhead - saa->audtail;
-			spin_unlock_irqrestore(&saa->lock, flags);
-			if (blocksize < 16384) {
-				saawrite(SAA7146_PSR_DEBI_S |
-					SAA7146_PSR_PIN1, SAA7146_IER);
-				saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
-				/* wait for buffer space to open */
-				interruptible_sleep_on(&saa->audq);
-			}
-			spin_lock_irqsave(&saa->lock, flags);
-			if (saa->audhead <= saa->audtail) {
-				blocksize = 65536 -
-					(saa->audtail - saa->audhead);
-				split = 65536 - saa->audtail;
-			} else {
-				blocksize = saa->audhead - saa->audtail;
-				split = 65536;
-			}
-			spin_unlock_irqrestore(&saa->lock, flags);
-			blocksize--;
-			if (blocksize > todo)
-				blocksize = todo;
-			/* double check that we really have space */
-			if (!blocksize)
-				return -ENOSPC;
-			if (split < blocksize) {
-				if (copy_from_user(saa->audbuf +
-						saa->audtail, buf, split))
-					return -EFAULT;
-				buf += split;
-				todo -= split;
-				blocksize -= split;
-				saa->audtail = 0;
-			}
-			if (copy_from_user(saa->audbuf + saa->audtail, buf,
-					blocksize))
-				return -EFAULT;
-			saa->audtail += blocksize;
-			todo -= blocksize;
-			buf += blocksize;
-			saa->audtail &= 0xffff;
-		} else if (saa->writemode == VID_WRITE_MPEG_VID) {
-			spin_lock_irqsave(&saa->lock, flags);
-			if (saa->vidhead <= saa->vidtail)
-				blocksize = 524288 -
-					(saa->vidtail - saa->vidhead);
-			else
-				blocksize = saa->vidhead - saa->vidtail;
-			spin_unlock_irqrestore(&saa->lock, flags);
-			if (blocksize < 65536) {
-				saawrite(SAA7146_PSR_DEBI_S |
-					SAA7146_PSR_PIN1, SAA7146_IER);
-				saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
-				/* wait for buffer space to open */
-				interruptible_sleep_on(&saa->vidq);
-			}
-			spin_lock_irqsave(&saa->lock, flags);
-			if (saa->vidhead <= saa->vidtail) {
-				blocksize = 524288 -
-					(saa->vidtail - saa->vidhead);
-				split = 524288 - saa->vidtail;
-			} else {
-				blocksize = saa->vidhead - saa->vidtail;
-				split = 524288;
-			}
-			spin_unlock_irqrestore(&saa->lock, flags);
-			blocksize--;
-			if (blocksize > todo)
-				blocksize = todo;
-			/* double check that we really have space */
-			if (!blocksize)
-				return -ENOSPC;
-			if (split < blocksize) {
-				if (copy_from_user(saa->vidbuf +
-						saa->vidtail, buf, split))
-					return -EFAULT;
-				buf += split;
-				todo -= split;
-				blocksize -= split;
-				saa->vidtail = 0;
-			}
-			if (copy_from_user(saa->vidbuf + saa->vidtail, buf,
-					blocksize))
-				return -EFAULT;
-			saa->vidtail += blocksize;
-			todo -= blocksize;
-			buf += blocksize;
-			saa->vidtail &= 0x7ffff;
-		} else if (saa->writemode == VID_WRITE_OSD) {
-			if (count > 131072)
-				return -ENOSPC;
-			if (copy_from_user(saa->osdbuf, buf, count))
-				return -EFAULT;
-			buf += count;
-			saa->osdhead = 0;
-			saa->osdtail = count;
-			debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR, 0, 2);
-			debiwrite(saa, debNormal, IBM_MP2_OSD_LINK_ADDR, 0, 2);
-			debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00d, 2);
-			debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
-				debiread(saa, debNormal,
-					IBM_MP2_DISP_MODE, 2) | 1, 2);
-			/* trigger osd data transfer */
-			saawrite(SAA7146_PSR_DEBI_S |
-				 SAA7146_PSR_PIN1, SAA7146_IER);
-			saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
-		}
-	}
-	return count;
-}
-
-static int saa_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct saa7146 *saa = container_of(vdev, struct saa7146, video_dev);
-
-	lock_kernel();
-	file->private_data = saa;
-
-	saa->user++;
-	if (saa->user > 1) {
-		unlock_kernel();
-		return 0;	/* device open already, don't reset */
-	}
-	saa->writemode = VID_WRITE_MPEG_VID;	/* default to video */
-	unlock_kernel();
-	return 0;
-}
-
-static int saa_release(struct file *file)
-{
-	struct saa7146 *saa = file->private_data;
-	saa->user--;
-
-	if (saa->user > 0)	/* still someone using device */
-		return 0;
-	saawrite(0x007f0000, SAA7146_MC1);	/* stop all overlay dma */
-	return 0;
-}
-
-static const struct v4l2_file_operations saa_fops = {
-	.owner = THIS_MODULE,
-	.open = saa_open,
-	.release = saa_release,
-	.ioctl = saa_ioctl,
-	.read = saa_read,
-	.write = saa_write,
-	.mmap = saa_mmap,
-};
-
-/* template for video_device-structure */
-static struct video_device saa_template = {
-	.name = "SAA7146A",
-	.fops = &saa_fops,
-	.release = video_device_release_empty,
-};
-
-static int __devinit configure_saa7146(struct pci_dev *pdev, int num)
-{
-	int retval;
-	struct saa7146 *saa = pci_get_drvdata(pdev);
-
-	saa->endmarkhead = saa->endmarktail = 0;
-	saa->win.x = saa->win.y = 0;
-	saa->win.width = saa->win.cropwidth = 720;
-	saa->win.height = saa->win.cropheight = 480;
-	saa->win.cropx = saa->win.cropy = 0;
-	saa->win.bpp = 2;
-	saa->win.depth = 16;
-	saa->win.color_fmt = palette2fmt[VIDEO_PALETTE_RGB565];
-	saa->win.bpl = 1024 * saa->win.bpp;
-	saa->win.swidth = 1024;
-	saa->win.sheight = 768;
-	saa->picture.brightness = 32768;
-	saa->picture.contrast = 38768;
-	saa->picture.colour = 32768;
-	saa->cap = 0;
-	saa->nr = num;
-	saa->playmode = VID_PLAY_NORMAL;
-	memset(saa->boardcfg, 0, 64);	/* clear board config area */
-	saa->saa7146_mem = NULL;
-	saa->dmavid1 = saa->dmavid2 = saa->dmavid3 = saa->dmaa1in =
-	    saa->dmaa1out = saa->dmaa2in = saa->dmaa2out =
-	    saa->pagevid1 = saa->pagevid2 = saa->pagevid3 = saa->pagea1in =
-	    saa->pagea1out = saa->pagea2in = saa->pagea2out =
-	    saa->pagedebi = saa->dmaRPS1 = saa->dmaRPS2 = saa->pageRPS1 =
-	    saa->pageRPS2 = NULL;
-	saa->audbuf = saa->vidbuf = saa->osdbuf = saa->dmadebi = NULL;
-	saa->audhead = saa->vidtail = 0;
-
-	init_waitqueue_head(&saa->i2cq);
-	init_waitqueue_head(&saa->audq);
-	init_waitqueue_head(&saa->debiq);
-	init_waitqueue_head(&saa->vidq);
-	spin_lock_init(&saa->lock);
-
-	retval = pci_enable_device(pdev);
-	if (retval) {
-		dev_err(&pdev->dev, "%d: pci_enable_device failed!\n", num);
-		goto err;
-	}
-
-	saa->id = pdev->device;
-	saa->irq = pdev->irq;
-	saa->saa7146_adr = pci_resource_start(pdev, 0);
-	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &saa->revision);
-
-	saa->saa7146_mem = ioremap(saa->saa7146_adr, 0x200);
-	if (saa->saa7146_mem == NULL) {
-		dev_err(&pdev->dev, "%d: ioremap failed!\n", num);
-		retval = -EIO;
-		goto err;
-	}
-
-	memcpy(&saa->video_dev, &saa_template, sizeof(saa_template));
-	saawrite(0, SAA7146_IER);	/* turn off all interrupts */
-
-	retval = request_irq(saa->irq, saa7146_irq, IRQF_SHARED | IRQF_DISABLED,
-		"stradis", saa);
-	if (retval == -EINVAL)
-		dev_err(&pdev->dev, "%d: Bad irq number or handler\n", num);
-	else if (retval == -EBUSY)
-		dev_err(&pdev->dev, "%d: IRQ %ld busy, change your PnP config "
-			"in BIOS\n", num, saa->irq);
-	if (retval < 0)
-		goto errio;
-
-	pci_set_master(pdev);
-	retval = video_register_device(&saa->video_dev, VFL_TYPE_GRABBER,
-		video_nr);
-	if (retval < 0) {
-		dev_err(&pdev->dev, "%d: error in registering video device!\n",
-			num);
-		goto errio;
-	}
-
-	return 0;
-errio:
-	iounmap(saa->saa7146_mem);
-err:
-	return retval;
-}
-
-static int __devinit init_saa7146(struct pci_dev *pdev)
-{
-	struct saa7146 *saa = pci_get_drvdata(pdev);
-
-	saa->user = 0;
-	/* reset the saa7146 */
-	saawrite(0xffff0000, SAA7146_MC1);
-	mdelay(5);
-	/* enable debi and i2c transfers and pins */
-	saawrite(((SAA7146_MC1_EDP | SAA7146_MC1_EI2C |
-		   SAA7146_MC1_TR_E_DEBI) << 16) | 0xffff, SAA7146_MC1);
-	/* ensure proper state of chip */
-	saawrite(0x00000000, SAA7146_PAGE1);
-	saawrite(0x00f302c0, SAA7146_NUM_LINE_BYTE1);
-	saawrite(0x00000000, SAA7146_PAGE2);
-	saawrite(0x01400080, SAA7146_NUM_LINE_BYTE2);
-	saawrite(0x00000000, SAA7146_DD1_INIT);
-	saawrite(0x00000000, SAA7146_DD1_STREAM_B);
-	saawrite(0x00000000, SAA7146_DD1_STREAM_A);
-	saawrite(0x00000000, SAA7146_BRS_CTRL);
-	saawrite(0x80400040, SAA7146_BCS_CTRL);
-	saawrite(0x0000e000 /*| (1<<29) */ , SAA7146_HPS_CTRL);
-	saawrite(0x00000060, SAA7146_CLIP_FORMAT_CTRL);
-	saawrite(0x00000000, SAA7146_ACON1);
-	saawrite(0x00000000, SAA7146_ACON2);
-	saawrite(0x00000600, SAA7146_I2C_STATUS);
-	saawrite(((SAA7146_MC2_UPLD_D1_B | SAA7146_MC2_UPLD_D1_A |
-		SAA7146_MC2_UPLD_BRS | SAA7146_MC2_UPLD_HPS_H |
-		SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_DMA2 |
-		SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_I2C) << 16) | 0xffff,
-		SAA7146_MC2);
-	/* setup arbitration control registers */
-	saawrite(0x1412121a, SAA7146_PCI_BT_V1);
-
-	/* allocate 32k dma buffer + 4k for page table */
-	if ((saa->dmadebi = kmalloc(32768 + 4096, GFP_KERNEL)) == NULL) {
-		dev_err(&pdev->dev, "%d: debi kmalloc failed\n", saa->nr);
-		goto err;
-	}
-#if 0
-	saa->pagedebi = saa->dmadebi + 32768;	/* top 4k is for mmu */
-	saawrite(virt_to_bus(saa->pagedebi) /*|0x800 */ , SAA7146_DEBI_PAGE);
-	for (i = 0; i < 12; i++)	/* setup mmu page table */
-		saa->pagedebi[i] = virt_to_bus((saa->dmadebi + i * 4096));
-#endif
-	saa->audhead = saa->vidhead = saa->osdhead = 0;
-	saa->audtail = saa->vidtail = saa->osdtail = 0;
-	if (saa->vidbuf == NULL && (saa->vidbuf = vmalloc(524288)) == NULL) {
-		dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
-		goto err;
-	}
-	if (saa->audbuf == NULL && (saa->audbuf = vmalloc(65536)) == NULL) {
-		dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
-		goto errfree;
-	}
-	if (saa->osdbuf == NULL && (saa->osdbuf = vmalloc(131072)) == NULL) {
-		dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
-		goto errfree;
-	}
-	/* allocate 81920 byte buffer for clipping */
-	if ((saa->dmavid2 = kzalloc(VIDEO_CLIPMAP_SIZE, GFP_KERNEL)) == NULL) {
-		dev_err(&pdev->dev, "%d: clip kmalloc failed\n", saa->nr);
-		goto errfree;
-	}
-	/* setup clipping registers */
-	saawrite(virt_to_bus(saa->dmavid2), SAA7146_BASE_EVEN2);
-	saawrite(virt_to_bus(saa->dmavid2) + 128, SAA7146_BASE_ODD2);
-	saawrite(virt_to_bus(saa->dmavid2) + VIDEO_CLIPMAP_SIZE,
-		 SAA7146_PROT_ADDR2);
-	saawrite(256, SAA7146_PITCH2);
-	saawrite(4, SAA7146_PAGE2);	/* dma direction: read, no byteswap */
-	saawrite(((SAA7146_MC2_UPLD_DMA2) << 16) | SAA7146_MC2_UPLD_DMA2,
-		 SAA7146_MC2);
-	I2CBusScan(saa);
-
-	return 0;
-errfree:
-	vfree(saa->osdbuf);
-	vfree(saa->audbuf);
-	vfree(saa->vidbuf);
-	saa->audbuf = saa->osdbuf = saa->vidbuf = NULL;
-err:
-	return -ENOMEM;
-}
-
-static void stradis_release_saa(struct pci_dev *pdev)
-{
-	u8 command;
-	struct saa7146 *saa = pci_get_drvdata(pdev);
-
-	/* turn off all capturing, DMA and IRQs */
-	saawrite(0xffff0000, SAA7146_MC1);	/* reset chip */
-	saawrite(0, SAA7146_MC2);
-	saawrite(0, SAA7146_IER);
-	saawrite(0xffffffffUL, SAA7146_ISR);
-
-	/* disable PCI bus-mastering */
-	pci_read_config_byte(pdev, PCI_COMMAND, &command);
-	command &= ~PCI_COMMAND_MASTER;
-	pci_write_config_byte(pdev, PCI_COMMAND, command);
-
-	/* unmap and free memory */
-	saa->audhead = saa->audtail = saa->osdhead = 0;
-	saa->vidhead = saa->vidtail = saa->osdtail = 0;
-	vfree(saa->vidbuf);
-	vfree(saa->audbuf);
-	vfree(saa->osdbuf);
-	kfree(saa->dmavid2);
-	saa->audbuf = saa->vidbuf = saa->osdbuf = NULL;
-	saa->dmavid2 = NULL;
-	kfree(saa->dmadebi);
-	kfree(saa->dmavid1);
-	kfree(saa->dmavid3);
-	kfree(saa->dmaa1in);
-	kfree(saa->dmaa1out);
-	kfree(saa->dmaa2in);
-	kfree(saa->dmaa2out);
-	kfree(saa->dmaRPS1);
-	kfree(saa->dmaRPS2);
-	free_irq(saa->irq, saa);
-	if (saa->saa7146_mem)
-		iounmap(saa->saa7146_mem);
-	if (video_is_registered(&saa->video_dev))
-		video_unregister_device(&saa->video_dev);
-}
-
-static int __devinit stradis_probe(struct pci_dev *pdev,
-	const struct pci_device_id *ent)
-{
-	int retval = -EINVAL;
-
-	if (saa_num >= SAA7146_MAX)
-		goto err;
-
-	if (!pdev->subsystem_vendor)
-		dev_info(&pdev->dev, "%d: rev1 decoder\n", saa_num);
-	else
-		dev_info(&pdev->dev, "%d: SDM2xx found\n", saa_num);
-
-	pci_set_drvdata(pdev, &saa7146s[saa_num]);
-
-	retval = configure_saa7146(pdev, saa_num);
-	if (retval) {
-		dev_err(&pdev->dev, "%d: error in configuring\n", saa_num);
-		goto err;
-	}
-
-	if (init_saa7146(pdev) < 0) {
-		dev_err(&pdev->dev, "%d: error in initialization\n", saa_num);
-		retval = -EIO;
-		goto errrel;
-	}
-
-	saa_num++;
-
-	return 0;
-errrel:
-	stradis_release_saa(pdev);
-err:
-	return retval;
-}
-
-static void __devexit stradis_remove(struct pci_dev *pdev)
-{
-	stradis_release_saa(pdev);
-}
-
-static struct pci_device_id stradis_pci_tbl[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146) },
-	{ 0 }
-};
-
-
-static struct pci_driver stradis_driver = {
-	.name = "stradis",
-	.id_table = stradis_pci_tbl,
-	.probe = stradis_probe,
-	.remove = __devexit_p(stradis_remove)
-};
-
-static int __init stradis_init(void)
-{
-	int retval;
-
-	saa_num = 0;
-
-	retval = pci_register_driver(&stradis_driver);
-	if (retval)
-		printk(KERN_ERR "stradis: Unable to register pci driver.\n");
-
-	return retval;
-}
-
-static void __exit stradis_exit(void)
-{
-	pci_unregister_driver(&stradis_driver);
-	printk(KERN_INFO "stradis: module cleanup complete\n");
-}
-
-module_init(stradis_init);
-module_exit(stradis_exit);
diff --git a/drivers/staging/stradis/Kconfig b/drivers/staging/stradis/Kconfig
new file mode 100644
index 0000000..92e8911
--- /dev/null
+++ b/drivers/staging/stradis/Kconfig
@@ -0,0 +1,7 @@
+config VIDEO_STRADIS
+        tristate "Stradis 4:2:2 MPEG-2 video driver (DEPRECATED)"
+        depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
+        help
+          Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
+          driver for PCI.  There is a product page at
+          <http://www.stradis.com/>.
diff --git a/drivers/staging/stradis/Makefile b/drivers/staging/stradis/Makefile
new file mode 100644
index 0000000..0f1feab
--- /dev/null
+++ b/drivers/staging/stradis/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/staging/stradis/TODO b/drivers/staging/stradis/TODO
new file mode 100644
index 0000000..f48150f
--- /dev/null
+++ b/drivers/staging/stradis/TODO
@@ -0,0 +1,6 @@
+This is an obsolete driver for ancient stradis hardware.
+We couldn't find anyone with this hardware in order to port it to use V4L2.
+
+If nobody take care on it, the driver will be removed for 2.6.38.
+
+Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/stradis/stradis.c b/drivers/staging/stradis/stradis.c
new file mode 100644
index 0000000..a057824
--- /dev/null
+++ b/drivers/staging/stradis/stradis.c
@@ -0,0 +1,2213 @@
+/*
+ * stradis.c - stradis 4:2:2 mpeg decoder driver
+ *
+ * Stradis 4:2:2 MPEG-2 Decoder Driver
+ * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/types.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#include "saa7146.h"
+#include "saa7146reg.h"
+#include "ibmmpeg2.h"
+#include "saa7121.h"
+#include "cs8420.h"
+
+#define DEBUG(x)		/* debug driver */
+#undef  IDEBUG			/* debug irq handler */
+#undef  MDEBUG			/* debug memory management */
+
+#define SAA7146_MAX 6
+
+static struct saa7146 saa7146s[SAA7146_MAX];
+
+static int saa_num;		/* number of SAA7146s in use */
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+MODULE_LICENSE("GPL");
+
+#define nDebNormal	0x00480000
+#define nDebNoInc	0x00480000
+#define nDebVideo	0xd0480000
+#define nDebAudio	0xd0400000
+#define nDebDMA		0x02c80000
+
+#define oDebNormal	0x13c80000
+#define oDebNoInc	0x13c80000
+#define oDebVideo	0xd1080000
+#define oDebAudio	0xd1080000
+#define oDebDMA		0x03080000
+
+#define NewCard		(saa->boardcfg[3])
+#define ChipControl	(saa->boardcfg[1])
+#define NTSCFirstActive	(saa->boardcfg[4])
+#define PALFirstActive	(saa->boardcfg[5])
+#define NTSCLastActive	(saa->boardcfg[54])
+#define PALLastActive	(saa->boardcfg[55])
+#define Have2MB		(saa->boardcfg[18] & 0x40)
+#define HaveCS8420	(saa->boardcfg[18] & 0x04)
+#define IBMMPEGCD20	(saa->boardcfg[18] & 0x20)
+#define HaveCS3310	(saa->boardcfg[18] & 0x01)
+#define CS3310MaxLvl	((saa->boardcfg[30] << 8) | saa->boardcfg[31])
+#define HaveCS4341	(saa->boardcfg[40] == 2)
+#define SDIType		(saa->boardcfg[27])
+#define CurrentMode	(saa->boardcfg[2])
+
+#define debNormal	(NewCard ? nDebNormal : oDebNormal)
+#define debNoInc	(NewCard ? nDebNoInc : oDebNoInc)
+#define debVideo	(NewCard ? nDebVideo : oDebVideo)
+#define debAudio	(NewCard ? nDebAudio : oDebAudio)
+#define debDMA		(NewCard ? nDebDMA : oDebDMA)
+
+#ifdef USE_RESCUE_EEPROM_SDM275
+static unsigned char rescue_eeprom[64] = {
+	0x00, 0x01, 0x04, 0x13, 0x26, 0x0f, 0x10, 0x00, 0x00, 0x00, 0x43, 0x63,
+	0x22, 0x01, 0x29, 0x15, 0x73, 0x00, 0x1f,  'd',  'e',  'c',  'x',  'l',
+	 'd',  'v',  'a', 0x02, 0x00, 0x01, 0x00, 0xcc, 0xa4, 0x63, 0x09, 0xe2,
+	0x10, 0x00, 0x0a, 0x00, 0x02, 0x02,  'd',  'e',  'c',  'x',  'l',  'a',
+	0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Hardware I2C functions */
+static void I2CWipe(struct saa7146 *saa)
+{
+	int i;
+	/* set i2c to ~=100kHz, abort transfer, clear busy */
+	saawrite(0x600 | SAA7146_I2C_ABORT, SAA7146_I2C_STATUS);
+	saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+		 SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+	/* wait for i2c registers to be programmed */
+	for (i = 0; i < 1000 &&
+	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+		schedule();
+	saawrite(0x600, SAA7146_I2C_STATUS);
+	saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+		 SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+	/* wait for i2c registers to be programmed */
+	for (i = 0; i < 1000 &&
+	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+		schedule();
+	saawrite(0x600, SAA7146_I2C_STATUS);
+	saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+		 SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+	/* wait for i2c registers to be programmed */
+	for (i = 0; i < 1000 &&
+	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+		schedule();
+}
+
+/* read I2C */
+static int I2CRead(struct saa7146 *saa, unsigned char addr,
+		   unsigned char subaddr, int dosub)
+{
+	int i;
+
+	if (saaread(SAA7146_I2C_STATUS) & 0x3c)
+		I2CWipe(saa);
+	for (i = 0;
+		i < 1000 && (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY);
+		i++)
+		schedule();
+	if (i == 1000)
+		I2CWipe(saa);
+	if (dosub)
+		saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 8) |
+			((subaddr & 0xff) << 16) | 0xed, SAA7146_I2C_TRANSFER);
+	else
+		saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 16) |
+			0xf1, SAA7146_I2C_TRANSFER);
+	saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+		 SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+	/* wait for i2c registers to be programmed */
+	for (i = 0; i < 1000 &&
+	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+		schedule();
+	/* wait for valid data */
+	for (i = 0; i < 1000 &&
+	     (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
+		schedule();
+	if (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_ERR)
+		return -1;
+	if (i == 1000)
+		printk("i2c setup read timeout\n");
+	saawrite(0x41, SAA7146_I2C_TRANSFER);
+	saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+		 SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+	/* wait for i2c registers to be programmed */
+	for (i = 0; i < 1000 &&
+	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+		schedule();
+	/* wait for valid data */
+	for (i = 0; i < 1000 &&
+	     (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_BUSY); i++)
+		schedule();
+	if (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_ERR)
+		return -1;
+	if (i == 1000)
+		printk("i2c read timeout\n");
+	return ((saaread(SAA7146_I2C_TRANSFER) >> 24) & 0xff);
+}
+
+/* set both to write both bytes, reset it to write only b1 */
+
+static int I2CWrite(struct saa7146 *saa, unsigned char addr, unsigned char b1,
+		    unsigned char b2, int both)
+{
+	int i;
+	u32 data;
+
+	if (saaread(SAA7146_I2C_STATUS) & 0x3c)
+		I2CWipe(saa);
+	for (i = 0; i < 1000 &&
+	     (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
+		schedule();
+	if (i == 1000)
+		I2CWipe(saa);
+	data = ((addr & 0xfe) << 24) | ((b1 & 0xff) << 16);
+	if (both)
+		data |= ((b2 & 0xff) << 8) | 0xe5;
+	else
+		data |= 0xd1;
+	saawrite(data, SAA7146_I2C_TRANSFER);
+	saawrite((SAA7146_MC2_UPLD_I2C << 16) | SAA7146_MC2_UPLD_I2C,
+		 SAA7146_MC2);
+	return 0;
+}
+
+static void attach_inform(struct saa7146 *saa, int id)
+{
+	int i;
+
+	DEBUG(printk(KERN_DEBUG "stradis%d: i2c: device found=%02x\n", saa->nr,
+		id));
+	if (id == 0xa0) {	/* we have rev2 or later board, fill in info */
+		for (i = 0; i < 64; i++)
+			saa->boardcfg[i] = I2CRead(saa, 0xa0, i, 1);
+#ifdef USE_RESCUE_EEPROM_SDM275
+		if (saa->boardcfg[0] != 0) {
+			printk("stradis%d: WARNING: EEPROM STORED VALUES HAVE "
+				"BEEN IGNORED\n", saa->nr);
+			for (i = 0; i < 64; i++)
+				saa->boardcfg[i] = rescue_eeprom[i];
+		}
+#endif
+		printk("stradis%d: config =", saa->nr);
+		for (i = 0; i < 51; i++) {
+			printk(" %02x", saa->boardcfg[i]);
+		}
+		printk("\n");
+	}
+}
+
+static void I2CBusScan(struct saa7146 *saa)
+{
+	int i;
+	for (i = 0; i < 0xff; i += 2)
+		if ((I2CRead(saa, i, 0, 0)) >= 0)
+			attach_inform(saa, i);
+}
+
+static int debiwait_maxwait;
+
+static int wait_for_debi_done(struct saa7146 *saa)
+{
+	int i;
+
+	/* wait for registers to be programmed */
+	for (i = 0; i < 100000 &&
+	     !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_DEBI); i++)
+		saaread(SAA7146_MC2);
+	/* wait for transfer to complete */
+	for (i = 0; i < 500000 &&
+	     (saaread(SAA7146_PSR) & SAA7146_PSR_DEBI_S); i++)
+		saaread(SAA7146_MC2);
+
+	if (i > debiwait_maxwait)
+		printk("wait-for-debi-done maxwait: %d\n",
+			debiwait_maxwait = i);
+
+	if (i == 500000)
+		return -1;
+
+	return 0;
+}
+
+static int debiwrite(struct saa7146 *saa, u32 config, int addr,
+	u32 val, int count)
+{
+	u32 cmd;
+	if (count <= 0 || count > 32764)
+		return -1;
+	if (wait_for_debi_done(saa) < 0)
+		return -1;
+	saawrite(config, SAA7146_DEBI_CONFIG);
+	if (count <= 4)		/* immediate transfer */
+		saawrite(val, SAA7146_DEBI_AD);
+	else			/* block transfer */
+		saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
+	saawrite((cmd = (count << 17) | (addr & 0xffff)), SAA7146_DEBI_COMMAND);
+	saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
+		 SAA7146_MC2);
+	return 0;
+}
+
+static u32 debiread(struct saa7146 *saa, u32 config, int addr, int count)
+{
+	u32 result = 0;
+
+	if (count > 32764 || count <= 0)
+		return 0;
+	if (wait_for_debi_done(saa) < 0)
+		return 0;
+	saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
+	saawrite((count << 17) | 0x10000 | (addr & 0xffff),
+		 SAA7146_DEBI_COMMAND);
+	saawrite(config, SAA7146_DEBI_CONFIG);
+	saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
+		 SAA7146_MC2);
+	if (count > 4)		/* not an immediate transfer */
+		return count;
+	wait_for_debi_done(saa);
+	result = saaread(SAA7146_DEBI_AD);
+	if (count == 1)
+		result &= 0xff;
+	if (count == 2)
+		result &= 0xffff;
+	if (count == 3)
+		result &= 0xffffff;
+	return result;
+}
+
+static void do_irq_send_data(struct saa7146 *saa)
+{
+	int split, audbytes, vidbytes;
+
+	saawrite(SAA7146_PSR_PIN1, SAA7146_IER);
+	/* if special feature mode in effect, disable audio sending */
+	if (saa->playmode != VID_PLAY_NORMAL)
+		saa->audtail = saa->audhead = 0;
+	if (saa->audhead <= saa->audtail)
+		audbytes = saa->audtail - saa->audhead;
+	else
+		audbytes = 65536 - (saa->audhead - saa->audtail);
+	if (saa->vidhead <= saa->vidtail)
+		vidbytes = saa->vidtail - saa->vidhead;
+	else
+		vidbytes = 524288 - (saa->vidhead - saa->vidtail);
+	if (audbytes == 0 && vidbytes == 0 && saa->osdtail == saa->osdhead) {
+		saawrite(0, SAA7146_IER);
+		return;
+	}
+	/* if at least 1 block audio waiting and audio fifo isn't full */
+	if (audbytes >= 2048 && (debiread(saa, debNormal, IBM_MP2_AUD_FIFO, 2)
+			& 0xff) < 60) {
+		if (saa->audhead > saa->audtail)
+			split = 65536 - saa->audhead;
+		else
+			split = 0;
+		audbytes = 2048;
+		if (split > 0 && split < 2048) {
+			memcpy(saa->dmadebi, saa->audbuf + saa->audhead, split);
+			saa->audhead = 0;
+			audbytes -= split;
+		} else
+			split = 0;
+		memcpy(saa->dmadebi + split, saa->audbuf + saa->audhead,
+			audbytes);
+		saa->audhead += audbytes;
+		saa->audhead &= 0xffff;
+		debiwrite(saa, debAudio, (NewCard ? IBM_MP2_AUD_FIFO :
+			IBM_MP2_AUD_FIFOW), 0, 2048);
+		wake_up_interruptible(&saa->audq);
+		/* if at least 1 block video waiting and video fifo isn't full */
+	} else if (vidbytes >= 30720 && (debiread(saa, debNormal,
+						  IBM_MP2_FIFO, 2)) < 16384) {
+		if (saa->vidhead > saa->vidtail)
+			split = 524288 - saa->vidhead;
+		else
+			split = 0;
+		vidbytes = 30720;
+		if (split > 0 && split < 30720) {
+			memcpy(saa->dmadebi, saa->vidbuf + saa->vidhead, split);
+			saa->vidhead = 0;
+			vidbytes -= split;
+		} else
+			split = 0;
+		memcpy(saa->dmadebi + split, saa->vidbuf + saa->vidhead,
+			vidbytes);
+		saa->vidhead += vidbytes;
+		saa->vidhead &= 0x7ffff;
+		debiwrite(saa, debVideo, (NewCard ? IBM_MP2_FIFO :
+					  IBM_MP2_FIFOW), 0, 30720);
+		wake_up_interruptible(&saa->vidq);
+	}
+	saawrite(SAA7146_PSR_DEBI_S | SAA7146_PSR_PIN1, SAA7146_IER);
+}
+
+static void send_osd_data(struct saa7146 *saa)
+{
+	int size = saa->osdtail - saa->osdhead;
+	if (size > 30720)
+		size = 30720;
+	/* ensure some multiple of 8 bytes is transferred */
+	size = 8 * ((size + 8) >> 3);
+	if (size) {
+		debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR,
+			  (saa->osdhead >> 3), 2);
+		memcpy(saa->dmadebi, &saa->osdbuf[saa->osdhead], size);
+		saa->osdhead += size;
+		/* block transfer of next 8 bytes to ~32k bytes */
+		debiwrite(saa, debNormal, IBM_MP2_OSD_DATA, 0, size);
+	}
+	if (saa->osdhead >= saa->osdtail) {
+		saa->osdhead = saa->osdtail = 0;
+		debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
+	}
+}
+
+static irqreturn_t saa7146_irq(int irq, void *dev_id)
+{
+	struct saa7146 *saa = dev_id;
+	u32 stat, astat;
+	int count;
+	int handled = 0;
+
+	count = 0;
+	while (1) {
+		/* get/clear interrupt status bits */
+		stat = saaread(SAA7146_ISR);
+		astat = stat & saaread(SAA7146_IER);
+		if (!astat)
+			break;
+		handled = 1;
+		saawrite(astat, SAA7146_ISR);
+		if (astat & SAA7146_PSR_DEBI_S) {
+			do_irq_send_data(saa);
+		}
+		if (astat & SAA7146_PSR_PIN1) {
+			int istat;
+			/* the following read will trigger DEBI_S */
+			istat = debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
+			if (istat & 1) {
+				saawrite(0, SAA7146_IER);
+				send_osd_data(saa);
+				saawrite(SAA7146_PSR_DEBI_S |
+					 SAA7146_PSR_PIN1, SAA7146_IER);
+			}
+			if (istat & 0x20) {	/* Video Start */
+				saa->vidinfo.frame_count++;
+			}
+			if (istat & 0x400) {	/* Picture Start */
+				/* update temporal reference */
+			}
+			if (istat & 0x200) {	/* Picture Resolution Change */
+				/* read new resolution */
+			}
+			if (istat & 0x100) {	/* New User Data found */
+				/* read new user data */
+			}
+			if (istat & 0x1000) {	/* new GOP/SMPTE */
+				/* read new SMPTE */
+			}
+			if (istat & 0x8000) {	/* Sequence Start Code */
+				/* reset frame counter, load sizes */
+				saa->vidinfo.frame_count = 0;
+				saa->vidinfo.h_size = 704;
+				saa->vidinfo.v_size = 480;
+#if 0
+				if (saa->endmarkhead != saa->endmarktail) {
+					saa->audhead =
+						saa->endmark[saa->endmarkhead];
+					saa->endmarkhead++;
+					if (saa->endmarkhead >= MAX_MARKS)
+						saa->endmarkhead = 0;
+				}
+#endif
+			}
+			if (istat & 0x4000) {	/* Sequence Error Code */
+				if (saa->endmarkhead != saa->endmarktail) {
+					saa->audhead =
+						saa->endmark[saa->endmarkhead];
+					saa->endmarkhead++;
+					if (saa->endmarkhead >= MAX_MARKS)
+						saa->endmarkhead = 0;
+				}
+			}
+		}
+#ifdef IDEBUG
+		if (astat & SAA7146_PSR_PPEF) {
+			IDEBUG(printk("stradis%d irq: PPEF\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_PABO) {
+			IDEBUG(printk("stradis%d irq: PABO\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_PPED) {
+			IDEBUG(printk("stradis%d irq: PPED\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_RPS_I1) {
+			IDEBUG(printk("stradis%d irq: RPS_I1\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_RPS_I0) {
+			IDEBUG(printk("stradis%d irq: RPS_I0\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_RPS_LATE1) {
+			IDEBUG(printk("stradis%d irq: RPS_LATE1\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_RPS_LATE0) {
+			IDEBUG(printk("stradis%d irq: RPS_LATE0\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_RPS_E1) {
+			IDEBUG(printk("stradis%d irq: RPS_E1\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_RPS_E0) {
+			IDEBUG(printk("stradis%d irq: RPS_E0\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_RPS_TO1) {
+			IDEBUG(printk("stradis%d irq: RPS_TO1\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_RPS_TO0) {
+			IDEBUG(printk("stradis%d irq: RPS_TO0\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_UPLD) {
+			IDEBUG(printk("stradis%d irq: UPLD\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_DEBI_E) {
+			IDEBUG(printk("stradis%d irq: DEBI_E\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_I2C_S) {
+			IDEBUG(printk("stradis%d irq: I2C_S\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_I2C_E) {
+			IDEBUG(printk("stradis%d irq: I2C_E\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_A2_IN) {
+			IDEBUG(printk("stradis%d irq: A2_IN\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_A2_OUT) {
+			IDEBUG(printk("stradis%d irq: A2_OUT\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_A1_IN) {
+			IDEBUG(printk("stradis%d irq: A1_IN\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_A1_OUT) {
+			IDEBUG(printk("stradis%d irq: A1_OUT\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_AFOU) {
+			IDEBUG(printk("stradis%d irq: AFOU\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_V_PE) {
+			IDEBUG(printk("stradis%d irq: V_PE\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_VFOU) {
+			IDEBUG(printk("stradis%d irq: VFOU\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_FIDA) {
+			IDEBUG(printk("stradis%d irq: FIDA\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_FIDB) {
+			IDEBUG(printk("stradis%d irq: FIDB\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_PIN3) {
+			IDEBUG(printk("stradis%d irq: PIN3\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_PIN2) {
+			IDEBUG(printk("stradis%d irq: PIN2\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_PIN0) {
+			IDEBUG(printk("stradis%d irq: PIN0\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_ECS) {
+			IDEBUG(printk("stradis%d irq: ECS\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_EC3S) {
+			IDEBUG(printk("stradis%d irq: EC3S\n", saa->nr));
+		}
+		if (astat & SAA7146_PSR_EC0S) {
+			IDEBUG(printk("stradis%d irq: EC0S\n", saa->nr));
+		}
+#endif
+		count++;
+		if (count > 15)
+			printk(KERN_WARNING "stradis%d: irq loop %d\n",
+			       saa->nr, count);
+		if (count > 20) {
+			saawrite(0, SAA7146_IER);
+			printk(KERN_ERR
+			       "stradis%d: IRQ loop cleared\n", saa->nr);
+		}
+	}
+	return IRQ_RETVAL(handled);
+}
+
+static int ibm_send_command(struct saa7146 *saa,
+			    int command, int data, int chain)
+{
+	int i;
+
+	if (chain)
+		debiwrite(saa, debNormal, IBM_MP2_COMMAND, (command << 1)| 1,2);
+	else
+		debiwrite(saa, debNormal, IBM_MP2_COMMAND, command << 1, 2);
+	debiwrite(saa, debNormal, IBM_MP2_CMD_DATA, data, 2);
+	debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 1, 2);
+	for (i = 0; i < 100 &&
+	     (debiread(saa, debNormal, IBM_MP2_CMD_STAT, 2) & 1); i++)
+		schedule();
+	if (i == 100)
+		return -1;
+	return 0;
+}
+
+static void cs4341_setlevel(struct saa7146 *saa, int left, int right)
+{
+	I2CWrite(saa, 0x22, 0x03, left > 94 ? 94 : left, 2);
+	I2CWrite(saa, 0x22, 0x04, right > 94 ? 94 : right, 2);
+}
+
+static void initialize_cs4341(struct saa7146 *saa)
+{
+	int i;
+	for (i = 0; i < 200; i++) {
+		/* auto mute off, power on, no de-emphasis */
+		/* I2S data up to 24-bit 64xFs internal SCLK */
+		I2CWrite(saa, 0x22, 0x01, 0x11, 2);
+		/* ATAPI mixer settings */
+		I2CWrite(saa, 0x22, 0x02, 0x49, 2);
+		/* attenuation left 3db */
+		I2CWrite(saa, 0x22, 0x03, 0x00, 2);
+		/* attenuation right 3db */
+		I2CWrite(saa, 0x22, 0x04, 0x00, 2);
+		I2CWrite(saa, 0x22, 0x01, 0x10, 2);
+		if (I2CRead(saa, 0x22, 0x02, 1) == 0x49)
+			break;
+		schedule();
+	}
+	printk("stradis%d: CS4341 initialized (%d)\n", saa->nr, i);
+	return;
+}
+
+static void initialize_cs8420(struct saa7146 *saa, int pro)
+{
+	int i;
+	u8 *sequence;
+	if (pro)
+		sequence = mode8420pro;
+	else
+		sequence = mode8420con;
+	for (i = 0; i < INIT8420LEN; i++)
+		I2CWrite(saa, 0x20, init8420[i * 2], init8420[i * 2 + 1], 2);
+	for (i = 0; i < MODE8420LEN; i++)
+		I2CWrite(saa, 0x20, sequence[i * 2], sequence[i * 2 + 1], 2);
+	printk("stradis%d: CS8420 initialized\n", saa->nr);
+}
+
+static void initialize_saa7121(struct saa7146 *saa, int dopal)
+{
+	int i, mod;
+	u8 *sequence;
+	if (dopal)
+		sequence = init7121pal;
+	else
+		sequence = init7121ntsc;
+	mod = saaread(SAA7146_PSR) & 0x08;
+	/* initialize PAL/NTSC video encoder */
+	for (i = 0; i < INIT7121LEN; i++) {
+		if (NewCard) {	/* handle new card encoder differences */
+			if (sequence[i * 2] == 0x3a)
+				I2CWrite(saa, 0x88, 0x3a, 0x13, 2);
+			else if (sequence[i * 2] == 0x6b)
+				I2CWrite(saa, 0x88, 0x6b, 0x20, 2);
+			else if (sequence[i * 2] == 0x6c)
+				I2CWrite(saa, 0x88, 0x6c,
+					 dopal ? 0x09 : 0xf5, 2);
+			else if (sequence[i * 2] == 0x6d)
+				I2CWrite(saa, 0x88, 0x6d,
+					 dopal ? 0x20 : 0x00, 2);
+			else if (sequence[i * 2] == 0x7a)
+				I2CWrite(saa, 0x88, 0x7a,
+					 dopal ? (PALFirstActive - 1) :
+					 (NTSCFirstActive - 4), 2);
+			else if (sequence[i * 2] == 0x7b)
+				I2CWrite(saa, 0x88, 0x7b,
+					 dopal ? PALLastActive :
+					 NTSCLastActive, 2);
+			else
+				I2CWrite(saa, 0x88, sequence[i * 2],
+					 sequence[i * 2 + 1], 2);
+		} else {
+			if (sequence[i * 2] == 0x6b && mod)
+				I2CWrite(saa, 0x88, 0x6b,
+					 (sequence[i * 2 + 1] ^ 0x09), 2);
+			else if (sequence[i * 2] == 0x7a)
+				I2CWrite(saa, 0x88, 0x7a,
+					 dopal ? (PALFirstActive - 1) :
+					 (NTSCFirstActive - 4), 2);
+			else if (sequence[i * 2] == 0x7b)
+				I2CWrite(saa, 0x88, 0x7b,
+					 dopal ? PALLastActive :
+					 NTSCLastActive, 2);
+			else
+				I2CWrite(saa, 0x88, sequence[i * 2],
+					 sequence[i * 2 + 1], 2);
+		}
+	}
+}
+
+static void set_genlock_offset(struct saa7146 *saa, int noffset)
+{
+	int nCode;
+	int PixelsPerLine = 858;
+	if (CurrentMode == VIDEO_MODE_PAL)
+		PixelsPerLine = 864;
+	if (noffset > 500)
+		noffset = 500;
+	else if (noffset < -500)
+		noffset = -500;
+	nCode = noffset + 0x100;
+	if (nCode == 1)
+		nCode = 0x401;
+	else if (nCode < 1)
+		nCode = 0x400 + PixelsPerLine + nCode;
+	debiwrite(saa, debNormal, XILINX_GLDELAY, nCode, 2);
+}
+
+static void set_out_format(struct saa7146 *saa, int mode)
+{
+	initialize_saa7121(saa, (mode == VIDEO_MODE_NTSC ? 0 : 1));
+	saa->boardcfg[2] = mode;
+	/* do not adjust analog video parameters here, use saa7121 init */
+	/* you will affect the SDI output on the new card */
+	if (mode == VIDEO_MODE_PAL) {	/* PAL */
+		debiwrite(saa, debNormal, XILINX_CTL0, 0x0808, 2);
+		mdelay(50);
+		saawrite(0x012002c0, SAA7146_NUM_LINE_BYTE1);
+		if (NewCard) {
+			debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, 0xe100, 2);
+			mdelay(50);
+		}
+		debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+			  NewCard ? 0xe500 : 0x6500, 2);
+		debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
+			  (1 << 8) |
+			  (NewCard ? PALFirstActive : PALFirstActive - 6), 2);
+	} else {		/* NTSC */
+		debiwrite(saa, debNormal, XILINX_CTL0, 0x0800, 2);
+		mdelay(50);
+		saawrite(0x00f002c0, SAA7146_NUM_LINE_BYTE1);
+		debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+			  NewCard ? 0xe100 : 0x6100, 2);
+		debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
+			  (1 << 8) |
+			  (NewCard ? NTSCFirstActive : NTSCFirstActive - 6), 2);
+	}
+}
+
+/* Intialize bitmangler to map from a byte value to the mangled word that
+ * must be output to program the Xilinx part through the DEBI port.
+ * Xilinx Data Bit->DEBI Bit: 0->15 1->7 2->6 3->12 4->11 5->2 6->1 7->0
+ * transfer FPGA code, init IBM chip, transfer IBM microcode
+ * rev2 card mangles: 0->7 1->6 2->5 3->4 4->3 5->2 6->1 7->0
+ */
+static u16 bitmangler[256];
+
+static int initialize_fpga(struct video_code *bitdata)
+{
+	int i, num, startindex, failure = 0, loadtwo, loadfile = 0;
+	u16 *dmabuf;
+	u8 *newdma;
+	struct saa7146 *saa;
+
+	/* verify fpga code */
+	for (startindex = 0; startindex < bitdata->datasize; startindex++)
+		if (bitdata->data[startindex] == 255)
+			break;
+	if (startindex == bitdata->datasize) {
+		printk(KERN_INFO "stradis: bad fpga code\n");
+		return -1;
+	}
+	/* initialize all detected cards */
+	for (num = 0; num < saa_num; num++) {
+		saa = &saa7146s[num];
+		if (saa->boardcfg[0] > 20)
+			continue;	/* card was programmed */
+		loadtwo = (saa->boardcfg[18] & 0x10);
+		if (!NewCard)	/* we have an old board */
+			for (i = 0; i < 256; i++)
+				bitmangler[i] = ((i & 0x01) << 15) |
+					((i & 0x02) << 6) | ((i & 0x04) << 4) |
+					((i & 0x08) << 9) | ((i & 0x10) << 7) |
+					((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
+					((i & 0x80) >> 7);
+		else		/* else we have a new board */
+			for (i = 0; i < 256; i++)
+				bitmangler[i] = ((i & 0x01) << 7) |
+					((i & 0x02) << 5) | ((i & 0x04) << 3) |
+					((i & 0x08) << 1) | ((i & 0x10) >> 1) |
+					((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
+					((i & 0x80) >> 7);
+
+		dmabuf = (u16 *) saa->dmadebi;
+		newdma = (u8 *) saa->dmadebi;
+		if (NewCard) {	/* SDM2xxx */
+			if (!strncmp(bitdata->loadwhat, "decoder2", 8))
+				continue;	/* fpga not for this card */
+			if (!strncmp(&saa->boardcfg[42], bitdata->loadwhat, 8))
+				loadfile = 1;
+			else if (loadtwo && !strncmp(&saa->boardcfg[19],
+				       bitdata->loadwhat, 8))
+				loadfile = 2;
+			else if (!saa->boardcfg[42] && !strncmp("decxl",
+					bitdata->loadwhat, 8))
+				loadfile = 1;	/* special */
+			else
+				continue;	/* fpga not for this card */
+			if (loadfile != 1 && loadfile != 2)
+				continue;	/* skip to next card */
+			if (saa->boardcfg[0] && loadfile == 1)
+				continue;	/* skip to next card */
+			if (saa->boardcfg[0] != 1 && loadfile == 2)
+				continue;	/* skip to next card */
+			saa->boardcfg[0]++;	/* mark fpga handled */
+			printk("stradis%d: loading %s\n", saa->nr,
+				bitdata->loadwhat);
+			if (loadtwo && loadfile == 2)
+				goto send_fpga_stuff;
+			/* turn on the Audio interface to set PROG low */
+			saawrite(0x00400040, SAA7146_GPIO_CTRL);
+			saaread(SAA7146_PSR);	/* ensure posted write */
+			/* wait for everyone to reset */
+			mdelay(10);
+			saawrite(0x00400000, SAA7146_GPIO_CTRL);
+		} else {	/* original card */
+			if (strncmp(bitdata->loadwhat, "decoder2", 8))
+				continue;	/* fpga not for this card */
+			/* Pull the Xilinx PROG signal WS3 low */
+			saawrite(0x02000200, SAA7146_MC1);
+			/* Turn on the Audio interface so can set PROG low */
+			saawrite(0x000000c0, SAA7146_ACON1);
+			/* Pull the Xilinx INIT signal (GPIO2) low */
+			saawrite(0x00400000, SAA7146_GPIO_CTRL);
+			/* Make sure everybody resets */
+			saaread(SAA7146_PSR);	/* ensure posted write */
+			mdelay(10);
+			/* Release the Xilinx PROG signal */
+			saawrite(0x00000000, SAA7146_ACON1);
+			/* Turn off the Audio interface */
+			saawrite(0x02000000, SAA7146_MC1);
+		}
+		/* Release Xilinx INIT signal (WS2) */
+		saawrite(0x00000000, SAA7146_GPIO_CTRL);
+		/* Wait for the INIT to go High */
+		for (i = 0;
+			i < 10000 && !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2);
+			i++)
+			schedule();
+		if (i == 1000) {
+			printk(KERN_INFO "stradis%d: no fpga INIT\n", saa->nr);
+			return -1;
+		}
+send_fpga_stuff:
+		if (NewCard) {
+			for (i = startindex; i < bitdata->datasize; i++)
+				newdma[i - startindex] =
+				    bitmangler[bitdata->data[i]];
+			debiwrite(saa, 0x01420000, 0, 0,
+				((bitdata->datasize - startindex) + 5));
+			if (loadtwo && loadfile == 1) {
+				printk("stradis%d: awaiting 2nd FPGA bitfile\n",
+				       saa->nr);
+				continue;	/* skip to next card */
+			}
+		} else {
+			for (i = startindex; i < bitdata->datasize; i++)
+				dmabuf[i - startindex] =
+					bitmangler[bitdata->data[i]];
+			debiwrite(saa, 0x014a0000, 0, 0,
+				((bitdata->datasize - startindex) + 5) * 2);
+		}
+		for (i = 0;
+			i < 1000 && !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2);
+			i++)
+			schedule();
+		if (i == 1000) {
+			printk(KERN_INFO "stradis%d: FPGA load failed\n",
+			       saa->nr);
+			failure++;
+			continue;
+		}
+		if (!NewCard) {
+			/* Pull the Xilinx INIT signal (GPIO2) low */
+			saawrite(0x00400000, SAA7146_GPIO_CTRL);
+			saaread(SAA7146_PSR);	/* ensure posted write */
+			mdelay(2);
+			saawrite(0x00000000, SAA7146_GPIO_CTRL);
+			mdelay(2);
+		}
+		printk(KERN_INFO "stradis%d: FPGA Loaded\n", saa->nr);
+		saa->boardcfg[0] = 26;	/* mark fpga programmed */
+		/* set VXCO to its lowest frequency */
+		debiwrite(saa, debNormal, XILINX_PWM, 0, 2);
+		if (NewCard) {
+			/* mute CS3310 */
+			if (HaveCS3310)
+				debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
+					0, 2);
+			/* set VXCO to PWM mode, release reset, blank on */
+			debiwrite(saa, debNormal, XILINX_CTL0, 0xffc4, 2);
+			mdelay(10);
+			/* unmute CS3310 */
+			if (HaveCS3310)
+				debiwrite(saa, debNormal, XILINX_CTL0,
+					0x2020, 2);
+		}
+		/* set source Black */
+		debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
+		saa->boardcfg[4] = 22;	/* set NTSC First Active Line */
+		saa->boardcfg[5] = 23;	/* set PAL First Active Line */
+		saa->boardcfg[54] = 2;	/* set NTSC Last Active Line - 256 */
+		saa->boardcfg[55] = 54;	/* set PAL Last Active Line - 256 */
+		set_out_format(saa, VIDEO_MODE_NTSC);
+		mdelay(50);
+		/* begin IBM chip init */
+		debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
+		saaread(SAA7146_PSR);	/* wait for reset */
+		mdelay(5);
+		debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
+		debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
+		debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0x10, 2);
+		debiwrite(saa, debNormal, IBM_MP2_CMD_ADDR, 0, 2);
+		debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
+		if (NewCard) {
+			mdelay(5);
+			/* set i2s rate converter to 48KHz */
+			debiwrite(saa, debNormal, 0x80c0, 6, 2);
+			/* we must init CS8420 first since rev b pulls i2s */
+			/* master clock low and CS4341 needs i2s master to */
+			/* run the i2c port. */
+			if (HaveCS8420)
+				/* 0=consumer, 1=pro */
+				initialize_cs8420(saa, 0);
+
+			mdelay(5);
+			if (HaveCS4341)
+				initialize_cs4341(saa);
+		}
+		debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
+		debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
+		debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
+		debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
+		if (NewCard)
+			set_genlock_offset(saa, 0);
+		debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
+#if 0
+		/* enable genlock */
+		debiwrite(saa, debNormal, XILINX_CTL0, 0x8000, 2);
+#else
+		/* disable genlock */
+		debiwrite(saa, debNormal, XILINX_CTL0, 0x8080, 2);
+#endif
+	}
+
+	return failure;
+}
+
+static int do_ibm_reset(struct saa7146 *saa)
+{
+	/* failure if decoder not previously programmed */
+	if (saa->boardcfg[0] < 37)
+		return -EIO;
+	/* mute CS3310 */
+	if (HaveCS3310)
+		debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, 0, 2);
+	/* disable interrupts */
+	saawrite(0, SAA7146_IER);
+	saa->audhead = saa->audtail = 0;
+	saa->vidhead = saa->vidtail = 0;
+	/* tristate debi bus, disable debi transfers */
+	saawrite(0x00880000, SAA7146_MC1);
+	/* ensure posted write */
+	saaread(SAA7146_MC1);
+	mdelay(50);
+	/* re-enable debi transfers */
+	saawrite(0x00880088, SAA7146_MC1);
+	/* set source Black */
+	debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
+	/* begin IBM chip init */
+	set_out_format(saa, CurrentMode);
+	debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
+	saaread(SAA7146_PSR);	/* wait for reset */
+	mdelay(5);
+	debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
+	debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
+	debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+	debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
+	if (NewCard) {
+		mdelay(5);
+		/* set i2s rate converter to 48KHz */
+		debiwrite(saa, debNormal, 0x80c0, 6, 2);
+		/* we must init CS8420 first since rev b pulls i2s */
+		/* master clock low and CS4341 needs i2s master to */
+		/* run the i2c port. */
+		if (HaveCS8420)
+			/* 0=consumer, 1=pro */
+			initialize_cs8420(saa, 1);
+
+		mdelay(5);
+		if (HaveCS4341)
+			initialize_cs4341(saa);
+	}
+	debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
+	debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
+	debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
+	debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
+	if (NewCard)
+		set_genlock_offset(saa, 0);
+	debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
+	debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
+	debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
+	if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
+			(ChipControl == 0x43 ? 0xe800 : 0xe000), 1)) {
+		printk(KERN_ERR "stradis%d: IBM config failed\n", saa->nr);
+	}
+	if (HaveCS3310) {
+		int i = CS3310MaxLvl;
+		debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, ((i << 8)| i),2);
+	}
+	/* start video decoder */
+	debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+	/* 256k vid, 3520 bytes aud */
+	debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037, 2);
+	debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
+	ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
+	/* enable buffer threshold irq */
+	debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
+	/* clear pending interrupts */
+	debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
+	debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
+
+	return 0;
+}
+
+/* load the decoder microcode */
+static int initialize_ibmmpeg2(struct video_code *microcode)
+{
+	int i, num;
+	struct saa7146 *saa;
+
+	for (num = 0; num < saa_num; num++) {
+		saa = &saa7146s[num];
+		/* check that FPGA is loaded */
+		debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0xa55a, 2);
+		i = debiread(saa, debNormal, IBM_MP2_OSD_SIZE, 2);
+		if (i != 0xa55a) {
+			printk(KERN_INFO "stradis%d: %04x != 0xa55a\n",
+				saa->nr, i);
+#if 0
+			return -1;
+#endif
+		}
+		if (!strncmp(microcode->loadwhat, "decoder.vid", 11)) {
+			if (saa->boardcfg[0] > 27)
+				continue;	/* skip to next card */
+			/* load video control store */
+			saa->boardcfg[1] = 0x13;	/* no-sync default */
+			debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
+			debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
+			for (i = 0; i < microcode->datasize / 2; i++)
+				debiwrite(saa, debNormal, IBM_MP2_PROC_IDATA,
+					(microcode->data[i * 2] << 8) |
+					microcode->data[i * 2 + 1], 2);
+			debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
+			debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
+			debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
+				ChipControl, 2);
+			saa->boardcfg[0] = 28;
+		}
+		if (!strncmp(microcode->loadwhat, "decoder.aud", 11)) {
+			if (saa->boardcfg[0] > 35)
+				continue;	/* skip to next card */
+			/* load audio control store */
+			debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
+			debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
+			for (i = 0; i < microcode->datasize; i++)
+				debiwrite(saa, debNormal, IBM_MP2_AUD_IDATA,
+					microcode->data[i], 1);
+			debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
+			debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
+			debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
+			debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
+			if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
+					0xe000, 1)) {
+				printk(KERN_ERR "stradis%d: IBM config "
+					"failed\n", saa->nr);
+				return -1;
+			}
+			/* set PWM to center value */
+			if (NewCard) {
+				debiwrite(saa, debNormal, XILINX_PWM,
+					saa->boardcfg[14] +
+					(saa->boardcfg[13] << 8), 2);
+			} else
+				debiwrite(saa, debNormal, XILINX_PWM, 0x46, 2);
+
+			if (HaveCS3310) {
+				i = CS3310MaxLvl;
+				debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
+					(i << 8) | i, 2);
+			}
+			printk(KERN_INFO "stradis%d: IBM MPEGCD%d Inited\n",
+				saa->nr, 18 + (debiread(saa, debNormal,
+				IBM_MP2_CHIP_CONTROL, 2) >> 12));
+			/* start video decoder */
+			debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
+				ChipControl, 2);
+			debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037,
+				2);	/* 256k vid, 3520 bytes aud */
+			debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
+			ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
+			/* enable buffer threshold irq */
+			debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
+			debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
+			/* enable gpio irq */
+			saawrite(0x00002000, SAA7146_GPIO_CTRL);
+			/* enable decoder output to HPS */
+			debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
+			saa->boardcfg[0] = 37;
+		}
+	}
+
+	return 0;
+}
+
+static u32 palette2fmt[] = {	/* some of these YUV translations are wrong */
+	0xffffffff, 0x86000000, 0x87000000, 0x80000000, 0x8100000, 0x82000000,
+	0x83000000, 0x00000000, 0x03000000, 0x03000000, 0x0a00000, 0x03000000,
+	0x06000000, 0x00000000, 0x03000000, 0x0a000000, 0x0300000
+};
+static int bpp2fmt[4] = {
+	VIDEO_PALETTE_HI240, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB24,
+	VIDEO_PALETTE_RGB32
+};
+
+/* I wish I could find a formula to calculate these... */
+static u32 h_prescale[64] = {
+	0x10000000, 0x18040202, 0x18080000, 0x380c0606, 0x38100204, 0x38140808,
+	0x38180000, 0x381c0000, 0x3820161c, 0x38242a3b, 0x38281230, 0x382c4460,
+	0x38301040, 0x38340080, 0x38380000, 0x383c0000, 0x3840fefe, 0x3844ee9f,
+	0x3848ee9f, 0x384cee9f, 0x3850ee9f, 0x38542a3b, 0x38581230, 0x385c0000,
+	0x38600000, 0x38640000, 0x38680000, 0x386c0000, 0x38700000, 0x38740000,
+	0x38780000, 0x387c0000, 0x30800000, 0x38840000, 0x38880000, 0x388c0000,
+	0x38900000, 0x38940000, 0x38980000, 0x389c0000, 0x38a00000, 0x38a40000,
+	0x38a80000, 0x38ac0000, 0x38b00000, 0x38b40000, 0x38b80000, 0x38bc0000,
+	0x38c00000, 0x38c40000, 0x38c80000, 0x38cc0000, 0x38d00000, 0x38d40000,
+	0x38d80000, 0x38dc0000, 0x38e00000, 0x38e40000, 0x38e80000, 0x38ec0000,
+	0x38f00000, 0x38f40000, 0x38f80000, 0x38fc0000,
+};
+static u32 v_gain[64] = {
+	0x016000ff, 0x016100ff, 0x016100ff, 0x016200ff, 0x016200ff, 0x016200ff,
+	0x016200ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff,
+	0x016300ff, 0x016300ff, 0x016300ff, 0x016400ff, 0x016400ff, 0x016400ff,
+	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+	0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+};
+
+static void saa7146_set_winsize(struct saa7146 *saa)
+{
+	u32 format;
+	int offset, yacl, ysci;
+	saa->win.color_fmt = format =
+	    (saa->win.depth == 15) ? palette2fmt[VIDEO_PALETTE_RGB555] :
+	    palette2fmt[bpp2fmt[(saa->win.bpp - 1) & 3]];
+	offset = saa->win.x * saa->win.bpp + saa->win.y * saa->win.bpl;
+	saawrite(saa->win.vidadr + offset, SAA7146_BASE_EVEN1);
+	saawrite(saa->win.vidadr + offset + saa->win.bpl, SAA7146_BASE_ODD1);
+	saawrite(saa->win.bpl * 2, SAA7146_PITCH1);
+	saawrite(saa->win.vidadr + saa->win.bpl * saa->win.sheight,
+		 SAA7146_PROT_ADDR1);
+	saawrite(0, SAA7146_PAGE1);
+	saawrite(format | 0x60, SAA7146_CLIP_FORMAT_CTRL);
+	offset = (704 / (saa->win.width - 1)) & 0x3f;
+	saawrite(h_prescale[offset], SAA7146_HPS_H_PRESCALE);
+	offset = (720896 / saa->win.width) / (offset + 1);
+	saawrite((offset << 12) | 0x0c, SAA7146_HPS_H_SCALE);
+	if (CurrentMode == VIDEO_MODE_NTSC) {
+		yacl = /*(480 / saa->win.height - 1) & 0x3f */ 0;
+		ysci = 1024 - (saa->win.height * 1024 / 480);
+	} else {
+		yacl = /*(576 / saa->win.height - 1) & 0x3f */ 0;
+		ysci = 1024 - (saa->win.height * 1024 / 576);
+	}
+	saawrite((1 << 31) | (ysci << 21) | (yacl << 15), SAA7146_HPS_V_SCALE);
+	saawrite(v_gain[yacl], SAA7146_HPS_V_GAIN);
+	saawrite(((SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_HPS_V |
+		SAA7146_MC2_UPLD_HPS_H) << 16) | (SAA7146_MC2_UPLD_DMA1 |
+		SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_HPS_H), SAA7146_MC2);
+}
+
+/* clip_draw_rectangle(cm,x,y,w,h) -- handle clipping an area
+ * bitmap is fixed width, 128 bytes (1024 pixels represented)
+ * arranged most-sigificant-bit-left in 32-bit words
+ * based on saa7146 clipping hardware, it swaps bytes if LE
+ * much of this makes up for egcs brain damage -- so if you
+ * are wondering "why did he do this?" it is because the C
+ * was adjusted to generate the optimal asm output without
+ * writing non-portable __asm__ directives.
+ */
+
+static void clip_draw_rectangle(u32 *clipmap, int x, int y, int w, int h)
+{
+	register int startword, endword;
+	register u32 bitsleft, bitsright;
+	u32 *temp;
+	if (x < 0) {
+		w += x;
+		x = 0;
+	}
+	if (y < 0) {
+		h += y;
+		y = 0;
+	}
+	if (w <= 0 || h <= 0 || x > 1023 || y > 639)
+		return;		/* throw away bad clips */
+	if (x + w > 1024)
+		w = 1024 - x;
+	if (y + h > 640)
+		h = 640 - y;
+	startword = (x >> 5);
+	endword = ((x + w) >> 5);
+	bitsleft = (0xffffffff >> (x & 31));
+	bitsright = (0xffffffff << (~((x + w) - (endword << 5))));
+	temp = &clipmap[(y << 5) + startword];
+	w = endword - startword;
+	if (!w) {
+		bitsleft |= bitsright;
+		for (y = 0; y < h; y++) {
+			*temp |= bitsleft;
+			temp += 32;
+		}
+	} else {
+		for (y = 0; y < h; y++) {
+			*temp++ |= bitsleft;
+			for (x = 1; x < w; x++)
+				*temp++ = 0xffffffff;
+			*temp |= bitsright;
+			temp += (32 - w);
+		}
+	}
+}
+
+static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr)
+{
+	int i, width, height;
+	u32 *clipmap;
+
+	clipmap = saa->dmavid2;
+	if ((width = saa->win.width) > 1023)
+		width = 1023;	/* sanity check */
+	if ((height = saa->win.height) > 640)
+		height = 639;	/* sanity check */
+	if (ncr > 0) {		/* rectangles pased */
+		/* convert rectangular clips to a bitmap */
+		memset(clipmap, 0, VIDEO_CLIPMAP_SIZE);	/* clear map */
+		for (i = 0; i < ncr; i++)
+			clip_draw_rectangle(clipmap, cr[i].x, cr[i].y,
+				cr[i].width, cr[i].height);
+	}
+	/* clip against viewing window AND screen
+	   so we do not have to rely on the user program
+	 */
+	clip_draw_rectangle(clipmap, (saa->win.x + width > saa->win.swidth) ?
+		(saa->win.swidth - saa->win.x) : width, 0, 1024, 768);
+	clip_draw_rectangle(clipmap, 0,
+		(saa->win.y + height > saa->win.sheight) ?
+		(saa->win.sheight - saa->win.y) : height, 1024, 768);
+	if (saa->win.x < 0)
+		clip_draw_rectangle(clipmap, 0, 0, -saa->win.x, 768);
+	if (saa->win.y < 0)
+		clip_draw_rectangle(clipmap, 0, 0, 1024, -saa->win.y);
+}
+
+static long saa_ioctl(struct file *file,
+		     unsigned int cmd, unsigned long argl)
+{
+	struct saa7146 *saa = file->private_data;
+	void __user *arg = (void __user *)argl;
+
+	switch (cmd) {
+	case VIDIOCGCAP:
+		{
+			struct video_capability b;
+			strcpy(b.name, saa->video_dev.name);
+			b.type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY |
+				VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
+				VID_TYPE_SCALES;
+			b.channels = 1;
+			b.audios = 1;
+			b.maxwidth = 768;
+			b.maxheight = 576;
+			b.minwidth = 32;
+			b.minheight = 32;
+			if (copy_to_user(arg, &b, sizeof(b)))
+				return -EFAULT;
+			return 0;
+		}
+	case VIDIOCGPICT:
+		{
+			struct video_picture p = saa->picture;
+			if (saa->win.depth == 8)
+				p.palette = VIDEO_PALETTE_HI240;
+			if (saa->win.depth == 15)
+				p.palette = VIDEO_PALETTE_RGB555;
+			if (saa->win.depth == 16)
+				p.palette = VIDEO_PALETTE_RGB565;
+			if (saa->win.depth == 24)
+				p.palette = VIDEO_PALETTE_RGB24;
+			if (saa->win.depth == 32)
+				p.palette = VIDEO_PALETTE_RGB32;
+			if (copy_to_user(arg, &p, sizeof(p)))
+				return -EFAULT;
+			return 0;
+		}
+	case VIDIOCSPICT:
+		{
+			struct video_picture p;
+			u32 format;
+			if (copy_from_user(&p, arg, sizeof(p)))
+				return -EFAULT;
+			if (p.palette < ARRAY_SIZE(palette2fmt)) {
+				format = palette2fmt[p.palette];
+				saa->win.color_fmt = format;
+				saawrite(format | 0x60,
+					SAA7146_CLIP_FORMAT_CTRL);
+			}
+			saawrite(((p.brightness & 0xff00) << 16) |
+				((p.contrast & 0xfe00) << 7) |
+				((p.colour & 0xfe00) >> 9), SAA7146_BCS_CTRL);
+			saa->picture = p;
+			/* upload changed registers */
+			saawrite(((SAA7146_MC2_UPLD_HPS_H |
+				SAA7146_MC2_UPLD_HPS_V) << 16) |
+				SAA7146_MC2_UPLD_HPS_H |
+				SAA7146_MC2_UPLD_HPS_V, SAA7146_MC2);
+			return 0;
+		}
+	case VIDIOCSWIN:
+		{
+			struct video_window vw;
+			struct video_clip *vcp = NULL;
+
+			if (copy_from_user(&vw, arg, sizeof(vw)))
+				return -EFAULT;
+
+			/* stop capture */
+			if (vw.flags || vw.width < 16 || vw.height < 16) {
+				saawrite((SAA7146_MC1_TR_E_1 << 16),
+					SAA7146_MC1);
+				return -EINVAL;
+			}
+			/* 32-bit align start and adjust width */
+			if (saa->win.bpp < 4) {
+				int i = vw.x;
+				vw.x = (vw.x + 3) & ~3;
+				i = vw.x - i;
+				vw.width -= i;
+			}
+			saa->win.x = vw.x;
+			saa->win.y = vw.y;
+			saa->win.width = vw.width;
+			if (saa->win.width > 768)
+				saa->win.width = 768;
+			saa->win.height = vw.height;
+			if (CurrentMode == VIDEO_MODE_NTSC) {
+				if (saa->win.height > 480)
+					saa->win.height = 480;
+			} else {
+				if (saa->win.height > 576)
+					saa->win.height = 576;
+			}
+
+			/* stop capture */
+			saawrite((SAA7146_MC1_TR_E_1 << 16), SAA7146_MC1);
+			saa7146_set_winsize(saa);
+
+			/*
+			 *    Do any clips.
+			 */
+			if (vw.clipcount < 0) {
+				if (copy_from_user(saa->dmavid2, vw.clips,
+						VIDEO_CLIPMAP_SIZE))
+					return -EFAULT;
+			} else if (vw.clipcount > 16384) {
+				return -EINVAL;
+			} else if (vw.clipcount > 0) {
+				vcp = vmalloc(sizeof(struct video_clip) *
+					vw.clipcount);
+				if (vcp == NULL)
+					return -ENOMEM;
+				if (copy_from_user(vcp, vw.clips,
+						sizeof(struct video_clip) *
+						vw.clipcount)) {
+					vfree(vcp);
+					return -EFAULT;
+				}
+			} else	/* nothing clipped */
+				memset(saa->dmavid2, 0, VIDEO_CLIPMAP_SIZE);
+
+			make_clip_tab(saa, vcp, vw.clipcount);
+			if (vw.clipcount > 0)
+				vfree(vcp);
+
+			/* start capture & clip dma if we have an address */
+			if ((saa->cap & 3) && saa->win.vidadr != 0)
+				saawrite(((SAA7146_MC1_TR_E_1 |
+					SAA7146_MC1_TR_E_2) << 16) | 0xffff,
+					SAA7146_MC1);
+			return 0;
+		}
+	case VIDIOCGWIN:
+		{
+			struct video_window vw;
+			vw.x = saa->win.x;
+			vw.y = saa->win.y;
+			vw.width = saa->win.width;
+			vw.height = saa->win.height;
+			vw.chromakey = 0;
+			vw.flags = 0;
+			if (copy_to_user(arg, &vw, sizeof(vw)))
+				return -EFAULT;
+			return 0;
+		}
+	case VIDIOCCAPTURE:
+		{
+			int v;
+			if (copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if (v == 0) {
+				saa->cap &= ~1;
+				saawrite((SAA7146_MC1_TR_E_1 << 16),
+					SAA7146_MC1);
+			} else {
+				if (saa->win.vidadr == 0 || saa->win.width == 0
+						|| saa->win.height == 0)
+					return -EINVAL;
+				saa->cap |= 1;
+				saawrite((SAA7146_MC1_TR_E_1 << 16) | 0xffff,
+					SAA7146_MC1);
+			}
+			return 0;
+		}
+	case VIDIOCGFBUF:
+		{
+			struct video_buffer v;
+			v.base = (void *)saa->win.vidadr;
+			v.height = saa->win.sheight;
+			v.width = saa->win.swidth;
+			v.depth = saa->win.depth;
+			v.bytesperline = saa->win.bpl;
+			if (copy_to_user(arg, &v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+
+		}
+	case VIDIOCSFBUF:
+		{
+			struct video_buffer v;
+			if (!capable(CAP_SYS_ADMIN))
+				return -EPERM;
+			if (copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if (v.depth != 8 && v.depth != 15 && v.depth != 16 &&
+			    v.depth != 24 && v.depth != 32 && v.width > 16 &&
+			    v.height > 16 && v.bytesperline > 16)
+				return -EINVAL;
+			if (v.base)
+				saa->win.vidadr = (unsigned long)v.base;
+			saa->win.sheight = v.height;
+			saa->win.swidth = v.width;
+			saa->win.bpp = ((v.depth + 7) & 0x38) / 8;
+			saa->win.depth = v.depth;
+			saa->win.bpl = v.bytesperline;
+
+			DEBUG(printk("Display at %p is %d by %d, bytedepth %d, "
+					"bpl %d\n", v.base, v.width, v.height,
+					saa->win.bpp, saa->win.bpl));
+			saa7146_set_winsize(saa);
+			return 0;
+		}
+	case VIDIOCKEY:
+		{
+			/* Will be handled higher up .. */
+			return 0;
+		}
+
+	case VIDIOCGAUDIO:
+		{
+			struct video_audio v;
+			v = saa->audio_dev;
+			v.flags &= ~(VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
+			v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
+			strcpy(v.name, "MPEG");
+			v.mode = VIDEO_SOUND_STEREO;
+			if (copy_to_user(arg, &v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+	case VIDIOCSAUDIO:
+		{
+			struct video_audio v;
+			int i;
+			if (copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			i = (~(v.volume >> 8)) & 0xff;
+			if (!HaveCS4341) {
+				if (v.flags & VIDEO_AUDIO_MUTE)
+					debiwrite(saa, debNormal,
+						IBM_MP2_FRNT_ATTEN, 0xffff, 2);
+				if (!(v.flags & VIDEO_AUDIO_MUTE))
+					debiwrite(saa, debNormal,
+						IBM_MP2_FRNT_ATTEN, 0x0000, 2);
+				if (v.flags & VIDEO_AUDIO_VOLUME)
+					debiwrite(saa, debNormal,
+						IBM_MP2_FRNT_ATTEN,
+						(i << 8) | i, 2);
+			} else {
+				if (v.flags & VIDEO_AUDIO_MUTE)
+					cs4341_setlevel(saa, 0xff, 0xff);
+				if (!(v.flags & VIDEO_AUDIO_MUTE))
+					cs4341_setlevel(saa, 0, 0);
+				if (v.flags & VIDEO_AUDIO_VOLUME)
+					cs4341_setlevel(saa, i, i);
+			}
+			saa->audio_dev = v;
+			return 0;
+		}
+
+	case VIDIOCGUNIT:
+		{
+			struct video_unit vu;
+			vu.video = saa->video_dev.minor;
+			vu.vbi = VIDEO_NO_UNIT;
+			vu.radio = VIDEO_NO_UNIT;
+			vu.audio = VIDEO_NO_UNIT;
+			vu.teletext = VIDEO_NO_UNIT;
+			if (copy_to_user(arg, &vu, sizeof(vu)))
+				return -EFAULT;
+			return 0;
+		}
+	case VIDIOCSPLAYMODE:
+		{
+			struct video_play_mode pmode;
+			if (copy_from_user((void *)&pmode, arg,
+					sizeof(struct video_play_mode)))
+				return -EFAULT;
+			switch (pmode.mode) {
+			case VID_PLAY_VID_OUT_MODE:
+				if (pmode.p1 != VIDEO_MODE_NTSC &&
+						pmode.p1 != VIDEO_MODE_PAL)
+					return -EINVAL;
+				set_out_format(saa, pmode.p1);
+				return 0;
+			case VID_PLAY_GENLOCK:
+				debiwrite(saa, debNormal, XILINX_CTL0,
+					pmode.p1 ? 0x8000 : 0x8080, 2);
+				if (NewCard)
+					set_genlock_offset(saa, pmode.p2);
+				return 0;
+			case VID_PLAY_NORMAL:
+				debiwrite(saa, debNormal,
+					IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+				ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
+				saa->playmode = pmode.mode;
+				return 0;
+			case VID_PLAY_PAUSE:
+				/* IBM removed the PAUSE command */
+				/* they say use SINGLE_FRAME now */
+			case VID_PLAY_SINGLE_FRAME:
+				ibm_send_command(saa, IBM_MP2_SINGLE_FRAME,0,0);
+				if (saa->playmode == pmode.mode) {
+					debiwrite(saa, debNormal,
+						IBM_MP2_CHIP_CONTROL,
+						ChipControl, 2);
+				}
+				saa->playmode = pmode.mode;
+				return 0;
+			case VID_PLAY_FAST_FORWARD:
+				ibm_send_command(saa, IBM_MP2_FAST_FORWARD,0,0);
+				saa->playmode = pmode.mode;
+				return 0;
+			case VID_PLAY_SLOW_MOTION:
+				ibm_send_command(saa, IBM_MP2_SLOW_MOTION,
+					pmode.p1, 0);
+				saa->playmode = pmode.mode;
+				return 0;
+			case VID_PLAY_IMMEDIATE_NORMAL:
+				/* ensure transfers resume */
+				debiwrite(saa, debNormal,
+					IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+				ibm_send_command(saa, IBM_MP2_IMED_NORM_PLAY,
+					0, 0);
+				saa->playmode = VID_PLAY_NORMAL;
+				return 0;
+			case VID_PLAY_SWITCH_CHANNELS:
+				saa->audhead = saa->audtail = 0;
+				saa->vidhead = saa->vidtail = 0;
+				ibm_send_command(saa, IBM_MP2_FREEZE_FRAME,0,1);
+				ibm_send_command(saa, IBM_MP2_RESET_AUD_RATE,
+					0, 1);
+				debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
+					0, 2);
+				ibm_send_command(saa, IBM_MP2_CHANNEL_SWITCH,
+					0, 1);
+				debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
+					ChipControl, 2);
+				ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
+				saa->playmode = VID_PLAY_NORMAL;
+				return 0;
+			case VID_PLAY_FREEZE_FRAME:
+				ibm_send_command(saa, IBM_MP2_FREEZE_FRAME,0,0);
+				saa->playmode = pmode.mode;
+				return 0;
+			case VID_PLAY_STILL_MODE:
+				ibm_send_command(saa, IBM_MP2_SET_STILL_MODE,
+					0, 0);
+				saa->playmode = pmode.mode;
+				return 0;
+			case VID_PLAY_MASTER_MODE:
+				if (pmode.p1 == VID_PLAY_MASTER_NONE)
+					saa->boardcfg[1] = 0x13;
+				else if (pmode.p1 == VID_PLAY_MASTER_VIDEO)
+					saa->boardcfg[1] = 0x23;
+				else if (pmode.p1 == VID_PLAY_MASTER_AUDIO)
+					saa->boardcfg[1] = 0x43;
+				else
+					return -EINVAL;
+				debiwrite(saa, debNormal,
+					  IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+				return 0;
+			case VID_PLAY_ACTIVE_SCANLINES:
+				if (CurrentMode == VIDEO_MODE_PAL) {
+					if (pmode.p1 < 1 || pmode.p2 > 625)
+						return -EINVAL;
+					saa->boardcfg[5] = pmode.p1;
+					saa->boardcfg[55] = (pmode.p1 +
+						(pmode.p2 / 2) - 1) & 0xff;
+				} else {
+					if (pmode.p1 < 4 || pmode.p2 > 525)
+						return -EINVAL;
+					saa->boardcfg[4] = pmode.p1;
+					saa->boardcfg[54] = (pmode.p1 +
+						(pmode.p2 / 2) - 4) & 0xff;
+				}
+				set_out_format(saa, CurrentMode);
+			case VID_PLAY_RESET:
+				return do_ibm_reset(saa);
+			case VID_PLAY_END_MARK:
+				if (saa->endmarktail < saa->endmarkhead) {
+					if (saa->endmarkhead -
+							saa->endmarktail < 2)
+						return -ENOSPC;
+				} else if (saa->endmarkhead <=saa->endmarktail){
+					if (saa->endmarktail - saa->endmarkhead
+							> (MAX_MARKS - 2))
+						return -ENOSPC;
+				} else
+					return -ENOSPC;
+				saa->endmark[saa->endmarktail] = saa->audtail;
+				saa->endmarktail++;
+				if (saa->endmarktail >= MAX_MARKS)
+					saa->endmarktail = 0;
+			}
+			return -EINVAL;
+		}
+	case VIDIOCSWRITEMODE:
+		{
+			int mode;
+			if (copy_from_user((void *)&mode, arg, sizeof(int)))
+				return -EFAULT;
+			if (mode == VID_WRITE_MPEG_AUD ||
+					mode == VID_WRITE_MPEG_VID ||
+					mode == VID_WRITE_CC ||
+					mode == VID_WRITE_TTX ||
+					mode == VID_WRITE_OSD) {
+				saa->writemode = mode;
+				return 0;
+			}
+			return -EINVAL;
+		}
+	case VIDIOCSMICROCODE:
+		{
+			struct video_code ucode;
+			__u8 *udata;
+			int i;
+			if (copy_from_user(&ucode, arg, sizeof(ucode)))
+				return -EFAULT;
+			if (ucode.datasize > 65536 || ucode.datasize < 1024 ||
+					strncmp(ucode.loadwhat, "dec", 3))
+				return -EINVAL;
+			if ((udata = vmalloc(ucode.datasize)) == NULL)
+				return -ENOMEM;
+			if (copy_from_user(udata, ucode.data, ucode.datasize)) {
+				vfree(udata);
+				return -EFAULT;
+			}
+			ucode.data = udata;
+			if (!strncmp(ucode.loadwhat, "decoder.aud", 11) ||
+				!strncmp(ucode.loadwhat, "decoder.vid", 11))
+				i = initialize_ibmmpeg2(&ucode);
+			else
+				i = initialize_fpga(&ucode);
+			vfree(udata);
+			if (i)
+				return -EINVAL;
+			return 0;
+
+		}
+	case VIDIOCGCHAN:	/* this makes xawtv happy */
+		{
+			struct video_channel v;
+			if (copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			v.flags = VIDEO_VC_AUDIO;
+			v.tuners = 0;
+			v.type = VID_TYPE_MPEG_DECODER;
+			v.norm = CurrentMode;
+			strcpy(v.name, "MPEG2");
+			if (copy_to_user(arg, &v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+	case VIDIOCSCHAN:	/* this makes xawtv happy */
+		{
+			struct video_channel v;
+			if (copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			/* do nothing */
+			return 0;
+		}
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int saa_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct saa7146 *saa = file->private_data;
+	printk(KERN_DEBUG "stradis%d: saa_mmap called\n", saa->nr);
+	return -EINVAL;
+}
+
+static ssize_t saa_read(struct file *file, char __user * buf,
+	size_t count, loff_t * ppos)
+{
+	return -EINVAL;
+}
+
+static ssize_t saa_write(struct file *file, const char __user * buf,
+	size_t count, loff_t * ppos)
+{
+	struct saa7146 *saa = file->private_data;
+	unsigned long todo = count;
+	int blocksize, split;
+	unsigned long flags;
+
+	while (todo > 0) {
+		if (saa->writemode == VID_WRITE_MPEG_AUD) {
+			spin_lock_irqsave(&saa->lock, flags);
+			if (saa->audhead <= saa->audtail)
+				blocksize = 65536 -
+					(saa->audtail - saa->audhead);
+			else
+				blocksize = saa->audhead - saa->audtail;
+			spin_unlock_irqrestore(&saa->lock, flags);
+			if (blocksize < 16384) {
+				saawrite(SAA7146_PSR_DEBI_S |
+					SAA7146_PSR_PIN1, SAA7146_IER);
+				saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
+				/* wait for buffer space to open */
+				interruptible_sleep_on(&saa->audq);
+			}
+			spin_lock_irqsave(&saa->lock, flags);
+			if (saa->audhead <= saa->audtail) {
+				blocksize = 65536 -
+					(saa->audtail - saa->audhead);
+				split = 65536 - saa->audtail;
+			} else {
+				blocksize = saa->audhead - saa->audtail;
+				split = 65536;
+			}
+			spin_unlock_irqrestore(&saa->lock, flags);
+			blocksize--;
+			if (blocksize > todo)
+				blocksize = todo;
+			/* double check that we really have space */
+			if (!blocksize)
+				return -ENOSPC;
+			if (split < blocksize) {
+				if (copy_from_user(saa->audbuf +
+						saa->audtail, buf, split))
+					return -EFAULT;
+				buf += split;
+				todo -= split;
+				blocksize -= split;
+				saa->audtail = 0;
+			}
+			if (copy_from_user(saa->audbuf + saa->audtail, buf,
+					blocksize))
+				return -EFAULT;
+			saa->audtail += blocksize;
+			todo -= blocksize;
+			buf += blocksize;
+			saa->audtail &= 0xffff;
+		} else if (saa->writemode == VID_WRITE_MPEG_VID) {
+			spin_lock_irqsave(&saa->lock, flags);
+			if (saa->vidhead <= saa->vidtail)
+				blocksize = 524288 -
+					(saa->vidtail - saa->vidhead);
+			else
+				blocksize = saa->vidhead - saa->vidtail;
+			spin_unlock_irqrestore(&saa->lock, flags);
+			if (blocksize < 65536) {
+				saawrite(SAA7146_PSR_DEBI_S |
+					SAA7146_PSR_PIN1, SAA7146_IER);
+				saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
+				/* wait for buffer space to open */
+				interruptible_sleep_on(&saa->vidq);
+			}
+			spin_lock_irqsave(&saa->lock, flags);
+			if (saa->vidhead <= saa->vidtail) {
+				blocksize = 524288 -
+					(saa->vidtail - saa->vidhead);
+				split = 524288 - saa->vidtail;
+			} else {
+				blocksize = saa->vidhead - saa->vidtail;
+				split = 524288;
+			}
+			spin_unlock_irqrestore(&saa->lock, flags);
+			blocksize--;
+			if (blocksize > todo)
+				blocksize = todo;
+			/* double check that we really have space */
+			if (!blocksize)
+				return -ENOSPC;
+			if (split < blocksize) {
+				if (copy_from_user(saa->vidbuf +
+						saa->vidtail, buf, split))
+					return -EFAULT;
+				buf += split;
+				todo -= split;
+				blocksize -= split;
+				saa->vidtail = 0;
+			}
+			if (copy_from_user(saa->vidbuf + saa->vidtail, buf,
+					blocksize))
+				return -EFAULT;
+			saa->vidtail += blocksize;
+			todo -= blocksize;
+			buf += blocksize;
+			saa->vidtail &= 0x7ffff;
+		} else if (saa->writemode == VID_WRITE_OSD) {
+			if (count > 131072)
+				return -ENOSPC;
+			if (copy_from_user(saa->osdbuf, buf, count))
+				return -EFAULT;
+			buf += count;
+			saa->osdhead = 0;
+			saa->osdtail = count;
+			debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR, 0, 2);
+			debiwrite(saa, debNormal, IBM_MP2_OSD_LINK_ADDR, 0, 2);
+			debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00d, 2);
+			debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+				debiread(saa, debNormal,
+					IBM_MP2_DISP_MODE, 2) | 1, 2);
+			/* trigger osd data transfer */
+			saawrite(SAA7146_PSR_DEBI_S |
+				 SAA7146_PSR_PIN1, SAA7146_IER);
+			saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
+		}
+	}
+	return count;
+}
+
+static int saa_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct saa7146 *saa = container_of(vdev, struct saa7146, video_dev);
+
+	lock_kernel();
+	file->private_data = saa;
+
+	saa->user++;
+	if (saa->user > 1) {
+		unlock_kernel();
+		return 0;	/* device open already, don't reset */
+	}
+	saa->writemode = VID_WRITE_MPEG_VID;	/* default to video */
+	unlock_kernel();
+	return 0;
+}
+
+static int saa_release(struct file *file)
+{
+	struct saa7146 *saa = file->private_data;
+	saa->user--;
+
+	if (saa->user > 0)	/* still someone using device */
+		return 0;
+	saawrite(0x007f0000, SAA7146_MC1);	/* stop all overlay dma */
+	return 0;
+}
+
+static const struct v4l2_file_operations saa_fops = {
+	.owner = THIS_MODULE,
+	.open = saa_open,
+	.release = saa_release,
+	.ioctl = saa_ioctl,
+	.read = saa_read,
+	.write = saa_write,
+	.mmap = saa_mmap,
+};
+
+/* template for video_device-structure */
+static struct video_device saa_template = {
+	.name = "SAA7146A",
+	.fops = &saa_fops,
+	.release = video_device_release_empty,
+};
+
+static int __devinit configure_saa7146(struct pci_dev *pdev, int num)
+{
+	int retval;
+	struct saa7146 *saa = pci_get_drvdata(pdev);
+
+	saa->endmarkhead = saa->endmarktail = 0;
+	saa->win.x = saa->win.y = 0;
+	saa->win.width = saa->win.cropwidth = 720;
+	saa->win.height = saa->win.cropheight = 480;
+	saa->win.cropx = saa->win.cropy = 0;
+	saa->win.bpp = 2;
+	saa->win.depth = 16;
+	saa->win.color_fmt = palette2fmt[VIDEO_PALETTE_RGB565];
+	saa->win.bpl = 1024 * saa->win.bpp;
+	saa->win.swidth = 1024;
+	saa->win.sheight = 768;
+	saa->picture.brightness = 32768;
+	saa->picture.contrast = 38768;
+	saa->picture.colour = 32768;
+	saa->cap = 0;
+	saa->nr = num;
+	saa->playmode = VID_PLAY_NORMAL;
+	memset(saa->boardcfg, 0, 64);	/* clear board config area */
+	saa->saa7146_mem = NULL;
+	saa->dmavid1 = saa->dmavid2 = saa->dmavid3 = saa->dmaa1in =
+	    saa->dmaa1out = saa->dmaa2in = saa->dmaa2out =
+	    saa->pagevid1 = saa->pagevid2 = saa->pagevid3 = saa->pagea1in =
+	    saa->pagea1out = saa->pagea2in = saa->pagea2out =
+	    saa->pagedebi = saa->dmaRPS1 = saa->dmaRPS2 = saa->pageRPS1 =
+	    saa->pageRPS2 = NULL;
+	saa->audbuf = saa->vidbuf = saa->osdbuf = saa->dmadebi = NULL;
+	saa->audhead = saa->vidtail = 0;
+
+	init_waitqueue_head(&saa->i2cq);
+	init_waitqueue_head(&saa->audq);
+	init_waitqueue_head(&saa->debiq);
+	init_waitqueue_head(&saa->vidq);
+	spin_lock_init(&saa->lock);
+
+	retval = pci_enable_device(pdev);
+	if (retval) {
+		dev_err(&pdev->dev, "%d: pci_enable_device failed!\n", num);
+		goto err;
+	}
+
+	saa->id = pdev->device;
+	saa->irq = pdev->irq;
+	saa->saa7146_adr = pci_resource_start(pdev, 0);
+	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &saa->revision);
+
+	saa->saa7146_mem = ioremap(saa->saa7146_adr, 0x200);
+	if (saa->saa7146_mem == NULL) {
+		dev_err(&pdev->dev, "%d: ioremap failed!\n", num);
+		retval = -EIO;
+		goto err;
+	}
+
+	memcpy(&saa->video_dev, &saa_template, sizeof(saa_template));
+	saawrite(0, SAA7146_IER);	/* turn off all interrupts */
+
+	retval = request_irq(saa->irq, saa7146_irq, IRQF_SHARED | IRQF_DISABLED,
+		"stradis", saa);
+	if (retval == -EINVAL)
+		dev_err(&pdev->dev, "%d: Bad irq number or handler\n", num);
+	else if (retval == -EBUSY)
+		dev_err(&pdev->dev, "%d: IRQ %ld busy, change your PnP config "
+			"in BIOS\n", num, saa->irq);
+	if (retval < 0)
+		goto errio;
+
+	pci_set_master(pdev);
+	retval = video_register_device(&saa->video_dev, VFL_TYPE_GRABBER,
+		video_nr);
+	if (retval < 0) {
+		dev_err(&pdev->dev, "%d: error in registering video device!\n",
+			num);
+		goto errio;
+	}
+
+	return 0;
+errio:
+	iounmap(saa->saa7146_mem);
+err:
+	return retval;
+}
+
+static int __devinit init_saa7146(struct pci_dev *pdev)
+{
+	struct saa7146 *saa = pci_get_drvdata(pdev);
+
+	saa->user = 0;
+	/* reset the saa7146 */
+	saawrite(0xffff0000, SAA7146_MC1);
+	mdelay(5);
+	/* enable debi and i2c transfers and pins */
+	saawrite(((SAA7146_MC1_EDP | SAA7146_MC1_EI2C |
+		   SAA7146_MC1_TR_E_DEBI) << 16) | 0xffff, SAA7146_MC1);
+	/* ensure proper state of chip */
+	saawrite(0x00000000, SAA7146_PAGE1);
+	saawrite(0x00f302c0, SAA7146_NUM_LINE_BYTE1);
+	saawrite(0x00000000, SAA7146_PAGE2);
+	saawrite(0x01400080, SAA7146_NUM_LINE_BYTE2);
+	saawrite(0x00000000, SAA7146_DD1_INIT);
+	saawrite(0x00000000, SAA7146_DD1_STREAM_B);
+	saawrite(0x00000000, SAA7146_DD1_STREAM_A);
+	saawrite(0x00000000, SAA7146_BRS_CTRL);
+	saawrite(0x80400040, SAA7146_BCS_CTRL);
+	saawrite(0x0000e000 /*| (1<<29) */ , SAA7146_HPS_CTRL);
+	saawrite(0x00000060, SAA7146_CLIP_FORMAT_CTRL);
+	saawrite(0x00000000, SAA7146_ACON1);
+	saawrite(0x00000000, SAA7146_ACON2);
+	saawrite(0x00000600, SAA7146_I2C_STATUS);
+	saawrite(((SAA7146_MC2_UPLD_D1_B | SAA7146_MC2_UPLD_D1_A |
+		SAA7146_MC2_UPLD_BRS | SAA7146_MC2_UPLD_HPS_H |
+		SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_DMA2 |
+		SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_I2C) << 16) | 0xffff,
+		SAA7146_MC2);
+	/* setup arbitration control registers */
+	saawrite(0x1412121a, SAA7146_PCI_BT_V1);
+
+	/* allocate 32k dma buffer + 4k for page table */
+	if ((saa->dmadebi = kmalloc(32768 + 4096, GFP_KERNEL)) == NULL) {
+		dev_err(&pdev->dev, "%d: debi kmalloc failed\n", saa->nr);
+		goto err;
+	}
+#if 0
+	saa->pagedebi = saa->dmadebi + 32768;	/* top 4k is for mmu */
+	saawrite(virt_to_bus(saa->pagedebi) /*|0x800 */ , SAA7146_DEBI_PAGE);
+	for (i = 0; i < 12; i++)	/* setup mmu page table */
+		saa->pagedebi[i] = virt_to_bus((saa->dmadebi + i * 4096));
+#endif
+	saa->audhead = saa->vidhead = saa->osdhead = 0;
+	saa->audtail = saa->vidtail = saa->osdtail = 0;
+	if (saa->vidbuf == NULL && (saa->vidbuf = vmalloc(524288)) == NULL) {
+		dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
+		goto err;
+	}
+	if (saa->audbuf == NULL && (saa->audbuf = vmalloc(65536)) == NULL) {
+		dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
+		goto errfree;
+	}
+	if (saa->osdbuf == NULL && (saa->osdbuf = vmalloc(131072)) == NULL) {
+		dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
+		goto errfree;
+	}
+	/* allocate 81920 byte buffer for clipping */
+	if ((saa->dmavid2 = kzalloc(VIDEO_CLIPMAP_SIZE, GFP_KERNEL)) == NULL) {
+		dev_err(&pdev->dev, "%d: clip kmalloc failed\n", saa->nr);
+		goto errfree;
+	}
+	/* setup clipping registers */
+	saawrite(virt_to_bus(saa->dmavid2), SAA7146_BASE_EVEN2);
+	saawrite(virt_to_bus(saa->dmavid2) + 128, SAA7146_BASE_ODD2);
+	saawrite(virt_to_bus(saa->dmavid2) + VIDEO_CLIPMAP_SIZE,
+		 SAA7146_PROT_ADDR2);
+	saawrite(256, SAA7146_PITCH2);
+	saawrite(4, SAA7146_PAGE2);	/* dma direction: read, no byteswap */
+	saawrite(((SAA7146_MC2_UPLD_DMA2) << 16) | SAA7146_MC2_UPLD_DMA2,
+		 SAA7146_MC2);
+	I2CBusScan(saa);
+
+	return 0;
+errfree:
+	vfree(saa->osdbuf);
+	vfree(saa->audbuf);
+	vfree(saa->vidbuf);
+	saa->audbuf = saa->osdbuf = saa->vidbuf = NULL;
+err:
+	return -ENOMEM;
+}
+
+static void stradis_release_saa(struct pci_dev *pdev)
+{
+	u8 command;
+	struct saa7146 *saa = pci_get_drvdata(pdev);
+
+	/* turn off all capturing, DMA and IRQs */
+	saawrite(0xffff0000, SAA7146_MC1);	/* reset chip */
+	saawrite(0, SAA7146_MC2);
+	saawrite(0, SAA7146_IER);
+	saawrite(0xffffffffUL, SAA7146_ISR);
+
+	/* disable PCI bus-mastering */
+	pci_read_config_byte(pdev, PCI_COMMAND, &command);
+	command &= ~PCI_COMMAND_MASTER;
+	pci_write_config_byte(pdev, PCI_COMMAND, command);
+
+	/* unmap and free memory */
+	saa->audhead = saa->audtail = saa->osdhead = 0;
+	saa->vidhead = saa->vidtail = saa->osdtail = 0;
+	vfree(saa->vidbuf);
+	vfree(saa->audbuf);
+	vfree(saa->osdbuf);
+	kfree(saa->dmavid2);
+	saa->audbuf = saa->vidbuf = saa->osdbuf = NULL;
+	saa->dmavid2 = NULL;
+	kfree(saa->dmadebi);
+	kfree(saa->dmavid1);
+	kfree(saa->dmavid3);
+	kfree(saa->dmaa1in);
+	kfree(saa->dmaa1out);
+	kfree(saa->dmaa2in);
+	kfree(saa->dmaa2out);
+	kfree(saa->dmaRPS1);
+	kfree(saa->dmaRPS2);
+	free_irq(saa->irq, saa);
+	if (saa->saa7146_mem)
+		iounmap(saa->saa7146_mem);
+	if (video_is_registered(&saa->video_dev))
+		video_unregister_device(&saa->video_dev);
+}
+
+static int __devinit stradis_probe(struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	int retval = -EINVAL;
+
+	if (saa_num >= SAA7146_MAX)
+		goto err;
+
+	if (!pdev->subsystem_vendor)
+		dev_info(&pdev->dev, "%d: rev1 decoder\n", saa_num);
+	else
+		dev_info(&pdev->dev, "%d: SDM2xx found\n", saa_num);
+
+	pci_set_drvdata(pdev, &saa7146s[saa_num]);
+
+	retval = configure_saa7146(pdev, saa_num);
+	if (retval) {
+		dev_err(&pdev->dev, "%d: error in configuring\n", saa_num);
+		goto err;
+	}
+
+	if (init_saa7146(pdev) < 0) {
+		dev_err(&pdev->dev, "%d: error in initialization\n", saa_num);
+		retval = -EIO;
+		goto errrel;
+	}
+
+	saa_num++;
+
+	return 0;
+errrel:
+	stradis_release_saa(pdev);
+err:
+	return retval;
+}
+
+static void __devexit stradis_remove(struct pci_dev *pdev)
+{
+	stradis_release_saa(pdev);
+}
+
+static struct pci_device_id stradis_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146) },
+	{ 0 }
+};
+
+
+static struct pci_driver stradis_driver = {
+	.name = "stradis",
+	.id_table = stradis_pci_tbl,
+	.probe = stradis_probe,
+	.remove = __devexit_p(stradis_remove)
+};
+
+static int __init stradis_init(void)
+{
+	int retval;
+
+	saa_num = 0;
+
+	retval = pci_register_driver(&stradis_driver);
+	if (retval)
+		printk(KERN_ERR "stradis: Unable to register pci driver.\n");
+
+	return retval;
+}
+
+static void __exit stradis_exit(void)
+{
+	pci_unregister_driver(&stradis_driver);
+	printk(KERN_INFO "stradis: module cleanup complete\n");
+}
+
+module_init(stradis_init);
+module_exit(stradis_exit);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2010-09-16  1:05 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <cover.1284597566.git.mchehab@redhat.com>
2010-09-16  0:56 ` [PATCH 1/8] V4L/DVB: radio-si470x: remove the BKL lock used internally at the driver Mauro Carvalho Chehab
2010-09-16  0:56 ` [PATCH 3/8] V4L/DVB: bttv-driver: document functions using mutex_lock Mauro Carvalho Chehab
2010-09-16  0:56 ` [PATCH 4/8] V4L/DVB: bttv: fix driver lock and remove explicit calls to BKL Mauro Carvalho Chehab
2010-09-16  0:56 ` [PATCH 5/8] V4L/DVB: bttv: use unlocked ioctl Mauro Carvalho Chehab
2010-09-16  0:56 ` [PATCH 2/8] V4L/DVB: radio-si470x: " Mauro Carvalho Chehab
2010-09-16  0:56 ` [PATCH 6/8] V4L/DVB: cx88: Remove BKL Mauro Carvalho Chehab
2010-09-16  0:56 ` [PATCH 8/8] V4L/DVB: Deprecate stradis driver Mauro Carvalho Chehab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).