📄 vino.c
字号:
case VINO_DATA_NORM_NTSC: case VINO_DATA_NORM_D1: fps = (unsigned int)(fps / 6) * 6; // FIXME: round! if (fps < vino_data_norms[vcs->data_norm].fps_min) fps = vino_data_norms[vcs->data_norm].fps_min; if (fps > vino_data_norms[vcs->data_norm].fps_max) fps = vino_data_norms[vcs->data_norm].fps_max; switch (fps) { case 6: mask = 0x003; break; case 12: mask = 0x0c3; break; case 18: mask = 0x333; break; case 24: mask = 0x3ff; break; case 30: mask = 0xfff; break; default: mask = VINO_FRAMERT_FULL; } vcs->framert_reg = VINO_FRAMERT_RT(mask); break; case VINO_DATA_NORM_PAL: case VINO_DATA_NORM_SECAM: fps = (unsigned int)(fps / 5) * 5; // FIXME: round! if (fps < vino_data_norms[vcs->data_norm].fps_min) fps = vino_data_norms[vcs->data_norm].fps_min; if (fps > vino_data_norms[vcs->data_norm].fps_max) fps = vino_data_norms[vcs->data_norm].fps_max; switch (fps) { case 5: mask = 0x003; break; case 10: mask = 0x0c3; break; case 15: mask = 0x333; break; case 20: mask = 0x0ff; break; case 25: mask = 0x3ff; break; default: mask = VINO_FRAMERT_FULL; } vcs->framert_reg = VINO_FRAMERT_RT(mask) | VINO_FRAMERT_PAL; break; } vcs->fps = fps;}/* execute with input_lock locked */static inline void vino_set_default_framerate(struct vino_channel_settings *vcs){ vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max);}/* * Prepare VINO for DMA transfer... * (execute only with vino_lock and input_lock locked) */static int vino_dma_setup(struct vino_channel_settings *vcs, struct vino_framebuffer *fb){ u32 ctrl, intr; struct sgi_vino_channel *ch; const struct vino_data_norm *norm; dprintk("vino_dma_setup():\n"); vcs->field = 0; fb->frame_counter = 0; ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b; norm = &vino_data_norms[vcs->data_norm]; ch->page_index = 0; ch->line_count = 0; /* VINO line size register is set 8 bytes less than actual */ ch->line_size = vcs->line_size - 8; /* let VINO know where to transfer data */ ch->start_desc_tbl = fb->desc_table.dma; ch->next_4_desc = fb->desc_table.dma; /* give vino time to fetch the first four descriptors, 5 usec * should be more than enough time */ udelay(VINO_DESC_FETCH_DELAY); dprintk("vino_dma_setup(): start desc = %08x, next 4 desc = %08x\n", ch->start_desc_tbl, ch->next_4_desc); /* set the alpha register */ ch->alpha = vcs->alpha; /* set clipping registers */ ch->clip_start = VINO_CLIP_ODD(norm->odd.top + vcs->clipping.top / 2) | VINO_CLIP_EVEN(norm->even.top + vcs->clipping.top / 2) | VINO_CLIP_X(vcs->clipping.left); ch->clip_end = VINO_CLIP_ODD(norm->odd.top + vcs->clipping.bottom / 2 - 1) | VINO_CLIP_EVEN(norm->even.top + vcs->clipping.bottom / 2 - 1) | VINO_CLIP_X(vcs->clipping.right); /* set the size of actual content in the buffer (DECIMATION !) */ fb->data_size = ((vcs->clipping.right - vcs->clipping.left) / vcs->decimation) * ((vcs->clipping.bottom - vcs->clipping.top) / vcs->decimation) * vino_data_formats[vcs->data_format].bpp; ch->frame_rate = vcs->framert_reg; ctrl = vino->control; intr = vino->intr_status; if (vcs->channel == VINO_CHANNEL_A) { /* All interrupt conditions for this channel was cleared * so clear the interrupt status register and enable * interrupts */ intr &= ~VINO_INTSTAT_A; ctrl |= VINO_CTRL_A_INT; /* enable synchronization */ ctrl |= VINO_CTRL_A_SYNC_ENBL; /* enable frame assembly */ ctrl |= VINO_CTRL_A_INTERLEAVE_ENBL; /* set decimation used */ if (vcs->decimation < 2) ctrl &= ~VINO_CTRL_A_DEC_ENBL; else { ctrl |= VINO_CTRL_A_DEC_ENBL; ctrl &= ~VINO_CTRL_A_DEC_SCALE_MASK; ctrl |= (vcs->decimation - 1) << VINO_CTRL_A_DEC_SCALE_SHIFT; } /* select input interface */ if (vcs->input == VINO_INPUT_D1) ctrl |= VINO_CTRL_A_SELECT; else ctrl &= ~VINO_CTRL_A_SELECT; /* palette */ ctrl &= ~(VINO_CTRL_A_LUMA_ONLY | VINO_CTRL_A_RGB | VINO_CTRL_A_DITHER); } else { intr &= ~VINO_INTSTAT_B; ctrl |= VINO_CTRL_B_INT; ctrl |= VINO_CTRL_B_SYNC_ENBL; ctrl |= VINO_CTRL_B_INTERLEAVE_ENBL; if (vcs->decimation < 2) ctrl &= ~VINO_CTRL_B_DEC_ENBL; else { ctrl |= VINO_CTRL_B_DEC_ENBL; ctrl &= ~VINO_CTRL_B_DEC_SCALE_MASK; ctrl |= (vcs->decimation - 1) << VINO_CTRL_B_DEC_SCALE_SHIFT; } if (vcs->input == VINO_INPUT_D1) ctrl |= VINO_CTRL_B_SELECT; else ctrl &= ~VINO_CTRL_B_SELECT; ctrl &= ~(VINO_CTRL_B_LUMA_ONLY | VINO_CTRL_B_RGB | VINO_CTRL_B_DITHER); } /* set palette */ fb->data_format = vcs->data_format; switch (vcs->data_format) { case VINO_DATA_FMT_GREY: ctrl |= (vcs->channel == VINO_CHANNEL_A) ? VINO_CTRL_A_LUMA_ONLY : VINO_CTRL_B_LUMA_ONLY; break; case VINO_DATA_FMT_RGB32: ctrl |= (vcs->channel == VINO_CHANNEL_A) ? VINO_CTRL_A_RGB : VINO_CTRL_B_RGB; break; case VINO_DATA_FMT_YUV: /* nothing needs to be done */ break; case VINO_DATA_FMT_RGB332: ctrl |= (vcs->channel == VINO_CHANNEL_A) ? VINO_CTRL_A_RGB | VINO_CTRL_A_DITHER : VINO_CTRL_B_RGB | VINO_CTRL_B_DITHER; break; } vino->intr_status = intr; vino->control = ctrl; return 0;}/* (execute only with vino_lock locked) */static inline void vino_dma_start(struct vino_channel_settings *vcs){ u32 ctrl = vino->control; dprintk("vino_dma_start():\n"); ctrl |= (vcs->channel == VINO_CHANNEL_A) ? VINO_CTRL_A_DMA_ENBL : VINO_CTRL_B_DMA_ENBL; vino->control = ctrl;}/* (execute only with vino_lock locked) */static inline void vino_dma_stop(struct vino_channel_settings *vcs){ u32 ctrl = vino->control; ctrl &= (vcs->channel == VINO_CHANNEL_A) ? ~VINO_CTRL_A_DMA_ENBL : ~VINO_CTRL_B_DMA_ENBL; ctrl &= (vcs->channel == VINO_CHANNEL_A) ? ~VINO_CTRL_A_INT : ~VINO_CTRL_B_INT; vino->control = ctrl; dprintk("vino_dma_stop():\n");}/* * Load dummy page to descriptor registers. This prevents generating of * spurious interrupts. (execute only with vino_lock locked) */static void vino_clear_interrupt(struct vino_channel_settings *vcs){ struct sgi_vino_channel *ch; ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b; ch->page_index = 0; ch->line_count = 0; ch->start_desc_tbl = vino_drvdata->dummy_desc_table.dma; ch->next_4_desc = vino_drvdata->dummy_desc_table.dma; udelay(VINO_DESC_FETCH_DELAY); dprintk("channel %c clear interrupt condition\n", (vcs->channel == VINO_CHANNEL_A) ? 'A':'B');}static int vino_capture(struct vino_channel_settings *vcs, struct vino_framebuffer *fb){ int err = 0; unsigned long flags, flags2; spin_lock_irqsave(&fb->state_lock, flags); if (fb->state == VINO_FRAMEBUFFER_IN_USE) err = -EBUSY; fb->state = VINO_FRAMEBUFFER_IN_USE; spin_unlock_irqrestore(&fb->state_lock, flags); if (err) return err; spin_lock_irqsave(&vino_drvdata->vino_lock, flags); spin_lock_irqsave(&vino_drvdata->input_lock, flags2); vino_dma_setup(vcs, fb); vino_dma_start(vcs); spin_unlock_irqrestore(&vino_drvdata->input_lock, flags2); spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); return err;}staticstruct vino_framebuffer *vino_capture_enqueue(struct vino_channel_settings *vcs, unsigned int index){ struct vino_framebuffer *fb; unsigned long flags; dprintk("vino_capture_enqueue():\n"); spin_lock_irqsave(&vcs->capture_lock, flags); fb = vino_queue_add(&vcs->fb_queue, index); if (fb == NULL) { dprintk("vino_capture_enqueue(): vino_queue_add() failed, " "queue full?\n"); goto out; }out: spin_unlock_irqrestore(&vcs->capture_lock, flags); return fb;}static int vino_capture_next(struct vino_channel_settings *vcs, int start){ struct vino_framebuffer *fb; unsigned int incoming, id; int err = 0; unsigned long flags; dprintk("vino_capture_next():\n"); spin_lock_irqsave(&vcs->capture_lock, flags); if (start) { /* start capture only if capture isn't in progress already */ if (vcs->capturing) { spin_unlock_irqrestore(&vcs->capture_lock, flags); return 0; } } else { /* capture next frame: * stop capture if capturing is not set */ if (!vcs->capturing) { spin_unlock_irqrestore(&vcs->capture_lock, flags); return 0; } } err = vino_queue_get_incoming(&vcs->fb_queue, &incoming); if (err) { dprintk("vino_capture_next(): vino_queue_get_incoming() " "failed\n"); err = -EINVAL; goto out; } if (incoming == 0) { dprintk("vino_capture_next(): no buffers available\n"); goto out; } fb = vino_queue_peek(&vcs->fb_queue, &id); if (fb == NULL) { dprintk("vino_capture_next(): vino_queue_peek() failed\n"); err = -EINVAL; goto out; } if (start) { vcs->capturing = 1; } spin_unlock_irqrestore(&vcs->capture_lock, flags); err = vino_capture(vcs, fb); return err;out: vcs->capturing = 0; spin_unlock_irqrestore(&vcs->capture_lock, flags); return err;}static inline int vino_is_capturing(struct vino_channel_settings *vcs){ int ret; unsigned long flags; spin_lock_irqsave(&vcs->capture_lock, flags); ret = vcs->capturing; spin_unlock_irqrestore(&vcs->capture_lock, flags); return ret;}/* waits until a frame is captured */static int vino_wait_for_frame(struct vino_channel_settings *vcs){ wait_queue_t wait; int err = 0; dprintk("vino_wait_for_frame():\n"); init_waitqueue_entry(&wait, current); /* add ourselves into wait queue */ add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait); /* and set current state */ set_current_state(TASK_INTERRUPTIBLE); /* to ensure that schedule_timeout will return immediately * if VINO interrupt was triggred meanwhile */ schedule_timeout(HZ / 10); if (signal_pending(current)) err = -EINTR; remove_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait); dprintk("vino_wait_for_frame(): waiting for frame %s\n", err ? "failed" : "ok"); return err;}/* the function assumes that PAGE_SIZE % 4 == 0 */static void vino_convert_to_rgba(struct vino_framebuffer *fb) { unsigned char *pageptr; unsigned int page, i; unsigned char a; for (page = 0; page < fb->desc_table.page_count; page++) { pageptr = (unsigned char *)fb->desc_table.virtual[page]; for (i = 0; i < PAGE_SIZE; i += 4) { a = pageptr[0]; pageptr[0] = pageptr[3]; pageptr[1] = pageptr[2]; pageptr[2] = pageptr[1]; pageptr[3] = a; pageptr += 4; } }}/* checks if the buffer is in correct state and syncs data */static int vino_check_buffer(struct vino_channel_settings *vcs, struct vino_framebuffer *fb){ int err = 0; unsigned long flags; dprintk("vino_check_buffer():\n"); spin_lock_irqsave(&fb->state_lock, flags); switch (fb->state) { case VINO_FRAMEBUFFER_IN_USE: err = -EIO; break; case VINO_FRAMEBUFFER_READY: vino_sync_buffer(fb); fb->state = VINO_FRAMEBUFFER_UNUSED; break; default: err = -EINVAL; } spin_unlock_irqrestore(&fb->state_lock, flags); if (!err) { if (vino_pixel_conversion && (fb->data_format == VINO_DATA_FMT_RGB32)) { vino_convert_to_rgba(fb); } } else if (err && (err != -EINVAL)) { dprintk("vino_check_buffer(): buffer not ready\n"); spin_lock_irqsave(&vino_drvdata->vino_lock, flags); vino_dma_stop(vcs); vino_clear_interrupt(vcs); spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); } return err;}/* forcefully terminates capture */static void vino_capture_stop(struct vino_channel_settings *vcs){ unsigned int incoming = 0, outgoing = 0, id; unsigned long flags, flags2; dprintk("vino_capture_stop():\n"); spin_lock_irqsave(&vcs->capture_lock, flags); /* unset capturing to stop queue processing */ vcs->capturing = 0; spin_lock_irqsave(&vino_drvdata->vino_lock, flags2); vino_dma_stop(vcs); vino_clear_interrupt(vcs); spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags2); /* remove all items from the queue */ if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) { dprintk("vino_capture_stop(): " "vino_queue_get_incoming() failed\n"); goto out; } while (incoming > 0) { vino_queue_transfer(&vcs->fb_queue); if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) { dprintk("vino_capture_stop(): " "vino_queue_get_incoming() failed\n"); goto out; } } if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { dprintk("vino_capture_stop(): " "vino_queue_get_outgoing() failed\n"); goto out; } while (outgoing > 0) { vino_queue_remove(&vcs->fb_queue, &id); if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { dprintk("vino_capture_stop(): " "vino_queue_get_outgoing() failed\n"); goto out; } }out: spin_unlock_irqrestore(&vcs->capture_lock, flags);}#if 0 /* keep */;static int vino_capture_failed(struct vino_channel_settings *vcs){ struct vino_framebuffer *fb; unsigned long flags; unsigned int i; int ret; dprintk("vino_capture_failed():\n"); spin_lock_irqsave(&vino_drvdata->vino_lock, flags); vino_dma_stop(vcs); vino_clear_interrupt(vcs); spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); ret = vino_queue_get_incoming(&vcs->fb_queue, &i); if (ret == VINO_QUEUE_ERROR) { dprintk("vino_queue_get_incoming() failed\n"); return -EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -