Exemple #1
0
void em8300_dicom_setBCS(struct em8300_s *em, int brightness, int contrast, int saturation)
{
	int luma_factor, luma_offset, chroma_factor;
	em->dicom_brightness = brightness;
	em->dicom_contrast = contrast;
	em->dicom_saturation = saturation;

	if (read_ucregister(DICOM_UpdateFlag) == 1) {
		write_ucregister(DICOM_UpdateFlag, 0);
		udelay(1);
	}

	luma_factor = (contrast * 127 + 500) / 1000;
	luma_offset = 128 - 2 * luma_factor + ((brightness - 500) * 255 + 500) / 1000;
	if (luma_offset < -128)
		luma_offset = -128;
	if (luma_offset > 127)
		luma_offset = 127;
	chroma_factor = (luma_factor * saturation + 250) / 500;
	if (chroma_factor > 127)
		chroma_factor = 127;

	write_ucregister(DICOM_BCSLuma,
			 ((luma_factor & 255) << 8) | (luma_offset & 255));
	write_ucregister(DICOM_BCSChroma,
			 ((chroma_factor & 255) << 8) | (chroma_factor & 255));

	write_ucregister(DICOM_UpdateFlag, 1);
}
static int snd_em8300_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
	em8300_alsa_t *em8300_alsa = snd_pcm_substream_chip(substream);
	struct em8300_s *em = em8300_alsa->em;
//	snd_pcm_runtime_t *runtime = substream->runtime;
//	printk("em8300-%d: snd_em8300_pcm_trigger(%d) called.\n", em->instance, cmd);
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
		em8300_alsa->indirect.hw_io =
		em8300_alsa->indirect.hw_data =
			((read_ucregister(MA_Rdptr_Hi) << 16)
			| read_ucregister(MA_Rdptr)) & ~3;
		snd_em8300_pcm_ack(substream);
		em->irqmask |= IRQSTATUS_AUDIO_FIFO;
		write_ucregister(Q_IrqMask, em->irqmask);
		mpegaudio_command(em, MACOMMAND_PLAY);
		break;
	case SNDRV_PCM_TRIGGER_STOP:
		em->irqmask &= ~IRQSTATUS_AUDIO_FIFO;
		write_ucregister(Q_IrqMask, em->irqmask);
		mpegaudio_command(em, MACOMMAND_STOP);
		break;
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		mpegaudio_command(em, MACOMMAND_PAUSE);
		break;
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		mpegaudio_command(em, MACOMMAND_PLAY);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}
static int snd_em8300_playback_open(struct snd_pcm_substream *substream)
{
	em8300_alsa_t *em8300_alsa = snd_pcm_substream_chip(substream);
	struct em8300_s *em = em8300_alsa->em;
	struct snd_pcm_runtime *runtime = substream->runtime;

	if (substream->pcm->device == EM8300_ALSA_ANALOG_DEVICENUM)
		snd_em8300_playback_hw.formats = SNDRV_PCM_FMTBIT_S16_BE;
	else
		snd_em8300_playback_hw.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE;
	runtime->hw = snd_em8300_playback_hw;

//	printk("em8300-%d: snd_em8300_playback_open called.\n", em->instance);

	em->clockgen &= ~CLOCKGEN_OUTMASK;
	if (substream->pcm->device == EM8300_ALSA_ANALOG_DEVICENUM)
		em->clockgen |= CLOCKGEN_ANALOGOUT;
	else
		em->clockgen |= CLOCKGEN_DIGITALOUT;
	em8300_clockgen_write(em, em->clockgen);

	if (substream->pcm->device == EM8300_ALSA_ANALOG_DEVICENUM) {
		write_register(AUDIO_RATE, 0x62);
		em8300_setregblock(em, 2 * ucregister(Mute_Pattern), 0, 0x600);
	} else {
		write_register(AUDIO_RATE, 0x3a0);
	}
	write_ucregister(MA_Threshold, 6);

	/* store current used substream - needed for interrupt handler */
	em8300_alsa->substream = substream;

	return 0;
}
static int mpegaudio_command(struct em8300_s *em, int cmd)
{
	em8300_waitfor(em, ucregister(MA_Command), 0xffff, 0xffff);

	pr_debug("em8300-%d: MA_Command: %d\n", em->instance, cmd);
	write_ucregister(MA_Command, cmd);

	return em8300_waitfor(em, ucregister(MA_Status), cmd, 0xffff);
}
void em8300_dicom_update_aspect_ratio(struct em8300_s *em)
{
	if (em->aspect_ratio == EM8300_ASPECTRATIO_16_9) {
		em->dicom_tvout |= 0x10;
	} else {
		em->dicom_tvout &= ~0x10;
	}
	write_ucregister(DICOM_TvOut, em->dicom_tvout);
}
static int snd_em8300_pcm_prepare(struct snd_pcm_substream *substream)
{
	em8300_alsa_t *em8300_alsa = snd_pcm_substream_chip(substream);
	struct em8300_s *em = em8300_alsa->em;
	struct snd_pcm_runtime *runtime = substream->runtime;
//	printk("em8300-%d: snd_em8300_pcm_prepare called.\n", em->instance);

	em->clockgen &= ~CLOCKGEN_SAMPFREQ_MASK;
	switch (runtime->rate) {
	case 48000:
//		printk("em8300-%d: runtime->rate set to 48000\n", em->instance);
		em->clockgen |= CLOCKGEN_SAMPFREQ_48;
		break;
	case 44100:
//		printk("em8300-%d: runtime->rate set to 44100\n", em->instance);
		em->clockgen |= CLOCKGEN_SAMPFREQ_44;
		break;
	case 32000:
//		printk("em8300-%d: runtime->rate set to 32000\n", em->instance);
		em->clockgen |= CLOCKGEN_SAMPFREQ_32;
		break;
	default:
//		printk("em8300-%d: bad runtime->rate\n", em->instance);
		em->clockgen |= CLOCKGEN_SAMPFREQ_48;
	}
	em8300_clockgen_write(em, em->clockgen);

	memset(&em8300_alsa->indirect, 0, sizeof(em8300_alsa->indirect));
	em8300_alsa->indirect.hw_buffer_size =
		(read_ucregister(MA_BuffSize_Hi) << 16)
		| read_ucregister(MA_BuffSize);
	em8300_alsa->indirect.sw_buffer_size =
		snd_pcm_lib_buffer_bytes(substream);

	write_ucregister(MA_PCIRdPtr, ucregister(MA_PCIStart) - 0x1000);
	write_ucregister(MA_PCIWrPtr, ucregister(MA_PCIStart) - 0x1000);

	return 0;
}
Exemple #7
0
void em8300_dicom_enable(struct em8300_s *em)
{
	if (em->overlay_enabled) {
		em->dicom_tvout = 0x4000;
	} else {
		em->dicom_tvout = 0x4001;
	}

	if (em->aspect_ratio == EM8300_ASPECTRATIO_16_9) {
		em->dicom_tvout |= 0x10;
	} else {
		em->dicom_tvout &= ~0x10;
	}

	write_ucregister(DICOM_TvOut, em->dicom_tvout);
}
static void snd_em8300_pcm_trans_dma(struct snd_pcm_substream *substream,
				     snd_em8300_pcm_indirect_t *rec,
				     size_t bytes)
{
//	snd_pcm_runtime_t *runtime = substream->runtime;
	em8300_alsa_t *em8300_alsa = snd_pcm_substream_chip(substream);
	struct em8300_s *em = em8300_alsa->em;
	int writeindex = ((int)read_ucregister(MA_PCIWrPtr) - (ucregister(MA_PCIStart) - 0x1000)) / 3;
	int readindex = ((int)read_ucregister(MA_PCIRdPtr) - (ucregister(MA_PCIStart) - 0x1000)) / 3;
	writel((unsigned long int)(substream->runtime->dma_addr + rec->sw_data) >> 16,
	       ((uint32_t *)ucregister_ptr(MA_PCIStart))+3*writeindex);
	writel((unsigned long int)(substream->runtime->dma_addr + rec->sw_data) & 0xffff,
	       ((uint32_t *)ucregister_ptr(MA_PCIStart))+3*writeindex+1);
	writel(bytes,
	       ((uint32_t *)ucregister_ptr(MA_PCIStart))+3*writeindex+2);
	writeindex += 1;
	writeindex %= read_ucregister(MA_PCISize) / 3;
//	printk("em8300-%d: snd_em8300_pcm_trans_dma(%d) called.\n", em->instance, bytes);
	if (readindex != writeindex)
		write_ucregister(MA_PCIWrPtr, ucregister(MA_PCIStart) - 0x1000 + writeindex * 3);
	else
		printk("em8300-%d: snd_em8300_pcm_trans_dma failed.\n", em->instance);
}
Exemple #9
0
int em8300_dicom_update(struct em8300_s *em)
{
	int ret;
	int vmode_ntsc = 1;

	if (em->config.model.dicom_other_pal) {
		vmode_ntsc = (em->video_mode == EM8300_VIDEOMODE_NTSC);
	}

	if ((ret = em8300_waitfor(em, ucregister(DICOM_UpdateFlag), 0, 1))) {
		return ret;
	}

	if (em->overlay_enabled) {
		sub_4288c(em, em->overlay_frame_xpos, em->overlay_frame_ypos, em->overlay_frame_width,
				em->overlay_frame_height, em->overlay_a[EM9010_ATTRIBUTE_XOFFSET],
				em->overlay_a[EM9010_ATTRIBUTE_YOFFSET], em->overlay_a[EM9010_ATTRIBUTE_XCORR], em->overlay_double_y);
	} else {
		int f_vs, f_hs, f_vo, f_ho;
		int v_vs, v_hs, v_vo, v_ho;

		v_vs = f_vs = tvmodematrix[em->video_mode].vertsize;
		v_hs = f_hs = tvmodematrix[em->video_mode].horizsize;
		v_vo = f_vo = tvmodematrix[em->video_mode].vertoffset;
		v_ho = f_ho = tvmodematrix[em->video_mode].horizoffset;

		f_vo += ((100 - em->zoom) * f_vs + 100) / 200;
		f_ho += 2 * (((100 - em->zoom) * f_hs + 200) / 400);
		v_vo += ((100 - em->zoom) * v_vs + 100) / 200;
		v_ho += 2 * (((100 - em->zoom) * v_hs + 200) / 400);
		f_vs = (em->zoom * f_vs + 50) / 100;
		f_hs = (em->zoom * f_hs + 50) / 100;
		v_vs = (em->zoom * v_vs + 50) / 100;
		v_hs = (em->zoom * v_hs + 50) / 100;

		write_ucregister(DICOM_FrameTop, f_vo);
		write_ucregister(DICOM_FrameBottom, f_vo + f_vs - 1);
		write_ucregister(DICOM_FrameLeft, f_ho);
		write_ucregister(DICOM_FrameRight, f_ho + f_hs - 1);
		write_ucregister(DICOM_VisibleTop, v_vo);
		write_ucregister(DICOM_VisibleBottom, v_vo + v_vs - 1);
		write_ucregister(DICOM_VisibleLeft, v_ho);
		write_ucregister(DICOM_VisibleRight,v_ho + v_hs - 1);
	}

	if (em->aspect_ratio == EM8300_ASPECTRATIO_16_9) {
		em->dicom_tvout |= 0x10;
	} else {
		em->dicom_tvout &= ~0x10;
	}

	write_ucregister(DICOM_TvOut, em->dicom_tvout);

	if (em->overlay_enabled) {
		write_register(0x1f47, 0x0);
		write_register(0x1f5e, 0x1afe);
		write_ucregister(DICOM_Control, 0x9afe);

#if 0 /* don't know if this is necessary yet */
#ifdef EM8300_DICOM_0x1f5e_0x1efe
		write_register(0x1f5e, 0x1efe);
#else
		write_register(0x1f5e, 0x1afe);
#endif
#ifdef EM8300_DICOM_CONTROL_0x9efe
		write_ucregister(DICOM_Control, 0x9efe);
#else
		write_ucregister(DICOM_Control, 0x9afe);
#endif
#endif
	} else {

		if (em->encoder_type == ENCODER_BT865) {
			write_register(0x1f47, 0x0);
			if (em->video_mode == EM8300_VIDEOMODE_NTSC) {
				write_register(EM8300_HSYNC_LO, 134);
				write_register(EM8300_HSYNC_HI, 720);
			} else {
				write_register(EM8300_HSYNC_LO, 140);
				write_register(EM8300_HSYNC_HI, 720);
			}
			if (vmode_ntsc) {
				write_register(EM8300_VSYNC_HI, 260);
				write_register(0x1f5e, 0xfefe);
			} else {
				write_register(EM8300_VSYNC_HI, 310);
				write_register(0x1f5e, 0x9cfe);
			}

			write_ucregister(DICOM_VSyncLo1, 0x1);
			write_ucregister(DICOM_VSyncLo2, 0x0);
			write_ucregister(DICOM_VSyncDelay1, 0xd2);
			write_ucregister(DICOM_VSyncDelay2, 0x00);

			write_register(0x1f46, 0x00);
			write_register(0x1f47, 0x1f);

			write_ucregister(DICOM_Control, 0x9efe);
		} else { /* ADV7170 or ADV7175A */
			write_register(0x1f47, 0x18);

			if (vmode_ntsc) {
				if (em->config.model.dicom_fix) {
					write_register(0x1f5e, 0x1efe);
				} else {
					write_register(0x1f5e, 0x1afe);
				}

				if (em->config.model.dicom_control) {
					write_ucregister(DICOM_Control, 0x9efe);
				} else {
					write_ucregister(DICOM_Control, 0x9afe);
				}
			} else {
				if (em->config.model.dicom_fix) {
					write_register(0x1f5e, 0x1afe);
				} else {
					write_register(0x1f5e, 0x1efe);
				}

				if (em->config.model.dicom_control) {
					write_ucregister(DICOM_Control, 0x9afe);
				} else {
					write_ucregister(DICOM_Control, 0x9efe);
				}
			}
		}
	}

	pr_debug("em8300-%d: vmode_ntsc: %d\n", em->card_nr, vmode_ntsc);
	pr_debug("em8300-%d: dicom_other_pal: %d\n", em->card_nr, em->config.model.dicom_other_pal);
	pr_debug("em8300-%d: dicom_control: %d\n", em->card_nr, em->config.model.dicom_control);
	pr_debug("em8300-%d: dicom_fix: %d\n", em->card_nr, em->config.model.dicom_fix);

	write_ucregister(DICOM_UpdateFlag, 1);

	return em8300_waitfor(em, ucregister(DICOM_UpdateFlag), 0, 1);
}
Exemple #10
0
void em8300_dicom_disable(struct em8300_s *em)
{
	em->dicom_tvout = 0x8000;
	write_ucregister(DICOM_TvOut, em->dicom_tvout);
}
int em8300_dicom_update(struct em8300_s *em)
{
	int ret;
	int vmode_ntsc = 1;
	int f_vs, f_hs, f_vo, f_ho;
	int v_vs, v_hs, v_vo, v_ho;

	if (em->config.model.dicom_other_pal) {
		vmode_ntsc = (em->video_mode == V4L2_STD_NTSC);
	}

	if ((ret = em8300_waitfor(em, ucregister(DICOM_UpdateFlag), 0, 1))) {
		return ret;
	}

	v_vs = f_vs = tvmodematrix[em->video_mode].vertsize;
	v_hs = f_hs = tvmodematrix[em->video_mode].horizsize;
	v_vo = f_vo = tvmodematrix[em->video_mode].vertoffset;
	v_ho = f_ho = tvmodematrix[em->video_mode].horizoffset;

	f_vo += ((100 - em->zoom) * f_vs + 100) / 200;
	f_ho += 2 * (((100 - em->zoom) * f_hs + 200) / 400);
	v_vo += ((100 - em->zoom) * v_vs + 100) / 200;
	v_ho += 2 * (((100 - em->zoom) * v_hs + 200) / 400);
	f_vs = (em->zoom * f_vs + 50) / 100;
	f_hs = (em->zoom * f_hs + 50) / 100;
	v_vs = (em->zoom * v_vs + 50) / 100;
	v_hs = (em->zoom * v_hs + 50) / 100;

	write_ucregister(DICOM_FrameTop, f_vo);
	write_ucregister(DICOM_FrameBottom, f_vo + f_vs - 1);
	write_ucregister(DICOM_FrameLeft, f_ho);
	write_ucregister(DICOM_FrameRight, f_ho + f_hs - 1);
	write_ucregister(DICOM_VisibleTop, v_vo);
	write_ucregister(DICOM_VisibleBottom, v_vo + v_vs - 1);
	write_ucregister(DICOM_VisibleLeft, v_ho);
	write_ucregister(DICOM_VisibleRight,v_ho + v_hs - 1);

	if (em->aspect_ratio == EM8300_ASPECTRATIO_16_9) {
		em->dicom_tvout |= 0x10;
	} else {
		em->dicom_tvout &= ~0x10;
	}

	write_ucregister(DICOM_TvOut, em->dicom_tvout);

	if (em->encoder_type == ENCODER_BT865) {
		write_register(0x1f47, 0x0);
		if (em->video_mode == V4L2_STD_NTSC) {
			write_register(VIDEO_HSYNC_LO, 134);
			write_register(VIDEO_HSYNC_HI, 720);
		} else {
			write_register(VIDEO_HSYNC_LO, 140);
			write_register(VIDEO_HSYNC_HI, 720);
		}
		if (vmode_ntsc) {
			write_register(VIDEO_VSYNC_HI, 260);
			write_register(0x1f5e, 0xfefe);
		} else {
			write_register(VIDEO_VSYNC_HI, 310);
			write_register(0x1f5e, 0x9cfe);
		}

		write_ucregister(DICOM_VSyncLo1, 0x1);
		write_ucregister(DICOM_VSyncLo2, 0x0);
		write_ucregister(DICOM_VSyncDelay1, 0xd2);
		write_ucregister(DICOM_VSyncDelay2, 0x00);

		write_register(0x1f46, 0x00);
		write_register(0x1f47, 0x1f);

		write_ucregister(DICOM_Control, 0x9efe);
	} else { /* ADV7170 or ADV7175A */
		write_register(0x1f47, 0x18);

		if (vmode_ntsc) {
			if (em->config.model.dicom_fix) {
				write_register(0x1f5e, 0x1efe);
			} else {
				write_register(0x1f5e, 0x1afe);
			}

			if (em->config.model.dicom_control) {
				write_ucregister(DICOM_Control, 0x9efe);
			} else {
				write_ucregister(DICOM_Control, 0x9afe);
			}
		} else {
			if (em->config.model.dicom_fix) {
				write_register(0x1f5e, 0x1afe);
			} else {
				write_register(0x1f5e, 0x1efe);
			}

			if (em->config.model.dicom_control) {
				write_ucregister(DICOM_Control, 0x9afe);
			} else {
				write_ucregister(DICOM_Control, 0x9efe);
			}
		}
	}

	pr_debug("em8300-%d: vmode_ntsc: %d\n", em->instance, vmode_ntsc);
	pr_debug("em8300-%d: dicom_other_pal: %d\n", em->instance, em->config.model.dicom_other_pal);
	pr_debug("em8300-%d: dicom_control: %d\n", em->instance, em->config.model.dicom_control);
	pr_debug("em8300-%d: dicom_fix: %d\n", em->instance, em->config.model.dicom_fix);

	write_ucregister(DICOM_UpdateFlag, 1);

	return em8300_waitfor(em, ucregister(DICOM_UpdateFlag), 0, 1);
}
Exemple #12
0
int em8300_control_ioctl(struct em8300_s *em, int cmd, unsigned long arg)
{
	em8300_register_t reg;
	int val, len;
	em8300_bcs_t bcs;
	em8300_overlay_window_t ov_win;
	em8300_overlay_screen_t ov_scr;
	em8300_overlay_calibrate_t ov_cal;
	em8300_attribute_t attr;
	int old_count;
	long ret;

	if (_IOC_DIR(cmd) != 0) {
		len = _IOC_SIZE(cmd);

		if (len < 1 || len > 65536 || arg == 0) {
			return -EFAULT;
		}
		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			if (!access_ok(VERIFY_READ, (void *) arg, len)) {
				return -EFAULT;
			}
		}
		if (_IOC_DIR(cmd) & _IOC_READ) {
			if (!access_ok(VERIFY_WRITE, (void *) arg, len)) {
				return -EFAULT;
			}
		}
	}

	switch (_IOC_NR(cmd)) {
	case _IOC_NR(EM8300_IOCTL_INIT):
		return em8300_ioctl_init(em, (em8300_microcode_t *) arg);

	case _IOC_NR(EM8300_IOCTL_WRITEREG):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (copy_from_user(&reg, (void *) arg, sizeof(em8300_register_t)))
			return -EFAULT;

		if (reg.microcode_register) {
			write_ucregister(reg.reg, reg.val);
		} else {
			write_register(reg.reg, reg.val);
		}
		break;

	case _IOC_NR(EM8300_IOCTL_READREG):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (copy_from_user(&reg, (void *) arg, sizeof(em8300_register_t)))
			return -EFAULT;

		if (reg.microcode_register) {
			reg.val = read_ucregister(reg.reg);
			reg.reg = ucregister(reg.reg);
		} else {
			reg.val = read_register(reg.reg);
		}
		if (copy_to_user((void *) arg, &reg, sizeof(em8300_register_t)))
			return -EFAULT;
		break;

	case _IOC_NR(EM8300_IOCTL_VBI):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		old_count = em->irqcount;
		em->irqmask |= IRQSTATUS_VIDEO_VBL;
		write_ucregister(Q_IrqMask, em->irqmask);

		ret = wait_event_interruptible_timeout(em->vbi_wait, em->irqcount != old_count, HZ);
		if (ret == 0)
			return -EINTR;
		else if (ret < 0)
			return ret;

		/* copy timestamp and return */
		if (copy_to_user((void *) arg, &em->tv, sizeof(struct timeval)))
			return -EFAULT;
		return 0;

	case _IOC_NR(EM8300_IOCTL_GETBCS):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			if (copy_from_user(&bcs, (void *) arg, sizeof(em8300_bcs_t)))
				return -EFAULT;
			em8300_dicom_setBCS(em, bcs.brightness, bcs.contrast, bcs.saturation);
		}

		if (_IOC_DIR(cmd) & _IOC_READ) {
			bcs.brightness = em->dicom_brightness;
			bcs.contrast = em->dicom_contrast;
			bcs.saturation = em->dicom_saturation;
			if (copy_to_user((void *) arg, &bcs, sizeof(em8300_bcs_t)))
				return -EFAULT;
		}
		break;

	case _IOC_NR(EM8300_IOCTL_SET_VIDEOMODE):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			get_user(val, (int *) arg);
			return em8300_ioctl_setvideomode(em, val);
		}

		if (_IOC_DIR(cmd) & _IOC_READ) {
			if (copy_to_user((void *) arg, &em->video_mode, sizeof(em->video_mode)))
				return -EFAULT;
		}
		break;

	case _IOC_NR(EM8300_IOCTL_SET_PLAYMODE):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			get_user(val, (int *) arg);
			return em8300_ioctl_setplaymode(em, val);
		}
		break;

	case _IOC_NR(EM8300_IOCTL_SET_ASPECTRATIO):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			get_user(val, (int *) arg);
			em8300_ioctl_setaspectratio(em, val);
		}

		if (_IOC_DIR(cmd) & _IOC_READ) {
			if (copy_to_user((void *) arg, &em->aspect_ratio, sizeof(em->aspect_ratio)))
				return -EFAULT;
		}
		break;
	case _IOC_NR(EM8300_IOCTL_GET_AUDIOMODE):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			get_user(val, (int *) arg);
			em8300_ioctl_setaudiomode(em, val);
		}
		if (_IOC_DIR(cmd) & _IOC_READ) {
			em8300_ioctl_getaudiomode(em, arg);
		}
		break;
	case _IOC_NR(EM8300_IOCTL_SET_SPUMODE):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			get_user(val, (int *) arg);
			em8300_ioctl_setspumode(em, val);
		}

		if (_IOC_DIR(cmd) & _IOC_READ) {
			if (copy_to_user((void *) arg, &em->sp_mode, sizeof(em->sp_mode)))
				return -EFAULT;
		}
		break;

	case _IOC_NR(EM8300_IOCTL_OVERLAY_SETMODE):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			get_user(val, (int *) arg);
			if (!em8300_ioctl_overlay_setmode(em, val)) {
				return -EINVAL;
			}
		}
		break;

	case _IOC_NR(EM8300_IOCTL_OVERLAY_SIGNALMODE):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			get_user(val, (int *) arg);
			if (!em9010_overlay_set_signalmode(em, val)) {
				return -EINVAL;
			}
		}
		break;

	case _IOC_NR(EM8300_IOCTL_OVERLAY_SETWINDOW):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			if (copy_from_user(&ov_win, (void *) arg, sizeof(em8300_overlay_window_t)))
				return -EFAULT;
			if (!em8300_ioctl_overlay_setwindow(em, &ov_win)) {
				return -EINVAL;
			}
		}
		if (_IOC_DIR(cmd) & _IOC_READ) {
			if (copy_to_user((void *) arg, &ov_win, sizeof(em8300_overlay_window_t)))
				return -EFAULT;
		}
		break;

	case _IOC_NR(EM8300_IOCTL_OVERLAY_SETSCREEN):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			if (copy_from_user(&ov_scr, (void *) arg, sizeof(em8300_overlay_screen_t)))
				return -EFAULT;
			if (!em8300_ioctl_overlay_setscreen(em, &ov_scr)) {
				return -EINVAL;
			}
		}
		if (_IOC_DIR(cmd) & _IOC_READ) {
			if (copy_to_user((void *) arg, &ov_scr, sizeof(em8300_overlay_screen_t)))
				return -EFAULT;
		}
	break;

	case _IOC_NR(EM8300_IOCTL_OVERLAY_CALIBRATE):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			if (copy_from_user(&ov_cal, (void *) arg, sizeof(em8300_overlay_calibrate_t)))
				return -EFAULT;
			if(!em8300_ioctl_overlay_calibrate(em, &ov_cal)) {
				return -EIO;
			}
		}

		if (_IOC_DIR(cmd) & _IOC_READ) {
			if (copy_to_user((void *) arg, &ov_cal, sizeof(em8300_overlay_calibrate_t)))
				return -EFAULT;
		}
	break;

	case _IOC_NR(EM8300_IOCTL_OVERLAY_GET_ATTRIBUTE):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (copy_from_user(&attr, (void *) arg, sizeof(em8300_attribute_t)))
			return -EFAULT;
		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			em9010_set_attribute(em, attr.attribute, attr.value);
		}
		if (_IOC_DIR(cmd) & _IOC_READ) {
			attr.value = em9010_get_attribute(em, attr.attribute);
			if (copy_to_user((void *) arg, &attr, sizeof(em8300_attribute_t)))
				return -EFAULT;
		}
		break;

	case _IOC_NR(EM8300_IOCTL_SCR_GET):
		em8300_require_ucode(em);

		if (!em->ucodeloaded) {
			return -ENOTTY;
		}

		if (_IOC_DIR(cmd) & _IOC_WRITE) {
			unsigned scr;
			if (get_user(val, (unsigned *) arg))
				return -EFAULT;
			scr = read_ucregister(MV_SCRlo) | (read_ucregister(MV_SCRhi) << 16);

			if (scr > val)
				scr = scr - val;
			else
				scr = val - scr;

			if (scr > 2 * 1800) { /* Tolerance: 2 frames */
				pr_info("em8300-%d: adjusting scr: %i\n", em->card_nr, val);
				write_ucregister(MV_SCRlo, val & 0xffff);
				write_ucregister(MV_SCRhi, (val >> 16) & 0xffff);
			}
		}