ivtv-ioctl.c
来自「trident tm5600的linux驱动」· C语言 代码 · 共 1,920 行 · 第 1/4 页
C
1,920 行
/* ioctl system call Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "ivtv-driver.h"#include "ivtv-version.h"#include "ivtv-mailbox.h"#include "ivtv-i2c.h"#include "ivtv-queue.h"#include "ivtv-fileops.h"#include "ivtv-vbi.h"#include "ivtv-routing.h"#include "ivtv-streams.h"#include "ivtv-yuv.h"#include "ivtv-ioctl.h"#include "ivtv-gpio.h"#include "ivtv-controls.h"#include "ivtv-cards.h"#include <media/saa7127.h>#include <media/tveeprom.h>#include <media/v4l2-chip-ident.h>#include <linux/dvb/audio.h>#include <linux/i2c-id.h>u16 ivtv_service2vbi(int type){ switch (type) { case V4L2_SLICED_TELETEXT_B: return IVTV_SLICED_TYPE_TELETEXT_B; case V4L2_SLICED_CAPTION_525: return IVTV_SLICED_TYPE_CAPTION_525; case V4L2_SLICED_WSS_625: return IVTV_SLICED_TYPE_WSS_625; case V4L2_SLICED_VPS: return IVTV_SLICED_TYPE_VPS; default: return 0; }}static int valid_service_line(int field, int line, int is_pal){ return (is_pal && line >= 6 && (line != 23 || field == 0)) || (!is_pal && line >= 10 && line < 22);}static u16 select_service_from_set(int field, int line, u16 set, int is_pal){ u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); int i; set = set & valid_set; if (set == 0 || !valid_service_line(field, line, is_pal)) { return 0; } if (!is_pal) { if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) return V4L2_SLICED_CAPTION_525; } else { if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) return V4L2_SLICED_VPS; if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) return V4L2_SLICED_WSS_625; if (line == 23) return 0; } for (i = 0; i < 32; i++) { if ((1 << i) & set) return 1 << i; } return 0;}void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal){ u16 set = fmt->service_set; int f, l; fmt->service_set = 0; for (f = 0; f < 2; f++) { for (l = 0; l < 24; l++) { fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); } }}static void check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal){ int f, l; for (f = 0; f < 2; f++) { for (l = 0; l < 24; l++) { fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); } }}u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt){ int f, l; u16 set = 0; for (f = 0; f < 2; f++) { for (l = 0; l < 24; l++) { set |= fmt->service_lines[f][l]; } } return set;}void ivtv_set_osd_alpha(struct ivtv *itv){ ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state); ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key);}int ivtv_set_speed(struct ivtv *itv, int speed){ u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv_stream *s; int single_step = (speed == 1 || speed == -1); DEFINE_WAIT(wait); if (speed == 0) speed = 1000; /* No change? */ if (speed == itv->speed && !single_step) return 0; s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; if (single_step && (speed < 0) == (itv->speed < 0)) { /* Single step video and no need to change direction */ ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); itv->speed = speed; return 0; } if (single_step) /* Need to change direction */ speed = speed < 0 ? -1000 : 1000; data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0; data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0; data[1] = (speed < 0); data[2] = speed < 0 ? 3 : 7; data[3] = itv->params.video_b_frames; data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0; data[5] = 0; data[6] = 0; if (speed == 1500 || speed == -1500) data[0] |= 1; else if (speed == 2000 || speed == -2000) data[0] |= 2; else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed); else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed); /* If not decoding, just change speed setting */ if (atomic_read(&itv->decoding) > 0) { int got_sig = 0; /* Stop all DMA and decoding activity */ ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0); /* Wait for any DMA to finish */ prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); while (itv->i_flags & IVTV_F_I_DMA) { got_sig = signal_pending(current); if (got_sig) break; got_sig = 0; schedule(); } finish_wait(&itv->dma_waitq, &wait); if (got_sig) return -EINTR; /* Change Speed safely */ ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data); IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", data[0], data[1], data[2], data[3], data[4], data[5], data[6]); } if (single_step) { speed = (speed < 0) ? -1 : 1; ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); } itv->speed = speed; return 0;}static int ivtv_validate_speed(int cur_speed, int new_speed){ int fact = new_speed < 0 ? -1 : 1; int s; if (cur_speed == 0) cur_speed = 1000; if (new_speed < 0) new_speed = -new_speed; if (cur_speed < 0) cur_speed = -cur_speed; if (cur_speed <= new_speed) { if (new_speed > 1500) return fact * 2000; if (new_speed > 1000) return fact * 1500; } else { if (new_speed >= 2000) return fact * 2000; if (new_speed >= 1500) return fact * 1500; if (new_speed >= 1000) return fact * 1000; } if (new_speed == 0) return 1000; if (new_speed == 1 || new_speed == 1000) return fact * new_speed; s = new_speed; new_speed = 1000 / new_speed; if (1000 / cur_speed == new_speed) new_speed += (cur_speed < s) ? -1 : 1; if (new_speed > 60) return 1000 / (fact * 60); return 1000 / (fact * new_speed);}static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, struct video_command *vc, int try){ struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; switch (vc->cmd) { case VIDEO_CMD_PLAY: { vc->flags = 0; vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed); if (vc->play.speed < 0) vc->play.format = VIDEO_PLAY_FMT_GOP; if (try) break; if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG) return -EBUSY; if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { /* forces ivtv_set_speed to be called */ itv->speed = 0; } return ivtv_start_decoding(id, vc->play.speed); } case VIDEO_CMD_STOP: vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK; if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY) vc->stop.pts = 0; if (try) break; if (atomic_read(&itv->decoding) == 0) return 0; if (itv->output_mode != OUT_MPG) return -EBUSY; itv->output_mode = OUT_NONE; return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts); case VIDEO_CMD_FREEZE: vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK; if (try) break; if (itv->output_mode != OUT_MPG) return -EBUSY; if (atomic_read(&itv->decoding) > 0) { ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, (vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0); set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); } break; case VIDEO_CMD_CONTINUE: vc->flags = 0; if (try) break; if (itv->output_mode != OUT_MPG) return -EBUSY; if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { int speed = itv->speed; itv->speed = 0; return ivtv_start_decoding(id, speed); } break; default: return -EINVAL; } return 0;}static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt){ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; vbifmt->reserved[0] = 0; vbifmt->reserved[1] = 0; if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) return -EINVAL; vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; if (itv->is_60hz) { vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; } else { vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; } vbifmt->service_set = ivtv_get_service_set(vbifmt); return 0;}static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt){ struct ivtv_open_id *id = fh; struct ivtv *itv = id->itv; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; pixfmt->width = itv->params.width; pixfmt->height = itv->params.height; pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; pixfmt->field = V4L2_FIELD_INTERLACED; pixfmt->priv = 0; if (id->type == IVTV_ENC_STREAM_TYPE_YUV) { pixfmt->pixelformat = V4L2_PIX_FMT_HM12; /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ pixfmt->sizeimage = pixfmt->height * pixfmt->width + pixfmt->height * (pixfmt->width / 2); pixfmt->bytesperline = 720; } else { pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; pixfmt->sizeimage = 128 * 1024; pixfmt->bytesperline = 0; } return 0;}static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt){ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; vbifmt->sampling_rate = 27000000; vbifmt->offset = 248; vbifmt->samples_per_line = itv->vbi.raw_decoder_line_size - 4; vbifmt->sample_format = V4L2_PIX_FMT_GREY; vbifmt->start[0] = itv->vbi.start[0]; vbifmt->start[1] = itv->vbi.start[1]; vbifmt->count[0] = vbifmt->count[1] = itv->vbi.count; vbifmt->flags = 0; vbifmt->reserved[0] = 0; vbifmt->reserved[1] = 0; return 0;}static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt){ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; struct ivtv_open_id *id = fh; struct ivtv *itv = id->itv; vbifmt->reserved[0] = 0; vbifmt->reserved[1] = 0; vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; if (id->type == IVTV_DEC_STREAM_TYPE_VBI) { vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; ivtv_expand_service_set(vbifmt, itv->is_50hz); return 0; } itv->video_dec_func(itv, VIDIOC_G_FMT, fmt); vbifmt->service_set = ivtv_get_service_set(vbifmt); return 0;}static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt){ struct ivtv_open_id *id = fh; struct ivtv *itv = id->itv; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; pixfmt->width = itv->main_rect.width; pixfmt->height = itv->main_rect.height; pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; pixfmt->field = V4L2_FIELD_INTERLACED; pixfmt->priv = 0; if (id->type == IVTV_DEC_STREAM_TYPE_YUV) { switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { case IVTV_YUV_MODE_INTERLACED: pixfmt->field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB; break; case IVTV_YUV_MODE_PROGRESSIVE: pixfmt->field = V4L2_FIELD_NONE; break; default: pixfmt->field = V4L2_FIELD_ANY; break; } pixfmt->pixelformat = V4L2_PIX_FMT_HM12; pixfmt->bytesperline = 720; pixfmt->width = itv->yuv_info.v4l2_src_w; pixfmt->height = itv->yuv_info.v4l2_src_h; /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ pixfmt->sizeimage = 1080 * ((pixfmt->height + 31) & ~31); } else { pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; pixfmt->sizeimage = 128 * 1024; pixfmt->bytesperline = 0; } return 0;}static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt){ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; struct v4l2_window *winfmt = &fmt->fmt.win; if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; winfmt->chromakey = itv->osd_chroma_key; winfmt->global_alpha = itv->osd_global_alpha; winfmt->field = V4L2_FIELD_INTERLACED; winfmt->clips = NULL; winfmt->clipcount = 0; winfmt->bitmap = NULL; winfmt->w.top = winfmt->w.left = 0; winfmt->w.width = itv->osd_rect.width; winfmt->w.height = itv->osd_rect.height; return 0;}static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt){ return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);}static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt){ struct ivtv_open_id *id = fh; struct ivtv *itv = id->itv; int w = fmt->fmt.pix.width; int h = fmt->fmt.pix.height; w = min(w, 720); w = max(w, 2); h = min(h, itv->is_50hz ? 576 : 480); h = max(h, 2); ivtv_g_fmt_vid_cap(file, fh, fmt); fmt->fmt.pix.width = w; fmt->fmt.pix.height = h; return 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?