📄 em8300_video.c
字号:
#define __NO_VERSION__#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/version.h>#include <linux/string.h>#include <linux/pci.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/i2c-algo-bit.h>#include "em8300_reg.h"#include <linux/em8300.h>#include "em8300_fifo.h"#include <linux/soundcard.h>extern int bt865_ucode_timeout;static int mpegvideo_command(struct em8300_s *em, int cmd){ if (em8300_waitfor(em,ucregister(MV_Command), 0xffff, 0xffff)) { return -1; } write_ucregister(MV_Command, cmd); if ((cmd == MVCOMMAND_DISPLAYBUFINFO) || (cmd == 0x10)) { return em8300_waitfor_not(em, ucregister(DICOM_Display_Data), 0, 0xffff); } else { return em8300_waitfor(em,ucregister(MV_Command), 0xffff, 0xffff); }}int em8300_video_setplaymode(struct em8300_s *em, int mode){ if (mode == EM8300_PLAYMODE_FRAMEBUF) { mpegvideo_command(em, MVCOMMAND_DISPLAYBUFINFO); em->video_playmode=mode; return 0; } if (em->video_playmode != mode) { switch(mode) { case EM8300_PLAYMODE_STOPPED: em->video_ptsfifo_ptr = 0; em->video_offset = 0; mpegvideo_command(em, MVCOMMAND_STOP); break; case EM8300_PLAYMODE_PLAY: em->video_pts = 0; em->video_lastpts = 0; if (em->video_playmode == EM8300_PLAYMODE_STOPPED) { write_ucregister(MV_FrameEventLo, 0xffff); write_ucregister(MV_FrameEventHi, 0x7fff); } mpegvideo_command(em, MVCOMMAND_START); break; case EM8300_PLAYMODE_PAUSED: mpegvideo_command(em, MVCOMMAND_PAUSE); break; default: return -1; } em->video_playmode=mode; return 0; } return -1;}int em8300_video_sync(struct em8300_s *em){ int rdptr,wrptr,synctimeout; synctimeout = 0; do { wrptr = read_ucregister(MV_Wrptr_Lo) | (read_ucregister(MV_Wrptr_Hi)<<16); rdptr = read_ucregister(MV_RdPtr_Lo) | (read_ucregister(MV_RdPtr_Hi)<<16); if (rdptr != wrptr && ++synctimeout < 20) { schedule_timeout(HZ/10); } if (signal_pending(current)) { printk(KERN_ERR "em8300_video.o: Video sync interrupted\n"); return -EINTR; } } while (rdptr != wrptr && synctimeout < 20); return 0;}void set_dicom_kmin (struct em8300_s *em){ int kmin; kmin = (em->overlay_70 + 10) * 150645 / em->mystery_divisor; if (kmin > 0x900) { kmin = 0x900; } write_ucregister(DICOM_Kmin, kmin); pr_debug("em8300: register DICOM_Kmin = 0x%x\n", kmin);}int em8300_video_setup(struct em8300_s *em){#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) init_waitqueue(&em->video_ptsfifo_wait);#else init_waitqueue_head(&em->video_ptsfifo_wait);#endif write_register(0x1f47, 0x0); if (em->encoder_type == ENCODER_BT865) { write_register(0x1f5e, 0x9efe); write_ucregister(DICOM_Control, 0x9efe); } else { write_register(0x1f5e, 0x9afe); write_ucregister(DICOM_Control, 0x9afe); } write_register(EM8300_I2C_PIN, 0x3c3c); write_register(EM8300_I2C_OE, 0x3c00); write_register(EM8300_I2C_OE, 0x3c3c); write_register(EM8300_I2C_PIN, 0x808); write_register(EM8300_I2C_PIN, 0x1010); em9010_init(em); em9010_write(em, 7, 0x40); em9010_write(em, 9, 0x4); em9010_read(em, 0); udelay(100); write_ucregister(DICOM_UpdateFlag, 0x0); write_ucregister(DICOM_VisibleLeft, 0x168); write_ucregister(DICOM_VisibleTop, 0x2e); write_ucregister(DICOM_VisibleRight, 0x36b); write_ucregister(DICOM_VisibleBottom, 0x11e); write_ucregister(DICOM_FrameLeft, 0x168); write_ucregister(DICOM_FrameTop, 0x2e); write_ucregister(DICOM_FrameRight, 0x36b); write_ucregister(DICOM_FrameBottom, 0x11e); em8300_dicom_enable(em); em9010_write16(em, 0x8, 0xff); em9010_write16(em, 0x10, 0xff); em9010_write16(em, 0x20, 0xff); em9010_write(em, 0xa, 0x0); if (em9010_cabledetect(em)) { pr_debug("em8300: overlay loop-back cable detected\n"); } pr_debug("em8300: overlay reg 0x80 = %x \n", em9010_read16(em, 0x80)); em9010_write(em, 0xb, 0xc8); pr_debug("em8300: register 0x1f4b = %x (0x138)\n", read_register(0x1f4b)); em9010_write16(em, 1, 0x4fe); em9010_write(em, 1, 4); em9010_write(em, 5, 0); em9010_write(em, 6, 0); em9010_write(em, 7, 0x40); em9010_write(em, 8, 0x80); em9010_write(em, 0xc, 0x8c); em9010_write(em, 9, 0); set_dicom_kmin(em); em9010_write(em, 7, 0x80); em9010_write(em, 9, 0); if (bt865_ucode_timeout) { write_register(0x1f47, 0x18); } if (em->encoder_type == ENCODER_BT865) { write_register(0x1f5e, 0x9efe); write_ucregister(DICOM_Control, 0x9efe); } else { if (!bt865_ucode_timeout) { write_register(0x1f47, 0x18); } write_register(0x1f5e,0x9afe); write_ucregister(DICOM_Control, 0x9afe); } write_ucregister(DICOM_UpdateFlag, 0x1); udelay(100); write_ucregister(ForcedLeftParity, 0x2); write_ucregister(MV_Threshold, 0x90); // was 0x50 for BT865, but this works too write_register(EM8300_INTERRUPT_ACK, 0x2); write_ucregister(Q_IrqMask, 0x0); write_ucregister(Q_IrqStatus, 0x0); write_ucregister(Q_IntCnt, 0x64); write_register(0x1ffb, em->var_video_value); write_ucregister(MA_Threshold, 0x8); /* Release reset */ write_register(0x2000, 0x1); if (mpegvideo_command(em, MVCOMMAND_DISPLAYBUFINFO)) { printk(KERN_ERR "em8300_video: mpegvideo_command(0x11) failed\n"); return -ETIME; } em8300_dicom_get_dbufinfo(em); write_ucregister(SP_Status, 0x0); if(mpegvideo_command(em, 0x10)) { printk(KERN_ERR "em8300: mpegvideo_command(0x10) failed\n"); return -ETIME; } em8300_video_setspeed(em, 0x900); write_ucregister(MV_FrameEventLo, 0xffff); write_ucregister(MV_FrameEventHi, 0x7fff); em8300_ioctl_setvideomode(em, EM8300_VIDEOMODE_DEFAULT); em8300_ioctl_setaspectratio(em, EM8300_ASPECTRATIO_4_3); em8300_dicom_setBCS(em, 500, 500, 500); if (em8300_dicom_update(em)) { printk(KERN_ERR "em8300: DICOM Update failed\n"); return -ETIME; } em->video_playmode = -1; em8300_video_setplaymode(em, EM8300_PLAYMODE_STOPPED); return 0;}void em8300_video_setspeed(struct em8300_s *em, int speed){ if (read_ucregister(MicroCodeVersion) >= 0x29) { write_ucregister(MV_SCRSpeed, speed); } else { write_ucregister(MV_SCRSpeed, speed >> 8); }}void em8300_video_check_ptsfifo(struct em8300_s *em){ int ptsfifoptr; if (em->video_ptsfifo_waiting) { ptsfifoptr = ucregister(MV_PTSFifo) + 4*em->video_ptsfifo_ptr; if (!(read_register(ptsfifoptr+1) & 1)) { em->video_ptsfifo_waiting=0; wake_up_interruptible(&em->video_ptsfifo_wait); } }}int em8300_video_write(struct em8300_s *em, const char * buf, size_t count, loff_t *ppos){ unsigned flags=0; if (em->video_ptsvalid) { int ptsfifoptr=0; em->video_lastpts = em->video_pts; em->video_pts >>= 1; flags = 0x40000000; ptsfifoptr = ucregister(MV_PTSFifo) + 4*em->video_ptsfifo_ptr; if (read_register(ptsfifoptr+3) & 1) { em->video_ptsfifo_waiting=1; interruptible_sleep_on(&em->video_ptsfifo_wait); em->video_ptsfifo_waiting=0; if (signal_pending(current)) { return -EINTR; } } #ifdef DEBUG_SYNC pr_debug("em8300_video.o: pts: %u\n", pts>>1);#endif write_register(ptsfifoptr, em->video_offset >> 16); write_register(ptsfifoptr+1, em->video_offset & 0xffff); write_register(ptsfifoptr+2, em->video_pts >> 16); write_register(ptsfifoptr+3, (em->video_pts & 0xffff) | 1); em->video_ptsfifo_ptr++; em->video_ptsfifo_ptr %= read_ucregister(MV_PTSSize) / 4; em->video_ptsvalid=0; } em->video_offset += count; return em8300_fifo_writeblocking(em->mvfifo, count, buf, flags);}int em8300_video_ioctl(struct em8300_s *em, unsigned int cmd, unsigned long arg){ unsigned scr,val; switch (_IOC_NR(cmd)) { case _IOC_NR(EM8300_IOCTL_VIDEO_SETPTS): if (get_user(em->video_pts, (int *)arg)) { return -EFAULT; } em->video_ptsvalid = 1; break; case _IOC_NR(EM8300_IOCTL_VIDEO_SETSCR): if (_IOC_DIR(cmd) & _IOC_WRITE) { if (get_user(val,(unsigned*)arg)) return -EFAULT; val >>= 1; scr = read_ucregister(MV_SCRlo) | (read_ucregister(MV_SCRhi) << 16); scr -= val; if (scr < 0) scr = -scr; if (scr > 9000) { pr_info("setting scr: %i\n", val); write_ucregister(MV_SCRlo, val & 0xffff); write_ucregister(MV_SCRhi, (val >> 16) & 0xffff); } } if (_IOC_DIR(cmd) & _IOC_READ) { scr = read_ucregister(MV_SCRlo) | (read_ucregister(MV_SCRhi) << 16); copy_to_user((void *)arg, &scr, sizeof(unsigned)); } break; default: return -EINVAL; } return 0;}void em8300_video_open(struct em8300_s *em){ em->irqmask |= IRQSTATUS_VIDEO_FIFO | IRQSTATUS_VIDEO_VBL; write_ucregister(Q_IrqMask, em->irqmask);}int em8300_video_release(struct em8300_s *em){ em->video_ptsfifo_ptr=0; em->video_offset=0; em->video_ptsvalid=0; em8300_fifo_sync(em->mvfifo); em8300_video_sync(em); em->irqmask &= ~(IRQSTATUS_VIDEO_FIFO | IRQSTATUS_VIDEO_VBL); write_ucregister(Q_IrqMask, em->irqmask); return em8300_video_setplaymode(em, EM8300_PLAYMODE_STOPPED);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -