📄 meye.c
字号:
for (i = 0; i < MCHIP_REG_TIMEOUT; i++) { status = readl(meye.mchip_mmregs + MCHIP_HIC_STATUS); if (status & mask) return; udelay(1); } } else return; printk(KERN_WARNING "meye: mchip_sync() timeout on reg 0x%x status=0x%x\n", reg, status);}/* sets a value into the register */static inline void mchip_set(int reg, u32 v) { mchip_sync(reg); writel(v, meye.mchip_mmregs + reg);}/* get the register value */static inline u32 mchip_read(int reg) { mchip_sync(reg); return readl(meye.mchip_mmregs + reg);}/* wait for a register to become a particular value */static inline int mchip_delay(u32 reg, u32 v) { int n = 10; while (--n && mchip_read(reg) != v) udelay(1); return n;}/* setup subsampling */static void mchip_subsample(void) { mchip_set(MCHIP_MCC_R_SAMPLING, meye.params.subsample); mchip_set(MCHIP_MCC_R_XRANGE, mchip_hsize()); mchip_set(MCHIP_MCC_R_YRANGE, mchip_vsize()); mchip_set(MCHIP_MCC_B_XRANGE, mchip_hsize()); mchip_set(MCHIP_MCC_B_YRANGE, mchip_vsize()); mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE);}/* set the framerate into the mchip */static void mchip_set_framerate(void) { mchip_set(MCHIP_HIC_S_RATE, meye.params.framerate);}/* load some huffman and quantisation tables into the VRJ chip ready for JPEG compression */static void mchip_load_tables(void) { int i; int size; u16 *tables; tables = jpeg_huffman_tables(&size); for (i = 0; i < size / 2; i++) writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA); tables = jpeg_quantisation_tables(&size, meye.params.quality); for (i = 0; i < size / 2; i++) writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA);}/* setup the VRJ parameters in the chip */static void mchip_vrj_setup(u8 mode) { mchip_set(MCHIP_VRJ_BUS_MODE, 5); mchip_set(MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL, 0x1f); mchip_set(MCHIP_VRJ_PDAT_USE, 1); mchip_set(MCHIP_VRJ_IRQ_FLAG, 0xa0); mchip_set(MCHIP_VRJ_MODE_SPECIFY, mode); mchip_set(MCHIP_VRJ_NUM_LINES, mchip_vsize()); mchip_set(MCHIP_VRJ_NUM_PIXELS, mchip_hsize()); mchip_set(MCHIP_VRJ_NUM_COMPONENTS, 0x1b); mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_LO, 0xFFFF); mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_HI, 0xFFFF); mchip_set(MCHIP_VRJ_COMP_DATA_FORMAT, 0xC); mchip_set(MCHIP_VRJ_RESTART_INTERVAL, 0); mchip_set(MCHIP_VRJ_SOF1, 0x601); mchip_set(MCHIP_VRJ_SOF2, 0x1502); mchip_set(MCHIP_VRJ_SOF3, 0x1503); mchip_set(MCHIP_VRJ_SOF4, 0x1596); mchip_set(MCHIP_VRJ_SOS, 0x0ed0); mchip_load_tables();}/* setup for DMA transfers - also zeros the framebuffer */static int mchip_dma_alloc(void) { if (!meye.mchip_fbuffer) { meye.mchip_fbuffer = ptable_alloc(MCHIP_NB_PAGES, &meye.mchip_ptaddr); if (!meye.mchip_fbuffer) return -1; } return 0;}/* frees the DMA buffer */static void mchip_dma_free(void) { if (meye.mchip_fbuffer) { ptable_free(meye.mchip_fbuffer, MCHIP_NB_PAGES); meye.mchip_fbuffer = 0; meye.mchip_ptaddr = 0; }}/* sets the DMA parameters into the chip */static void mchip_dma_setup(void) { int i; mchip_set(MCHIP_MM_PT_ADDR, meye.mchip_ptaddr); for (i = 0; i < 4; i++) mchip_set(MCHIP_MM_FIR(i), 0); meye.mchip_fnum = 0;}/* stop any existing HIC action and wait for any dma to complete then reset the dma engine */static void mchip_hic_stop(void) { int i = 0; meye.mchip_mode = MCHIP_HIC_MODE_NOOP; if (!(mchip_read(MCHIP_HIC_STATUS) & MCHIP_HIC_STATUS_BUSY)) return; mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP); mchip_delay(MCHIP_HIC_CMD, 0); while (!mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) { /* resetting HIC */ mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP); mchip_delay(MCHIP_HIC_CMD, 0); mchip_set(MCHIP_HIC_CTL, MCHIP_HIC_CTL_SOFT_RESET); wait_ms(250); if (i++ > 20) { printk(KERN_ERR "meye: resetting HIC hanged!\n"); break; } } wait_ms(100);}/****************************************************************************//* MCHIP frame processing functions *//****************************************************************************//* get the next ready frame from the dma engine */static u32 mchip_get_frame(void) { u32 v; v = mchip_read(MCHIP_MM_FIR(meye.mchip_fnum)); return v;}/* frees the current frame from the dma engine */static void mchip_free_frame(void) { mchip_set(MCHIP_MM_FIR(meye.mchip_fnum), 0); meye.mchip_fnum++; meye.mchip_fnum %= 4;}/* read one frame from the framebuffer assuming it was captured using a uncompressed transfer */static void mchip_cont_read_frame(u32 v, u8 *buf, int size) { int pt_id; int avail; pt_id = (v >> 17) & 0x3FF; avail = MCHIP_NB_PAGES - pt_id; if (size > avail*PAGE_SIZE) { memcpy(buf, meye.mchip_fbuffer + pt_id * PAGE_SIZE, avail * PAGE_SIZE); memcpy(buf +avail * PAGE_SIZE, meye.mchip_fbuffer, size - avail * PAGE_SIZE); } else memcpy(buf, meye.mchip_fbuffer + pt_id * PAGE_SIZE, size);}/* read a compressed frame from the framebuffer */static int mchip_comp_read_frame(u32 v, u8 *buf, int size) { int pt_start, pt_end, trailer; int fsize, fsize2; int i; pt_start = (v >> 19) & 0xFF; pt_end = (v >> 11) & 0xFF; trailer = (v >> 1) & 0x3FF; if (pt_end < pt_start) { fsize = (MCHIP_NB_PAGES_MJPEG - pt_start) * PAGE_SIZE; fsize2 = pt_end * PAGE_SIZE + trailer * 4; if (fsize + fsize2 > size) { printk(KERN_WARNING "meye: oversized compressed frame %d %d\n", fsize, fsize2); return -1; } else { memcpy(buf, meye.mchip_fbuffer + pt_start * PAGE_SIZE, fsize); memcpy(buf + fsize, meye.mchip_fbuffer, fsize2); fsize += fsize2; } } else { fsize = (pt_end - pt_start) * PAGE_SIZE + trailer * 4; if (fsize > size) { printk(KERN_WARNING "meye: oversized compressed frame %d\n", fsize); return -1; } else memcpy(buf, meye.mchip_fbuffer + pt_start * PAGE_SIZE, fsize); }#ifdef MEYE_JPEG_CORRECTION /* Some mchip generated jpeg frames are incorrect. In most * (all ?) of those cases, the final EOI (0xff 0xd9) marker * is not present at the end of the frame. * * Since adding the final marker is not enough to restore * the jpeg integrity, we drop the frame. */ for (i = fsize - 1; i > 0 && buf[i] == 0xff; i--) ; if (i < 2 || buf[i - 1] != 0xff || buf[i] != 0xd9) return -1;#endif return fsize;}/* take a picture into SDRAM */static void mchip_take_picture(void) { int i; mchip_hic_stop(); mchip_subsample(); mchip_dma_setup(); mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_CAP); mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); mchip_delay(MCHIP_HIC_CMD, 0); for (i = 0; i < 100; ++i) { if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) break; wait_ms(1); }}/* dma a previously taken picture into a buffer */static void mchip_get_picture(u8 *buf, int bufsize) { u32 v; int i; mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_OUT); mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); mchip_delay(MCHIP_HIC_CMD, 0); for (i = 0; i < 100; ++i) { if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) break; wait_ms(1); } for (i = 0; i < 4 ; ++i) { v = mchip_get_frame(); if (v & MCHIP_MM_FIR_RDY) { mchip_cont_read_frame(v, buf, bufsize); break; } mchip_free_frame(); }}/* start continuous dma capture */static void mchip_continuous_start(void) { mchip_hic_stop(); mchip_subsample(); mchip_set_framerate(); mchip_dma_setup(); meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_OUT); mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); mchip_delay(MCHIP_HIC_CMD, 0);}/* compress one frame into a buffer */static int mchip_compress_frame(u8 *buf, int bufsize) { u32 v; int len = -1, i; mchip_vrj_setup(0x3f); udelay(50); mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_COMP); mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); mchip_delay(MCHIP_HIC_CMD, 0); for (i = 0; i < 100; ++i) { if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) break; wait_ms(1); } for (i = 0; i < 4 ; ++i) { v = mchip_get_frame(); if (v & MCHIP_MM_FIR_RDY) { len = mchip_comp_read_frame(v, buf, bufsize); break; } mchip_free_frame(); } return len;}#if 0/* uncompress one image into a buffer */static int mchip_uncompress_frame(u8 *img, int imgsize, u8 *buf, int bufsize) { mchip_vrj_setup(0x3f); udelay(50); mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_DECOMP); mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); mchip_delay(MCHIP_HIC_CMD, 0); return mchip_comp_read_frame(buf, bufsize);}#endif/* start continuous compressed capture */static void mchip_cont_compression_start(void) { mchip_hic_stop(); mchip_vrj_setup(0x3f); mchip_subsample(); mchip_set_framerate(); mchip_dma_setup(); meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_COMP); mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); mchip_delay(MCHIP_HIC_CMD, 0);}/****************************************************************************//* Interrupt handling *//****************************************************************************/static void meye_irq(int irq, void *dev_id, struct pt_regs *regs) { u32 v; int reqnr; v = mchip_read(MCHIP_MM_INTA); while (1) { v = mchip_get_frame(); if (!(v & MCHIP_MM_FIR_RDY)) goto out; switch (meye.mchip_mode) { case MCHIP_HIC_MODE_CONT_OUT: if (!meye_emptyq(&meye.grabq, NULL)) { int nr = meye_pullq(&meye.grabq); mchip_cont_read_frame( v, meye.grab_fbuffer + gbufsize * nr, mchip_hsize() * mchip_vsize() * 2); meye.grab_buffer[nr].state = MEYE_BUF_DONE; wake_up_interruptible(&meye.grabq.proc_list); } break; case MCHIP_HIC_MODE_CONT_COMP: if (!meye_emptyq(&meye.grabq, &reqnr)) { int size; size = mchip_comp_read_frame( v, meye.grab_fbuffer + gbufsize * reqnr, gbufsize); if (size == -1) break; reqnr = meye_pullq(&meye.grabq); meye.grab_buffer[reqnr].size = size; meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; wake_up_interruptible(&meye.grabq.proc_list); } break; default: /* do not free frame, since it can be a snap */ goto out; } /* switch */ mchip_free_frame(); }out:}/****************************************************************************//* video4linux integration *//****************************************************************************/static int meye_open(struct video_device *dev, int flags) { int i; down(&meye.lock); if (meye.open_count) { up(&meye.lock); return -EBUSY; } meye.open_count++; if (mchip_dma_alloc()) { printk(KERN_ERR "meye: mchip framebuffer allocation failed\n"); up(&meye.lock); return -ENOBUFS; } mchip_hic_stop(); meye_initq(&meye.grabq); for (i = 0; i < MEYE_MAX_BUFNBRS; i++) meye.grab_buffer[i].state = MEYE_BUF_UNUSED; up(&meye.lock); return 0;}static void meye_close(struct video_device *dev) { down(&meye.lock); meye.open_count--; mchip_hic_stop(); up(&meye.lock);}static int meye_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { switch (cmd) { case VIDIOCGCAP: { struct video_capability b; strcpy(b.name,meye.video_dev.name); b.type = VID_TYPE_CAPTURE; b.channels = 1; b.audios = 0; b.maxwidth = 640; b.maxheight = 480; b.minwidth = 320; b.minheight = 240; if(copy_to_user(arg,&b,sizeof(b))) return -EFAULT; break; } case VIDIOCGCHAN: { struct video_channel v; if(copy_from_user(&v, arg,sizeof(v))) return -EFAULT; v.flags = 0; v.tuners = 0; v.type = VIDEO_TYPE_CAMERA; if (v.channel != 0) return -EINVAL; strcpy(v.name,"Camera"); if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; break; } case VIDIOCSCHAN: { struct video_channel v; if(copy_from_user(&v, arg,sizeof(v))) return -EFAULT; if (v.channel != 0) return -EINVAL; break; } case VIDIOCGPICT: { struct video_picture p = meye.picture; if(copy_to_user(arg, &p, sizeof(p))) return -EFAULT; break; } case VIDIOCSPICT: { struct video_picture p; if(copy_from_user(&p, arg,sizeof(p))) return -EFAULT; if (p.depth != 2) return -EINVAL; if (p.palette != VIDEO_PALETTE_YUV422) return -EINVAL; down(&meye.lock); sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -