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); }
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 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; }
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); }
int em8300_dicom_get_dbufinfo(struct em8300_s *em) { int displaybuffer; struct displaybuffer_info_s *di = &em->dbuf_info; displaybuffer = read_ucregister(DICOM_DisplayBuffer) + 0x1000; di->xsize = read_register(displaybuffer); di->ysize = read_register(displaybuffer+1); di->xsize2 = read_register(displaybuffer+2) & 0xfff; di->flag1 = read_register(displaybuffer+2) & 0x8000; di->flag2 = read_ucregister(Vsync_DBuf) & 0x4000; if (read_ucregister(MicroCodeVersion) <= 0xf) { di->buffer1 = (read_register(displaybuffer + 3) | (read_register(displaybuffer + 4) << 16)) << 4; di->buffer2 = (read_register(displaybuffer + 5) | (read_register(displaybuffer + 6) << 16)) << 4; } else { di->buffer1 = read_register(displaybuffer + 3) << 6; di->buffer2 = read_register(displaybuffer + 4) << 6; } if (displaybuffer == ucregister(Width_Buf3)) { di->unk_present = 1; if(read_ucregister(MicroCodeVersion) <= 0xf) { di->unknown1 = read_register(displaybuffer + 7); di->unknown2 = (read_register(displaybuffer + 8) | (read_register(displaybuffer + 9) << 16)) << 4; di->unknown3 = (read_register(displaybuffer + 0xa) | (read_register(displaybuffer + 0xb) << 16)) << 4; } else { di->unknown2 = read_register(displaybuffer + 6); di->unknown3 = read_register(displaybuffer + 7); } } else { di->unk_present = 0; } pr_debug("em8300-%d: DICOM buffer: xsize=0x%x(%d)\n", em->card_nr, di->xsize, di->xsize); pr_debug("em8300-%d: ysize=0x%x(%d)\n", em->card_nr, di->ysize, di->ysize); pr_debug("em8300-%d: xsize2=0x%x(%d)\n", em->card_nr, di->xsize2, di->xsize2); pr_debug("em8300-%d: flag1=%d, flag2=%d\n", em->card_nr, di->flag1, di->flag2); pr_debug("em8300-%d: buffer1=0x%x(%d)\n", em->card_nr, di->buffer1, di->buffer1); pr_debug("em8300-%d: buffer2=0x%x(%d)\n", em->card_nr, di->buffer2, di->buffer2); if (di->unk_present) { pr_debug("em8300-%d: unknown1=0x%x(%d)\n", em->card_nr, di->unknown1, di->unknown1); pr_debug("em8300-%d: unknown2=0x%x(%d)\n", em->card_nr, di->unknown2, di->unknown2); pr_debug("em8300-%d: unknown3=0x%x(%d)\n", em->card_nr, di->unknown3, di->unknown3); } return 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); }
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); }
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(®, (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(®, (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, ®, 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); } }