/* License: GPL * Author: Kevin Thayer * * This file will hold API related functions, both internal (firmware api) * and external (v4l2, etc) * */ #include "ivtv.h" /* Fix the v4l2 api breakage - need to define if still using the old api */ #ifndef VIDIOC_OVERLAY_OLD #define VIDIOC_OVERLAY_OLD _IOWR ('V', 14, int) #define VIDIOC_S_PARM_OLD _IOW ('V', 22, struct v4l2_streamparm) #define VIDIOC_S_CTRL_OLD _IOW ('V', 28, struct v4l2_control) #define VIDIOC_G_AUDIO_OLD _IOWR ('V', 33, struct v4l2_audio) #define VIDIOC_G_AUDOUT_OLD _IOWR ('V', 49, struct v4l2_audioout) #endif /* FIXME need to find a good value */ #define V4L2_PIX_FMT_CMP_MPG2 77777 #define IVTV_V4L2_MAX_MINOR 15 static int ivtv_v4l2_init(struct video_device *v); static int ivtv_v4l2_close(struct inode *inode, struct file *filp); static int ivtv_v4l2_open(struct inode *inode, struct file *filp); static int ivtv_v4l2_read(struct file *filp, char *buf, size_t count, loff_t *pos); static ssize_t ivtv_v4l2_write(struct file *filp, const char *buf, size_t count, loff_t *pos); static int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); static int ivtv_v4l2_pre_init(struct ivtv *itv); struct file_operations ivtv_v4l2_fops = { read: ivtv_v4l2_read, write: ivtv_v4l2_write, open: ivtv_v4l2_open, ioctl: ivtv_v4l2_ioctl, release: ivtv_v4l2_close, poll: ivtv_poll, }; /* FIXME Static variables for the various card types go here */ static struct video_device tmk_v4l2dev = { /*values that work with the author's card */ .name = "Vanilla iTVC15 card", .type = VFL_TYPE_GRABBER, .type2 = VID_TYPE_CAPTURE, .fops = &ivtv_v4l2_fops, .initialize = ivtv_v4l2_init, }; /* some tuner table values can change, so allocate this dynamically when you use it*/ struct v4l2_tuner tmk_tuners[2] = { { .index = 0, .name = "ivtv TV Tuner", .type = V4L2_TUNER_ANALOG_TV, .capability = (V4L2_TUNER_CAP_NORM|V4L2_TUNER_CAP_STEREO), .rxsubchans = (V4L2_TUNER_SUB_STEREO), .audmode = V4L2_TUNER_MODE_STEREO, .signal = 0, .afc = 0, .reserved = {0,0,0,0} },{ .index = 1, .name = "ivtv Radio", .type = V4L2_TUNER_RADIO, .capability = (V4L2_TUNER_CAP_STEREO), .rxsubchans = 0, .audmode = V4L2_TUNER_MODE_STEREO, .signal = 0, .afc = 0, .reserved = {0,0,0,0} } }; struct v4l2_standard tmk_standards[3] = { { .index = 0, .id = V4L2_STD_NTSC, .name = "NTSC", .frameperiod = { .numerator = 1001, .denominator= 30000}, .framelines = 525, .reserved = {0,0,0,0} },{ .index = 1, .id = V4L2_STD_PAL, .name = "PAL", .frameperiod = { .numerator = 1, .denominator= 25}, .framelines = 625, .reserved = {0,0,0,0} },{ .index = 2, .id = V4L2_STD_SECAM, .name = "SECAM", .frameperiod = { .numerator = 1, .denominator= 25}, .framelines = 625, .reserved = {0,0,0,0} } }; struct v4l2_input tmk_inputs[10] = { /*values that work with the author's card */ { .index = 0, .name = "Composite 0", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 1, .tuner = 0, .status = 0, },{ .index = 1, .name = "Composite 1", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 1, .tuner = 0, .status = 0, },{ .index = 2, .name = "Composite 2", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 1, .tuner = 0, .status = 0, },{ .index = 3, .name = "Composite 3", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 1, .tuner = 0, .status = 0, },{ .index = 4, .name = "Tuner 0", .type = V4L2_INPUT_TYPE_TUNER, .audioset = 0, .tuner = 0, .status = 0, },{ .index = 5, .name = "Composite 4", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 1, .tuner = 0, .status = 0, },{ .index = 6, .name = "S-Video 0", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 1, .tuner = 0, .status = 0, },{ .index = 7, .name = "S-Video 1", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 1, .tuner = 0, .status = 0, },{ .index = 8, .name = "S-Video 2", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 1, .tuner = 0, .status = 0, },{ .index = 9, .name = "S-Video 3", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 1, .tuner = 0, .status = 0, } }; //FIXME capability and mode might be wrong struct v4l2_audio tmk_audio_inputs[2] = { {0,"Tuner Audio In",0,0,}, {1,"Audio Line In", 0,0,}, }; int tmk_audio_mapping[] = { 0,3, /* Input 0 is msp input 3 */ 1,1, /* input 1 is msp input 1 */ 0,0 /* you're at end of list! */ }; struct v4l2_queryctrl ivtv_ctrl_menu_freq = { .id = V4L2_CID_IVTV_FREQ, .type = V4L2_CTRL_TYPE_MENU, .name = "Frequency", .minimum = 0, .maximum = 2, .step = 1, .default_value = 2, .flags = 0, .reserved = {0,0} }; struct v4l2_querymenu ivtv_ctrl_query_freq[] = { /* ID, Index, Name, Reserved */ {V4L2_CID_IVTV_FREQ, 0, "32kHz", 0 }, {V4L2_CID_IVTV_FREQ, 1, "44.1kHz", 0 }, {V4L2_CID_IVTV_FREQ, 2, "48kHz", 0 } }; u32 ivtv_audio_tbl_freq[] = { /* setting */ 0x2 /* 32kHz binary 10 */, 0x0 /* 44.1kHz binary 00 */, 0x1 /* 48kHz binary 01 */ }; u32 ivtv_audio_mask_freq = 0x3; struct v4l2_queryctrl ivtv_ctrl_menu_enc = { .id = V4L2_CID_IVTV_ENC, .type = V4L2_CTRL_TYPE_MENU, .name = "Encoding", .minimum = 0, .maximum = 2, .step = 1, .default_value = 1, .flags = 0, .reserved = {0,0} }; struct v4l2_querymenu ivtv_ctrl_query_enc[] = { /* ID, Index, Name, Reserved */ {V4L2_CID_IVTV_ENC, 0, "Layer 1", 0}, {V4L2_CID_IVTV_ENC, 1, "Layer 2", 0}, {V4L2_CID_IVTV_ENC, 2, "Layer 3(?)", 0} }; u32 ivtv_audio_tbl_enc[] = { /* setting */ 0x1 << 2 /* Layer 1 binary 0100 */, 0x2 << 2 /* Layer 2 binary 1000 */, 0x3 << 2 /* Layer 3(?) binary 1100 */ }; u32 ivtv_audio_mask_enc = 0xC; struct v4l2_queryctrl ivtv_ctrl_menu_bitrate = { .id = V4L2_CID_IVTV_BITRATE, .type = V4L2_CTRL_TYPE_MENU, .name = "Audio Bitrate", .minimum = 0, .maximum = 14, .step = 1, .default_value = 14, .flags = 0, .reserved = {0,0} }; struct v4l2_querymenu ivtv_ctrl_query_bitrate[] = { /* ID, Index, Name, Reserved */ {V4L2_CID_IVTV_BITRATE, 0, "[L1/L2] Free fmt", 0}, {V4L2_CID_IVTV_BITRATE, 1, "[L1/L2] 32k/32k", 0}, {V4L2_CID_IVTV_BITRATE, 2, "[L1/L2] 64k/48k", 0}, {V4L2_CID_IVTV_BITRATE, 3, "[L1/L2] 96k/56k", 0}, {V4L2_CID_IVTV_BITRATE, 4, "[L1/L2] 128k/64k", 0}, {V4L2_CID_IVTV_BITRATE, 5, "[L1/L2] 160k/80k", 0}, {V4L2_CID_IVTV_BITRATE, 6, "[L1/L2] 192k/96k", 0}, {V4L2_CID_IVTV_BITRATE, 7, "[L1/L2] 224k/112k", 0}, {V4L2_CID_IVTV_BITRATE, 8, "[L1/L2] 256k/128k", 0}, {V4L2_CID_IVTV_BITRATE, 9, "[L1/L2] 288k/160k", 0}, {V4L2_CID_IVTV_BITRATE, 10, "[L1/L2] 320k/192k", 0}, {V4L2_CID_IVTV_BITRATE, 11, "[L1/L2] 352k/224k", 0}, {V4L2_CID_IVTV_BITRATE, 12, "[L1/L2] 384k/256k", 0}, {V4L2_CID_IVTV_BITRATE, 13, "[L1/L2] 416k/320k", 0}, {V4L2_CID_IVTV_BITRATE, 14, "[L1/L2] 448k/384k", 0}, }; u32 ivtv_audio_tbl_bitrate[] = { /* setting */ 0x0 << 4 /* [L1/L2] Free fmt binary 0000 */, 0x1 << 4 /* [L1/L2] 32k/32k, binary 0001 */, 0x2 << 4 /* [L1/L2] 64k/48k, binary 0010 */, 0x3 << 4 /* [L1/L2] 96k/56k, binary 0011 */, 0x4 << 4 /* [L1/L2] 128k/64k, binary 0100 */, 0x5 << 4 /* [L1/L2] 160k/80k, binary 0101 */, 0x6 << 4 /* [L1/L2] 192k/96k, binary 0110 */, 0x7 << 4 /* [L1/L2] 224k/112k, binary 0111 */, 0x8 << 4 /* [L1/L2] 256k/128k, binary 1000 */, 0x9 << 4 /* [L1/L2] 288k/160k, binary 1001 */, 0xA << 4 /* [L1/L2] 320k/192k, binary 1010 */, 0xB << 4 /* [L1/L2] 352k/224k, binary 1011 */, 0xC << 4 /* [L1/L2] 384k/256k, binary 1100 */, 0xD << 4 /* [L1/L2] 416k/320k, binary 1101 */, 0xE << 4 /* [L1/L2] 448k/384k, binary 1110 */ }; u32 ivtv_audio_mask_bitrate = 0xF0; struct v4l2_queryctrl ivtv_ctrl_menu_mono = { .id = V4L2_CID_IVTV_MONO, .type = V4L2_CTRL_TYPE_MENU, .name = "Mono/Stereo", .minimum = 0, .maximum = 3, .step = 1, .default_value = 0, .flags = 0, .reserved = {0,0} }; struct v4l2_querymenu ivtv_ctrl_query_mono[] = { /* ID, Index, Name, Reserved */ {V4L2_CID_IVTV_MONO, 0, "Stereo", 0}, {V4L2_CID_IVTV_MONO, 1, "JointStereo", 0}, {V4L2_CID_IVTV_MONO, 2, "Dual", 0}, {V4L2_CID_IVTV_MONO, 3, "Mono", 0} }; u32 ivtv_audio_tbl_mono[] = { /* setting */ 0x0 << 8 /* Stereo, binary 00 */, 0x1 << 8 /* JointStereo, binary 01 */, 0x2 << 8 /* Dual, binary 10 */, 0x3 << 8 /* Mono, binary 11 */ }; u32 ivtv_audio_mask_mono = 0x300; struct v4l2_queryctrl ivtv_ctrl_menu_joint = { .id = V4L2_CID_IVTV_JOINT, .type = V4L2_CTRL_TYPE_MENU, .name = "Joint extension", .minimum = 0, .maximum = 3, .step = 1, .default_value = 0, .flags = 0, .reserved = {0,0} }; struct v4l2_querymenu ivtv_ctrl_query_joint[] = { /* ID, Index, Name, Reserved */ {V4L2_CID_IVTV_JOINT, 0, "Subbands 4-31/bound=4", 0}, {V4L2_CID_IVTV_JOINT, 1, "Subbands 8-31/bound=8", 0}, {V4L2_CID_IVTV_JOINT, 2, "Subbands 12-31/bound=12", 0}, {V4L2_CID_IVTV_JOINT, 3, "Subbands 16-31/bound=16", 0} }; u32 ivtv_audio_tbl_joint[] = { /* setting */ 0x0 << 10 /* Subbands 4-31/bound=4, binary 00 */, 0x1 << 10 /* Subbands 8-31/bound=8, binary 01 */, 0x2 << 10 /* Subbands 12-31/bound=12, binary 10 */, 0x3 << 10 /* Subbands 16-31/bound=16, binary 11 */ }; u32 ivtv_audio_mask_joint = 0xc00; struct v4l2_queryctrl ivtv_ctrl_menu_emphasis = { .id = V4L2_CID_IVTV_EMPHASIS, .type = V4L2_CTRL_TYPE_MENU, .name = "Emphasis", .minimum = 0, .maximum = 2, .step = 1, .default_value = 0, .flags = 0, .reserved = {0,0} }; struct v4l2_querymenu ivtv_ctrl_query_emphasis[] = { /* ID, Index, Name, Reserved */ {V4L2_CID_IVTV_EMPHASIS, 0, "None", 0}, {V4L2_CID_IVTV_EMPHASIS, 1, "50/15uS", 0}, {V4L2_CID_IVTV_EMPHASIS, 2, "CCITT J.17", 0} }; u32 ivtv_audio_tbl_emphasis[] = { /* setting */ 0x0 << 12 /* None, binary 00 */, 0x1 << 12 /* 50/15uS, binary 01 */, 0x3 << 12 /* CCITT J.17, binary 11 */ }; u32 ivtv_audio_mask_emphasis = 0x3000; struct v4l2_queryctrl ivtv_ctrl_menu_crc = { .id = V4L2_CID_IVTV_CRC, .type = V4L2_CTRL_TYPE_MENU, .name = "Audio CRC", .minimum = 0, .maximum = 1, .step = 1, .default_value = 0, .flags = 0, .reserved = {0,0} }; struct v4l2_querymenu ivtv_ctrl_query_crc[] = { /* ID, Index, Name, Reserved */ {V4L2_CID_IVTV_CRC, 0, "off", 0}, {V4L2_CID_IVTV_CRC, 1, "on", 0} }; u32 ivtv_audio_tbl_crc[] = { /* setting */ 0x0 << 14 /* off, binary 0 */, 0x1 << 14 /* on, binary 1 */ }; u32 ivtv_audio_mask_crc = 0x4000; struct v4l2_queryctrl ivtv_ctrl_menu_copyright = { .id = V4L2_CID_IVTV_COPYRIGHT, .type = V4L2_CTRL_TYPE_MENU, .name = "Copyright", .minimum = 0, .maximum = 1, .step = 1, .default_value = 0, .flags = 0, .reserved = {0,0} }; struct v4l2_querymenu ivtv_ctrl_query_copyright[] = { /* ID, Index, Name, Reserved */ {V4L2_CID_IVTV_COPYRIGHT, 0, "off", 0}, {V4L2_CID_IVTV_COPYRIGHT, 1, "on", 0} }; u32 ivtv_audio_tbl_copyright[] = { /* setting */ 0x0 << 15 /* off, binary 0 */, 0x1 << 15 /* on, binary 1 */ }; u32 ivtv_audio_mask_copyright = 0x8000; struct v4l2_queryctrl ivtv_ctrl_menu_generation = { .id = V4L2_CID_IVTV_GEN, .type = V4L2_CTRL_TYPE_MENU, .name = "Generation", .minimum = 0, .maximum = 1, .step = 1, .default_value = 0, .flags = 0, .reserved = {0,0} }; struct v4l2_querymenu ivtv_ctrl_query_generation[] = { /* ID, Index, Name, Reserved */ {V4L2_CID_IVTV_GEN, 0, "copy", 0}, {V4L2_CID_IVTV_GEN, 1, "original", 0} }; u32 ivtv_audio_tbl_generation[] = { /* setting */ 0x0 << 16 /* copy, binary 0 */, 0x1 << 16 /* original, binary 1 */ }; u32 ivtv_audio_mask_generation = 0x10000; /* 3 stream types: mpeg, yuv, passthru */ struct ivtv_v4l2_stream tmk_mpg_stream = { /*MPEG*/ .s_flags = 0, .id = -1, .v4l_reg_type = VFL_TYPE_GRABBER, .format = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .fmt = { .pix = { .width = 720, .height = 480, .field = V4L2_FIELD_INTERLACED, .sizeimage = (128*1024), } }, }, .controlcount = 0, .controls = NULL }; struct ivtv_v4l2_stream tmk_yuv_stream = { /*YUV*/ .s_flags = 0, .id = -1, .v4l_reg_type = VFL_TYPE_GRABBER, .format = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .fmt = { .pix = { .width = 720, .height = 480, .field = V4L2_FIELD_INTERLACED, .sizeimage = (720*720), } }, }, .controlcount = 0, .controls = NULL }; //FIXME these settings are way wrong struct ivtv_v4l2_stream tmk_vbi_stream = { .s_flags = 0, .id = -1, .v4l_reg_type = VFL_TYPE_VBI, .format = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .fmt = { .pix = { .width = 720, .height = 480, .field = V4L2_FIELD_INTERLACED, .sizeimage = (128*1024), } }, }, .controlcount = 0, .controls = NULL }; struct ivtv_v4l2_stream dec_mpg_stream = { /*Decoder MPG*/ .s_flags = 0, .id = -1, .v4l_reg_type = VFL_TYPE_GRABBER, .format = { .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, .fmt = { .pix = { .width = 720, .height = 480, .field = V4L2_FIELD_INTERLACED, .sizeimage = (128*1024), } }, }, .controlcount = 0, .controls = NULL }; struct ivtv_v4l2_stream dec_yuv_stream = { /*Decoder YUV*/ .s_flags = 0, .id = -1, .v4l_reg_type = VFL_TYPE_GRABBER, .format = { .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, .fmt = { .pix = { .width = 720, .height = 480, .field = V4L2_FIELD_INTERLACED, .sizeimage = (720*720), } }, }, .controlcount = 0, .controls = NULL }; /* Initialize v4l2 variables and register v4l2 device */ int ivtv_v4l2_setup(struct ivtv *itv) { int x, cont, retval; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 setup\n"); /* Set owner for auto usage-incrementing and such */ SET_MODULE_OWNER(&ivtv_v4l2_fops); //switch based on card type // and fill in appropriate v4l2 device switch (itv->card_type) { case IVTV_350_V1: IVTV_DEBUG(IVTV_DEBUG_INFO,"Configuring 350rev1 card\n"); itv->v4l2.streamcount = IVTV_350_V1_STREAMS; /* Disable dec yuv buffers if requested */ if (itv->options.dec_yuv_buffers == 0) itv->v4l2.streamcount--; /* FIXME wrong values */ itv->v4l2.capabilities = (V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_TUNER| V4L2_CAP_AUDIO|V4L2_CAP_READWRITE| V4L2_CAP_VIDEO_OUTPUT); break; case IVTV_250_V2: IVTV_DEBUG(IVTV_DEBUG_INFO,"Configuring 250rev2 card\n"); itv->v4l2.streamcount = IVTV_250_V2_STREAMS; /* FIXME wrong values */ itv->v4l2.capabilities = (V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_TUNER| V4L2_CAP_AUDIO|V4L2_CAP_READWRITE); break; case IVTV_250_V1: IVTV_DEBUG(IVTV_DEBUG_INFO,"Configuring 250rev1 card\n"); default: /* shouldn't happen, treat like V1 */ itv->v4l2.streamcount = IVTV_250_V1_STREAMS; itv->v4l2.capabilities = (V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_TUNER| V4L2_CAP_AUDIO|V4L2_CAP_READWRITE); break; } /* Initial settings */ itv->v4l2.codec.bitrate_mode = 0; itv->v4l2.codec.bitrate = 8000000; itv->v4l2.codec.bitrate_peak = 16000000; itv->v4l2.codec.stream_type = IVTV_STREAM_PS; itv->v4l2.codec.bframes = 3; itv->v4l2.codec.gop_closure = 0; itv->v4l2.codec.dnr_mode = 0; itv->v4l2.codec.dnr_type = 0; itv->v4l2.codec.dnr_spatial = 0; itv->v4l2.codec.dnr_temporal = 0; itv->v4l2.codec.aspect = 2; itv->dec_options.hide_last_frame= 1; itv->dec_options.pts_low = 0; itv->dec_options.pts_hi = 0; itv->dec_options.gop_offset = 0; itv->dec_options.mute_frames = 0; /* Ctrls */ itv->dec_options.sf_mute = 1; itv->dec_options.aud_mute = 0; itv->dec_options.smooth = 1; itv->dec_options.fr_mask = 2; itv->dec_options.fr_field = 1; itv->dec_options.decbuffers = 1; itv->dec_options.prebuffer = 1; /* Allocate streams */ itv->v4l2.streams = (struct ivtv_v4l2_stream *) kmalloc((itv->v4l2.streamcount * sizeof(struct ivtv_v4l2_stream)), GFP_KERNEL); if (NULL == itv->v4l2.streams) { IVTV_DEBUG(IVTV_DEBUG_ERR, "Couldn't allocate v4l2 streams\n"); retval = -ENOMEM; goto ivtv_stream_fail; } /* pre-init */ retval = ivtv_v4l2_pre_init(itv); if (retval < 0) { IVTV_DEBUG(IVTV_DEBUG_ERR, "Error in pre-init\n"); goto ivtv_pre_init_fail; } /* Fill in streams with some defaults */ memcpy(&itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG], &tmk_mpg_stream, sizeof(struct ivtv_v4l2_stream)); memcpy(&itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV], &tmk_yuv_stream, sizeof(struct ivtv_v4l2_stream)); memcpy(&itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI], &tmk_vbi_stream, sizeof(struct ivtv_v4l2_stream)); /* Set some card-specific per-stream stuff here */ switch (itv->card_type) { case IVTV_350_V1: memcpy(&itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG], &dec_mpg_stream, sizeof(struct ivtv_v4l2_stream)); if (itv->options.dec_yuv_buffers !=0) { memcpy(&itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV], &dec_yuv_stream, sizeof(struct ivtv_v4l2_stream)); } break; case IVTV_250_V2: break; case IVTV_250_V1: default: /* shouldn't happen, treat like V1 */ break; } for (x=0; x < itv->v4l2.streamcount ; x++) { init_waitqueue_head(&itv->v4l2.streams[x].waitq); memcpy(&itv->v4l2.streams[x].v4l2dev, &tmk_v4l2dev, sizeof(struct video_device)); itv->v4l2.streams[x].v4l2dev.priv = itv; itv->v4l2.streams[x].ubytes = 0; itv->v4l2.streams[x].free_q.vdev = &itv->v4l2.streams[x].v4l2dev; itv->v4l2.streams[x].full_q.vdev = &itv->v4l2.streams[x].v4l2dev; itv->v4l2.streams[x].dma_q.vdev = &itv->v4l2.streams[x].v4l2dev; INIT_LIST_HEAD(&itv->v4l2.streams[x].free_q.list); INIT_LIST_HEAD(&itv->v4l2.streams[x].full_q.list); INIT_LIST_HEAD(&itv->v4l2.streams[x].dma_q.list); retval = ivtv_init_queue(itv, &itv->v4l2.streams[x].full_q, 0, itv->v4l2.streams[x].format.type); if (retval < 0) { IVTV_DEBUG(IVTV_DEBUG_ERR,"Error on init_queue 1\n"); goto ivtv_initq_fail; } retval = ivtv_init_queue(itv, &itv->v4l2.streams[x].dma_q, 0, itv->v4l2.streams[x].format.type); if (retval < 0) { IVTV_DEBUG(IVTV_DEBUG_ERR,"Error on init_queue 2\n"); goto ivtv_initq_fail; } } /* Some streams have specific values */ x = ivtv_init_queue(itv, &itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG].free_q, mpg_buffers, itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG].format.type); x = ivtv_init_queue(itv, &itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV].free_q, yuv_buffers, itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV].format.type); x = ivtv_init_queue(itv, &itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI].free_q, vbi_buffers, itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI].format.type); /* set default minors */ itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_MPG].v4l2dev.minor = itv->num; itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_YUV].v4l2dev.minor = itv->num + IVTV_V4L2_YUV_OFFSET; //vbi will get offset by v4l, so no offset needed by us itv->v4l2.streams[IVTV_ENC_STREAM_TYPE_VBI].v4l2dev.minor = itv->num; /* Set any card-specific per-stream stuff here */ switch (itv->card_type) { case IVTV_350_V1: /* allocate buffers for decoder */ x = ivtv_init_queue(itv, &itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG] .free_q, dec_mpg_buffers, itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG].format.type); itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG].v4l2dev.minor = itv->num + IVTV_V4L2_DEC_OFFSET; if (itv->options.dec_yuv_buffers != 0) { x = ivtv_init_queue(itv, &itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV] .free_q, dec_yuv_buffers, itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV].format.type); itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV].v4l2dev.minor = itv->num + IVTV_V4L2_YUV_OFFSET + IVTV_V4L2_DEC_OFFSET; } /* Set poll for decoder parts */ itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG].v4l2dev.fops->poll = ivtv_dec_poll; if (itv->options.dec_yuv_buffers) itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_YUV].v4l2dev.fops->poll = ivtv_dec_poll; break; case IVTV_250_V2: break; case IVTV_250_V1: default: /* shouldn't happen, treat like V1 */ break; } /* allocate minor, register, loop until works or out of range */ for (x=0;x < itv->v4l2.streamcount; x++) { cont = 0; do { if(video_register_device(&itv->v4l2.streams[x].v4l2dev, itv->v4l2.streams[x].v4l_reg_type, itv->v4l2.streams[x].v4l2dev.minor)) { IVTV_DEBUG(IVTV_DEBUG_ERR, "Device or minor %d not accepted\n", itv->v4l2.streams[x].v4l2dev.minor); itv->v4l2.streams[x].v4l2dev.minor++; } else { IVTV_DEBUG(IVTV_DEBUG_ERR, "Registered v4l2 device, minor %d\n", itv->v4l2.streams[x].v4l2dev.minor); cont = 1; } } while ((0 == cont) && (itv->v4l2.streams[x].v4l2dev.minor<=IVTV_V4L2_MAX_MINOR)); if (0 == cont) { IVTV_DEBUG(IVTV_DEBUG_ERR,"Couldn't register v4l2 device!\n"); /* invalidate so we don't try to unload the device */ itv->v4l2.streams[x].v4l2dev.minor = -1; return -ENODEV; } } return 0; ivtv_pre_init_fail: /* needs lots of queue cleanup here -axboe */ ivtv_initq_fail: kfree(itv->v4l2.streams); ivtv_stream_fail: return retval; } /* After setting the audio.active param, call this to * get the right input.. think of it as a resolver */ int ivtv_set_audio(struct ivtv *itv, int *map) { int input,msp_input; struct msp_matrix mspm; do { input = *(map++); msp_input = *(map++); if (input == itv->v4l2.audio.active) { IVTV_DEBUG(IVTV_DEBUG_INFO, "Setting audio to input %d\n", msp_input); mspm.input = msp_input; mspm.output = itv->v4l2.audio_output; ivtv_call_i2c_client(itv, IVTV_MSP3400_I2C_ADDR, MSP_SET_MATRIX, &mspm); return 0; } } while ((msp_input !=0) || (input != 0)); IVTV_DEBUG(IVTV_DEBUG_ERR,"Invalid audio input, shouldn't happen!\n"); return -EINVAL; } u32 ivtv_pause_encoder(struct ivtv *itv, int cmd) { u32 data[16], result=0; int x; data[0] = 0; /* 0 = pause, 1 = unpause */ if (cmd) data[0] = 1; x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_PAUSE_ENCODER, &result,1, &data[0]); return result; } /* Called if v4l2 registration is successful. Set video mode here, at least * that is required on PAL cards */ int ivtv_v4l2_init(struct video_device *v) { struct ivtv *ivtv = v->priv; u32 data[IVTV_MBOX_MAX_DATA], result; int x; /* * only set it on minor 0 */ if (v->minor != 0) return 0; memset(data, 0, sizeof(data)); /* set display standard */ if (ivtv_pal) data[0] = 1; else data[0] = 0; x = ivtv_api(ivtv->dec_mbox, &ivtv->dec_msem, IVTV_API_DEC_DISP_STANDARD, &result, 1, &data[0]); return 0; } /* Called before v4l2 registration */ int ivtv_v4l2_pre_init(struct ivtv *itv) { int x, temp, retval = -1; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 init\n"); //Allocate based on card type // allocate capabilities and such based on device type /* FIXME too much hardcoding? */ //inputs itv->v4l2.input.active = 4; itv->v4l2.input.count = 10; itv->v4l2.input.table.input = tmk_inputs; itv->v4l2.audio_output = 1; //audio inputs itv->v4l2.audio.active = 0; itv->v4l2.audio.count = 2; itv->v4l2.audio.table.audio = tmk_audio_inputs; //outputs .. none yet (no real 350 support anyways) itv->v4l2.output.active = 0; itv->v4l2.output.count = 0; itv->v4l2.output.table.output = NULL; //standards (NTSC, PAL, SECAM) if (ivtv_pal) itv->v4l2.standard.active = 1; else itv->v4l2.standard.active = 0; itv->v4l2.standard.count = 3; itv->v4l2.standard.table.std = tmk_standards; if (itv->v4l2.standard.active == 0) { itv->v4l2.codec.framespergop = 15; // NTSC itv->v4l2.codec.framerate = 0; // NTSC 30fps } else { itv->v4l2.codec.framespergop = 12; // PAL itv->v4l2.codec.framerate = 1; // PAL 25fps /* set pal height in stream defaults */ tmk_mpg_stream.format.fmt.pix.height = 576; tmk_yuv_stream.format.fmt.pix.height = 576; tmk_vbi_stream.format.fmt.pix.height = 576; dec_mpg_stream.format.fmt.pix.height = 576; dec_yuv_stream.format.fmt.pix.height = 576; } //tuner itv->v4l2.tuner.active = 0; if (itv->card_type == IVTV_350_V1) { itv->v4l2.tuner.count = 2; } else { itv->v4l2.tuner.count = 1; } itv->v4l2.tuner.table.tuner = (struct v4l2_tuner *) kmalloc((itv->v4l2.tuner.count * sizeof(struct v4l2_tuner)), GFP_KERNEL); if (itv->v4l2.tuner.table.tuner == NULL) { IVTV_DEBUG(IVTV_DEBUG_ERR, "Couldn't allocate v4l2 tuner\n"); return -ENOMEM; } memcpy(itv->v4l2.tuner.table.tuner, &tmk_tuners[0], (itv->v4l2.tuner.count * sizeof(struct v4l2_tuner))); /* Setup audio */ /* V4L2_CID_IVTV_FREQ */ itv->v4l2.audio_meta[0].ctrl = &ivtv_ctrl_menu_freq; itv->v4l2.audio_meta[0].menu = ivtv_ctrl_query_freq; itv->v4l2.audio_meta[0].mask = ivtv_audio_mask_freq; itv->v4l2.audio_meta[0].setting = ivtv_ctrl_menu_freq.default_value; itv->v4l2.audio_meta[0].table = &ivtv_audio_tbl_freq[0]; /* V4L2_CID_IVTV_ENC*/ itv->v4l2.audio_meta[1].ctrl = &ivtv_ctrl_menu_enc; itv->v4l2.audio_meta[1].menu = ivtv_ctrl_query_enc; itv->v4l2.audio_meta[1].mask = ivtv_audio_mask_enc; itv->v4l2.audio_meta[1].setting = ivtv_ctrl_menu_enc.default_value; itv->v4l2.audio_meta[1].table = &ivtv_audio_tbl_enc[0]; /* V4L2_CID_IVTV_BITRATE*/ itv->v4l2.audio_meta[2].ctrl = &ivtv_ctrl_menu_bitrate; itv->v4l2.audio_meta[2].menu = ivtv_ctrl_query_bitrate; itv->v4l2.audio_meta[2].mask = ivtv_audio_mask_bitrate; itv->v4l2.audio_meta[2].setting = ivtv_ctrl_menu_bitrate.default_value; itv->v4l2.audio_meta[2].table = &ivtv_audio_tbl_bitrate[0]; /* V4L2_CID_IVTV_MONO*/ itv->v4l2.audio_meta[3].ctrl = &ivtv_ctrl_menu_mono; itv->v4l2.audio_meta[3].menu = ivtv_ctrl_query_mono; itv->v4l2.audio_meta[3].mask = ivtv_audio_mask_mono; itv->v4l2.audio_meta[3].setting = ivtv_ctrl_menu_mono.default_value; itv->v4l2.audio_meta[3].table = &ivtv_audio_tbl_mono[0]; /* V4L2_CID_IVTV_JOINT*/ itv->v4l2.audio_meta[4].ctrl = &ivtv_ctrl_menu_joint; itv->v4l2.audio_meta[4].menu = ivtv_ctrl_query_joint; itv->v4l2.audio_meta[4].mask = ivtv_audio_mask_joint; itv->v4l2.audio_meta[4].setting = ivtv_ctrl_menu_joint.default_value; itv->v4l2.audio_meta[4].table = &ivtv_audio_tbl_joint[0]; /* V4L2_CID_IVTV_EMPHASIS*/ itv->v4l2.audio_meta[5].ctrl = &ivtv_ctrl_menu_emphasis; itv->v4l2.audio_meta[5].menu = ivtv_ctrl_query_emphasis; itv->v4l2.audio_meta[5].mask = ivtv_audio_mask_emphasis; itv->v4l2.audio_meta[5].setting = ivtv_ctrl_menu_emphasis.default_value; itv->v4l2.audio_meta[5].table = &ivtv_audio_tbl_emphasis[0]; /* V4L2_CID_IVTV_CRC*/ itv->v4l2.audio_meta[6].ctrl = &ivtv_ctrl_menu_crc; itv->v4l2.audio_meta[6].menu = ivtv_ctrl_query_crc; itv->v4l2.audio_meta[6].mask = ivtv_audio_mask_crc; itv->v4l2.audio_meta[6].setting = ivtv_ctrl_menu_crc.default_value; itv->v4l2.audio_meta[6].table = &ivtv_audio_tbl_crc[0]; /* V4L2_CID_IVTV_COPYRIGHT*/ itv->v4l2.audio_meta[7].ctrl = &ivtv_ctrl_menu_copyright; itv->v4l2.audio_meta[7].menu = ivtv_ctrl_query_copyright; itv->v4l2.audio_meta[7].mask = ivtv_audio_mask_copyright; itv->v4l2.audio_meta[7].setting = ivtv_ctrl_menu_copyright.default_value; itv->v4l2.audio_meta[7].table = &ivtv_audio_tbl_copyright[0]; /* V4L2_CID_IVTV_GEN*/ itv->v4l2.audio_meta[8].ctrl = &ivtv_ctrl_menu_generation; itv->v4l2.audio_meta[8].menu = ivtv_ctrl_query_generation; itv->v4l2.audio_meta[8].mask = ivtv_audio_mask_generation; itv->v4l2.audio_meta[8].setting = ivtv_ctrl_menu_generation.default_value; itv->v4l2.audio_meta[8].table = &ivtv_audio_tbl_generation[0]; itv->v4l2.codec.audio_bitmap = 0; for (x = 0; x < IVTV_V4L2_AUDIO_MENUCOUNT; x++) { temp = itv->v4l2.audio_meta[x].setting; itv->v4l2.codec.audio_bitmap |= itv->v4l2.audio_meta[x].table[temp]; } retval = ivtv_set_audio(itv,tmk_audio_mapping); if (retval) { kfree(itv->v4l2.tuner.table.tuner); return retval; } //FIXME Setup components here? tuner channel etc return 0; } int ivtv_start_v4l2_stream (struct ivtv_open_id *id) { struct ivtv *itv = id->itv; u32 data[IVTV_MBOX_MAX_DATA], result; int x,vsize,vsync,hsize; int type,subtype; unsigned int dig; /* sem_lock must be held */ IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0); IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv start v4l2 stream\n"); /* NTSC/PAL switching */ vsize = itv->v4l2.streams[0].format.fmt.pix.height; vsync = (int) itv->v4l2.streams[0].format.fmt.pix.height/2; hsize = itv->v4l2.streams[0].format.fmt.pix.width; type = id->type; switch (type) { case 2: /* VBI, may be the wrong value */ subtype = 4; case 4: /* Radio, probably not applicable */ subtype = 2; break; default: subtype = 3; break; } /* clear queues */ ivtv_move_queue(itv, &itv->v4l2.streams[id->type].full_q, &itv->v4l2.streams[id->type].free_q); ivtv_move_queue(itv, &itv->v4l2.streams[id->type].dma_q, &itv->v4l2.streams[id->type].free_q); IVTV_DEBUG(IVTV_DEBUG_INFO, "fullq size %d\n", itv->v4l2.streams[id->type].full_q.elements); IVTV_DEBUG(IVTV_DEBUG_INFO, "freeq size %d\n", itv->v4l2.streams[id->type].free_q.elements); IVTV_DEBUG(IVTV_DEBUG_INFO, "dmaq size %d\n", itv->v4l2.streams[id->type].dma_q.elements); /*assign dma block len*/ /* FIXME this needs a flag */ data[0] = 1; /* num bytes in block*/ data[1] = 1; /* use info from sg instead */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_DMA_BLOCKLEN, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 1. Code %d\n",x); /*assign program index info */ /* FIXME need more info on this call */ data[0] = 0; /*Mask 0:Disable */ data[1] = 0; /*Num_req 0:??/ */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_PGM_INDEX_INFO, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 2. Code %d\n",x); /*assign stream type */ data[0] = itv->v4l2.codec.stream_type; x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_STREAM_TYPE, &result,1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 3. Code %d\n",x); /*assign output port */ data[0] = 0; /*0:Memory */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_OUTPUT_PORT, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 4. Code %d\n",x); /*assign framerate */ data[0] = itv->v4l2.codec.framerate; x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_FRAMERATE, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 5. Code %d\n",x); /*assign frame size */ data[0] = vsize; /* height*/ data[1] = hsize; /* width */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_FRAME_SIZE, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 6. Code %d\n",x); /*assign aspect ratio */ data[0] = itv->v4l2.codec.aspect; /*mpeg spec sez 2 */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_ASPECT_RATIO, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 7. Code %d\n",x); /*assign bitrates */ /*FIXME i think these settings are valid for compressed only */ data[0] = itv->v4l2.codec.bitrate_mode; /*mode */ data[1] = itv->v4l2.codec.bitrate; /* bps */ data[2] = itv->v4l2.codec.bitrate_peak / 400; /* peak/400 */ data[3] = 0; /*??? */ data[4] = 0x70; /*??? */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_BITRATES, &result, 5, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 8. Code %d\n",x); /*assign gop properties */ data[0] = itv->v4l2.codec.framespergop; data[1] = itv->v4l2.codec.bframes; x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_GOP_PROPERTIES, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 9. Code %d\n",x); /*assign 3 2 pulldown */ data[0] = itv->v4l2.codec.pulldown; x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_3_2_PULLDOWN, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 10. Code %d\n",x); /*assign gop closure */ data[0] = itv->v4l2.codec.gop_closure; x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_GOP_CLOSURE, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 11. Code %d\n",x); /*assign audio properties */ data[0] = itv->v4l2.codec.audio_bitmap; x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_AUDIO_PROPERTIES, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 12. Code %d\n",x); /*assign dnr filter mode */ data[0] = itv->v4l2.codec.dnr_mode; data[1] = itv->v4l2.codec.dnr_type; x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_DNR_FILTER_MODE, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 13. Code %d\n",x); /*assign dnr filter props*/ data[0] = itv->v4l2.codec.dnr_spatial; data[1] = itv->v4l2.codec.dnr_temporal; x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_DNR_FILTER_PROPS, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 14. Code %d\n",x); /*assign coring levels */ data[0] = 0; /*luma_h */ data[1] = 255; /*luma_l */ data[2] = 0; /*chroma_h */ data[3] = 255; /*chroma_l */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_CORING_LEVELS, &result, 4, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 15. Code %d\n",x); /*assign spatial filter type */ data[0] = 1; /*luma_t: 1 = horiz_only */ data[1] = 1; /*chroma_t: 1 = horiz_only */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 16. Code %d\n",x); /*assign frame drop rate */ data[0] = 0; x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_FRAME_DROP_RATE, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 17. Code %d\n",x); /*assign placeholder */ data[0] = 0; /* type: 0 = Extension/UserData */ data[1] = 0; /*period */ data[2] = 0; /*size_t*/ data[3] = 0; /*arg0 */ data[4] = 0; /*arg1 */ data[5] = 0; /*arg2 */ data[6] = 0; /*arg3 */ data[7] = 0; /*arg4 */ data[8] = 0; /*arg5 */ data[9] = 0; /*arg6 */ data[10] = 0; /*arg7 */ data[11] = 0; /*arg8 */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_PLACEHOLDER, &result, 12, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 18. Code %d\n\n",x); /* assign num vsync lines */ data[0] = vsync; /*??? */ data[1] = vsync; /* ??? */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_ASSIGN_NUM_VSYNC_LINES, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 20. Code %d\n",x); if (atomic_read(&itv->capturing) == 0) { itv->trans_id = 0; itv->first_read = 1; /* Clear pending interrupts */ IVTV_DEBUG(IVTV_DEBUG_INFO, "Clearing Interrupts\n"); writel((readl(itv->reg_mem + IVTV_REG_IRQSTATUS)&0xC8000000), (IVTV_REG_IRQSTATUS+itv->reg_mem)); /* event notification (on) */ data[0] = 0; /*type: 0 = refresh */ data[1] = 1; /*on/off: 1 = on */ data[2] = 0x10000000; /*intr_bit: 0x10000000 = digitizer */ data[3] = -1; /*mbox_id: -1: none */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_EVENT_NOTIFICATION, &result, 4, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "startcap error 2. Code %d\n",x); /* Disable digitizer (saa7115) */ IVTV_DEBUG(IVTV_DEBUG_INFO, "Disabling digitizer\n"); dig=0; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, DECODER_ENABLE_OUTPUT,&dig); /*initialize input (no args) */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_INITIALIZE_INPUT, &result, 0, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 19. Code %d\n\n",x); /* enable digitizer (saa7115) */ IVTV_DEBUG(IVTV_DEBUG_INFO, "Enabling digitizer\n"); dig=1; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, DECODER_ENABLE_OUTPUT,&dig); IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 100ms\n"); ivtv_sleep_timeout(HZ/10); } clear_bit(IVTV_F_I_EOS, &itv->i_flags); /* begin_capture */ data[0] = type; /*type: 0 = mpeg */ data[1] = subtype; /*subtype: 3 = video+audio */ x = ivtv_api(itv->enc_mbox, &itv->enc_msem, IVTV_API_BEGIN_CAPTURE, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "startcap error 1. Code %d\n",x); if (atomic_read(&itv->capturing) == 0) { /*Clear the following Interrupt mask bits: 0xd8000000 */ ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); IVTV_DEBUG(IVTV_DEBUG_IRQ, "IRQ Mask is now: 0x%08x\n",itv->irqmask); } /*you're live! sit back and await interrupts :)*/ atomic_inc(&itv->capturing); return 0; } int ivtv_api_dec_playback_speed(struct ivtv* itv, int fastspeed, int factor, int forward, int mpeg_frame_type_mask, int bframes_per_gop, int mute_audio, int display_fields) { u32 data[IVTV_MBOX_MAX_DATA], result; data[0] = (fastspeed << 31) | (factor & 0xff); data[1] = forward; data[2] = mpeg_frame_type_mask; data[3] = bframes_per_gop; data[4] = mute_audio; data[5] = display_fields; ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_PLAYBACK_SPEED, &result, 6, &data[0]); return result; } int ivtv_start_v4l2_decode (struct ivtv_open_id *id) { struct ivtv *itv = id->itv; u32 data[IVTV_MBOX_MAX_DATA], result; int x; int type; int standard=0; /* sem_lock must be held */ IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0); type = id->type; if (itv->v4l2.standard.active != 0) { /* if not NTSC */ standard = 1; /* PAL */ } /* this isn't needed until we use buffers for decoding */ /* clear queues */ ivtv_move_queue(itv, &itv->v4l2.streams[id->type].full_q, &itv->v4l2.streams[id->type].free_q); ivtv_move_queue(itv, &itv->v4l2.streams[id->type].dma_q, &itv->v4l2.streams[id->type].free_q); IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder fullq size %d\n", itv->v4l2.streams[id->type].full_q.elements); IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder freeq size %d\n", itv->v4l2.streams[id->type].free_q.elements); IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder dmaq size %d\n", itv->v4l2.streams[id->type].dma_q.elements); if (atomic_read(&itv->decoding) == 0) { /* Clear pending interrupts */ IVTV_DEBUG(IVTV_DEBUG_INFO, "Clearing Interrupts\n"); writel((readl(itv->reg_mem + IVTV_REG_IRQSTATUS)&0xC8000000), (IVTV_REG_IRQSTATUS+itv->reg_mem)); } /* set display standard */ data[0] = standard; /* 0 = NTSC, 1 = PAL */ x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_DISP_STANDARD, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T SET DISPLAY STD %d\n",x); /* set audio mode */ data[0] = 0; /* Dual mono-mode action: ??? */ data[1] = 0; /* stereo mode action: 0=stereo, 1=left, 2=right, 3=mono */ x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_SELECT_AUDIO, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T SET AUDIO MODE %d\n",x); /* set decoder source settings */ data[0] = id->type; /* Data type: 0 = mpeg from host, 1 = yuv from encoder, 2 = yuv_from_host */ data[1] = 720; /* YUV source width*/ if (itv->v4l2.standard.active == 1) data[2] = 576; /* YUV source height*/ else data[2] = 480; /* YUV source height*/ data[3] = itv->v4l2.codec.audio_bitmap; /* Audio settings to use, bitmap. see docs.*/ x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_DECODE_SOURCE, &result, 4, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE DECODER SOURCE %d\n",x); #if 0 /* select event notification */ data[0] = 0; /* Event: 0 = audio change between stereo and mono */ data[1] = 1; /* Enable/Disable: 0 = disabled, 1 = enabled */ data[2] = 0x00010000; /* Bit: interrupt bit to fire */ data[3] = -1; /* Mailbox to use: -1 = no mailbox needed */ x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_EVENT_NOTIFICATION, &result, 4, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE EVENT NOTIFICATION %d\n",x); #endif /* set number of internal decoder buffers */ data[0] = itv->dec_options.decbuffers; /* 0 = 6 buffers, 1 = 9 buffers */ x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_DISPLAY_BUFFERS, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE # OF DISPLAY BUFFERS %d\n",x); /* prebufferring*/ data[0] = itv->dec_options.prebuffer; /* 0 = no prebuffering, 1 = enabled, see docs */ x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_BUFFER, &result, 1,&data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE BUFFER %d\n",x); #if 0 /* set stream input port */ data[0] = 0; /* 0 = memory, 1 = streaming */ x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_STREAM_INPUT, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T INITIALIZE STREAM INPUT %d\n",x); /* A/V sync delay */ data[0] = 0; /* Delay in 90khz ticks. 0 = synced, negative = audio lags, positive = video lags */ x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_SET_AV_DELAY, &result, 1, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN't INITIALIZE Audio/Vid sync delay %d\n",x); #endif /* start playback */ data[0] = itv->dec_options.gop_offset; /* frame to start from (in GOP) */ data[1] = itv->dec_options.mute_frames; /* # of audio frames to mute */ x = ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_START_PLAYBACK, &result, 2, &data[0]); if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T START PLAYBACK %d\n",x); if (atomic_read(&itv->decoding) == 0) { /*Clear the following Interrupt mask bits: 0xd8000000 */ ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE); IVTV_DEBUG(IVTV_DEBUG_IRQ, "IRQ Mask is now: 0x%08x\n",itv->irqmask); } /*you're live! sit back and await interrupts :)*/ atomic_inc(&itv->decoding); return 0; } void ivtv_v4l2_cleanup(struct ivtv *itv) { int x; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 unregister\n"); if (atomic_read(&itv->capturing) >= 0) ivtv_stop_all_captures(itv); if (itv->v4l2.tuner.table.tuner) kfree(itv->v4l2.tuner.table.tuner); for (x=0; x < itv->v4l2.streamcount; x++) { /* Catch a possible kernel panic */ if (itv->v4l2.streams[x].v4l2dev.minor != -1) { video_unregister_device(&itv->v4l2.streams[x].v4l2dev); } else { IVTV_DEBUG(IVTV_DEBUG_ERR, "invalid v4l2 registration on unload\n"); } } if (itv->v4l2.streams) kfree(itv->v4l2.streams); } int ivtv_v4l2_open(struct inode *inode, struct file *filp) { int x,y=0,minor; struct ivtv_open_id *item; struct ivtv *itv=NULL; minor = MINOR(inode->i_rdev); IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 open on minor %d\n", minor); /* Find which card this open was on */ spin_lock_irq(&ivtv_lock); for (x=0;xitv = itv; item->type = y; INIT_LIST_HEAD(&item->list); down(&itv->sem_lock); item->open_id = item->itv->open_id++; list_add_tail (&item->list, &item->itv->client_list); up(&itv->sem_lock); filp->private_data = item; return 0; } /* Couldnt find a device registered on that minor, shouldn't happen! */ IVTV_DEBUG(IVTV_DEBUG_ERR,"Device on minor %d not found!\n",minor); return -ENXIO; } int ivtv_v4l2_read(struct file *filp, char *buf, size_t count, loff_t *pos) { struct ivtv_open_id *id = filp->private_data; struct ivtv *itv = id->itv; struct ivtv_v4l2_stream *stream; int ret=0; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 read\n"); if (down_interruptible(&itv->sem_lock)) return -ERESTARTSYS; stream = &itv->v4l2.streams[id->type]; if (!test_and_set_bit(IVTV_F_S_CAP, &stream->s_flags) && stream->id == -1) { stream->id = id->open_id; ret = ivtv_start_v4l2_stream(id); if (ret) { IVTV_DEBUG(IVTV_DEBUG_INFO, "Error in v4l2 stream init\n"); /* bit of a hack... but try to reload firmware * if capture init fails */ ret = ivtv_firmware_copy(itv); if (!ret) ret = ivtv_start_v4l2_stream(id); } stream->seq = 0; stream->ubytes = 0; } else { if (id->open_id != stream->id) ret = -EBUSY; } up(&itv->sem_lock); if (ret) return ret; ret = ivtv_read(id, buf, count, !(filp->f_flags & O_NONBLOCK)); if (ret > 0) *pos += ret; return ret; } ssize_t ivtv_v4l2_write(struct file *filp, const char *buf, size_t count, loff_t *pos) { struct ivtv_open_id *id = filp->private_data; struct ivtv *itv = id->itv; struct ivtv_v4l2_stream *stream; int ret=0; if ( (id->type != IVTV_DEC_STREAM_TYPE_MPG) && (id->type != IVTV_DEC_STREAM_TYPE_YUV)) { IVTV_DEBUG(IVTV_DEBUG_ERR, "Write on read-only interface\n"); return -EINVAL; } if (down_interruptible(&itv->sem_lock)) return -ERESTARTSYS; // Initialize Decoder /* FIXME we'll need to make this its own stream type */ stream = &itv->v4l2.streams[id->type]; if (!test_and_set_bit(IVTV_F_S_CAP, &stream->s_flags)) { stream->id = id->open_id; ret = ivtv_start_v4l2_decode(id); } else { if (id->open_id != stream->id) ret = -EBUSY; } up(&itv->sem_lock); if (ret) return ret; /* do all the work */ return ivtv_write(id, buf, count); } int ivtv_v4l2_close(struct inode *inode, struct file *filp) { struct ivtv_open_id *id = filp->private_data; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 close\n"); if (NULL == id) { IVTV_DEBUG(IVTV_DEBUG_ERR,"invalid id on v4l2 close\n"); return -ENODEV; } if (down_interruptible(&id->itv->sem_lock)) return -ERESTARTSYS; if (id->open_id == id->itv->v4l2.streams[id->type].id) { ivtv_close(id); clear_bit(IVTV_F_S_CAP, &id->itv->v4l2.streams[id->type].s_flags); id->itv->v4l2.streams[id->type].id = -1; } list_del(&id->list); up(&id->itv->sem_lock); kfree(id); return 0; } /* direct from the latest v4l2 patch */ static unsigned int video_fix_command(unsigned int cmd) { switch (cmd) { case VIDIOC_OVERLAY_OLD: cmd = VIDIOC_OVERLAY; break; case VIDIOC_S_PARM_OLD: cmd = VIDIOC_S_PARM; break; case VIDIOC_S_CTRL_OLD: cmd = VIDIOC_S_CTRL; break; case VIDIOC_G_AUDIO_OLD: cmd = VIDIOC_G_AUDIO; break; case VIDIOC_G_AUDOUT_OLD: cmd = VIDIOC_G_AUDOUT; break; default: break; } return cmd; } int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; struct ivtv *itv = id->itv; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl 0x%08x\n", cmd); cmd = video_fix_command(cmd); switch (cmd) { #ifdef SAA7115_REGTEST /* ioctls to allow direct access to the saa7115 registers for testing */ case SAA7115_GET_REG: { struct saa7115_reg_t *saa7115_reg = (struct saa7115_reg_t *)arg; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,SAA7115_GET_REG,saa7115_reg); break; } case SAA7115_SET_REG: { struct saa7115_reg_t *saa7115_reg = (struct saa7115_reg_t *)arg; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,SAA7115_SET_REG,saa7115_reg); break; } #endif case IVTV_IOC_ZCOUNT: { /* Zeroes out usage count so it can be unloaded in case of * drastic error */ IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv ioctl: ZCOUNT\n"); while (MOD_IN_USE) MOD_DEC_USE_COUNT; MOD_INC_USE_COUNT; break; } case IVTV_IOC_GET_FB: { if (itv->fb_id < 0) return -EINVAL; if (copy_to_user((int*)arg, &itv->fb_id, sizeof(itv->fb_id))) return -EFAULT; break; } case IVTV_IOC_FWAPI: { struct ivtv_ioctl_fwapi fwapi; int x; IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv ioctl: FWAPI\n"); if (copy_from_user(&fwapi, (struct ivtv_ioctl_fwapi *) arg, sizeof(struct ivtv_ioctl_fwapi))) return -EFAULT; /* Encoder x = ivtv_api(itv->enc_mbox, &itv->enc_msem, fwapi.cmd, &fwapi.result, fwapi.args, &fwapi.data[0]); */ /* Decoder */ x = ivtv_api(itv->dec_mbox, &itv->dec_msem, fwapi.cmd, &fwapi.result, fwapi.args, &fwapi.data[0]); if (copy_to_user((struct ivtv_ioctl_fwapi *) arg, &fwapi, sizeof(struct ivtv_ioctl_fwapi))) return -EFAULT; return x; } case IVTV_IOC_FRAMESYNC: { interruptible_sleep_on(&itv->vsync_w); if (signal_pending(current)) return -ERESTARTSYS; if (copy_to_user((void*)arg, &itv->dec_timestamp, sizeof(itv->dec_timestamp))) { return -EFAULT; } break; } case IVTV_IOC_PLAY: { u32 data[IVTV_MBOX_MAX_DATA], result; data[0] = 0; /* 0-based frame # to start from (in GOP) */ data[1] = 0; /* # of audio frames to mute */ if (ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_START_PLAYBACK, &result, 2, &data[0])) IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error starting playback\n"); break; } case IVTV_IOC_S_START_DECODE: { struct ivtv_cfg_start_decode sd; if (copy_from_user(&sd, (struct ivtv_cfg_start_decode *) arg, sizeof(sd))) return -EFAULT; if ((sd.gop_offset < 0) || (sd.gop_offset > 15)) return -EINVAL; if (sd.muted_audio_frames < 0) return -EINVAL; itv->dec_options.gop_offset = sd.gop_offset; itv->dec_options.mute_frames = sd.muted_audio_frames; break; } case IVTV_IOC_S_STOP_DECODE: { struct ivtv_cfg_stop_decode sd; if (copy_from_user(&sd, (struct ivtv_cfg_stop_decode *)arg, sizeof(sd))) return -EFAULT; if ((sd.hide_last < 0) || (sd.hide_last > 1)) return -EINVAL; itv->dec_options.hide_last_frame = sd.hide_last; itv->dec_options.pts_low = (u32)(sd.pts_stop & 0xFFFFFFFF); itv->dec_options.pts_hi = (u32)(sd.pts_stop >> 32); break; } case IVTV_IOC_S_SLOW_FAST: { struct ivtv_slow_fast sf; u32 data[IVTV_MBOX_MAX_DATA], result; if (copy_from_user(&sf, (struct ivtv_slow_fast *)arg, sizeof(sf))) return -EFAULT; if ((sf.scale < 0) || (sf.scale > 50)) return -EINVAL; if ((sf.speed < 0) || (sf.speed > 1)) return -EINVAL; data[0] = sf.scale; if (itv->dec_options.smooth) /* smooth ff */ data[0] |= 0x40000000; if (sf.speed) /* fast forward */ data[0] |= 0x80000000; data[1] = 1; /* Forward. Reverse not supported */ switch (itv->dec_options.fr_mask) { case 0: data[2] = 1; /* I */ break; case 1: data[2] = 3; /* I, P */ break; case 2: default: data[2] = 7; /*I, P, B */ break; } data[3] = 0; /* reverse only, not supported */ data[4] = itv->dec_options.aud_mute; /* mute while fast/slow */ data[5] = itv->dec_options.fr_field; /* frame or field at a time */ data[6] = itv->dec_options.sf_mute; /* # of frames to mute on normal speed resume */ if (ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_PLAYBACK_SPEED, &result, 7, &data[0])) { IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error in slow/fast mode\n"); } break; } case IVTV_IOC_PAUSE: { u32 data[IVTV_MBOX_MAX_DATA], result; data[0] = 0; if (ivtv_api(itv->dec_mbox, &itv->dec_msem, IVTV_API_DEC_PAUSE_PLAYBACK, &result, 1, &data[0])) { IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: error pausing\n"); } break; } case IVTV_IOC_GET_TIMING: { struct ivtv_ioctl_framesync timing; int ret; if (atomic_read(&itv->decoding) == 0) { memset(&timing, 0, sizeof(timing)); } else { /* if the value pulled 'efficiently' was OK */ if (&itv->dec_timestamp.scr == 0) { /* firmware glitch gave us a bad value. get a good one */ ret = ivtv_get_timing_info(itv, &timing); if (ret) return -EINVAL; } else { memcpy(&timing, &itv->dec_timestamp, sizeof(timing)); } } if (copy_to_user((void*)arg, &timing, sizeof(timing))) { return -EFAULT; } break; } case VIDIOC_QUERYMENU: { struct v4l2_querymenu *qmenu = (struct v4l2_querymenu *)arg; if (qmenu->id >= V4L2_CID_PRIVATE_BASE) { int off = qmenu->id - V4L2_CID_PRIVATE_BASE; if (off < IVTV_V4L2_AUDIO_MENUCOUNT) { u32 i = qmenu->index; if ((i >= itv->v4l2.audio_meta[off].ctrl->minimum) && (i <= itv->v4l2.audio_meta[off].ctrl->maximum)) { memcpy(qmenu, &itv->v4l2.audio_meta[off].menu[i], sizeof(struct v4l2_querymenu)); } else { IVTV_DEBUG(IVTV_DEBUG_ERR, "qmenu: invalid index\n"); return -EINVAL; } } else { IVTV_DEBUG(IVTV_DEBUG_ERR, "qmenu: id out of range\n"); return -EINVAL; } } break; } case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *qctrl = (struct v4l2_queryctrl *)arg; if (qctrl->id >= V4L2_CID_PRIVATE_BASE) { int off = qctrl->id - V4L2_CID_PRIVATE_BASE; if (off < IVTV_V4L2_AUDIO_MENUCOUNT) { memcpy(qctrl,itv->v4l2.audio_meta[off].ctrl, sizeof(struct v4l2_queryctrl)); } else { switch (qctrl->id) { case V4L2_CID_IVTV_DEC_SMOOTH_FF: qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; strncpy(qctrl->name, "Smooth Slow/FF", 32); qctrl->minimum = 0; qctrl->maximum = 1; qctrl->default_value = 1; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 0; break; case V4L2_CID_IVTV_DEC_FR_MASK: qctrl->type = V4L2_CTRL_TYPE_INTEGER; strncpy(qctrl->name, "Frame Mask", 32); qctrl->minimum = 0; qctrl->maximum = 2; qctrl->default_value = 2; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 0; break; case V4L2_CID_IVTV_DEC_SP_MUTE: qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; strncpy(qctrl->name, "Mute during slow/fast", 32); qctrl->minimum = 0; qctrl->maximum = 1; qctrl->default_value = 1; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 0; break; case V4L2_CID_IVTV_DEC_FR_FIELD: qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; strncpy(qctrl->name, "Toggle frame/field", 32); qctrl->minimum = 0; qctrl->maximum = 1; qctrl->default_value = 1; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 0; break; case V4L2_CID_IVTV_DEC_AUD_SKIP: qctrl->type = V4L2_CTRL_TYPE_INTEGER; strncpy(qctrl->name, "Mute audio frames",32); qctrl->minimum = 0; qctrl->maximum = 15; qctrl->default_value = 0; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 0; break; case V4L2_CID_IVTV_DEC_NUM_BUFFERS: qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; strncpy(qctrl->name, "Number of decoder buffers", 32); qctrl->minimum = 0; qctrl->maximum = 1; qctrl->default_value = 1; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 1; break; case V4L2_CID_IVTV_DEC_PREBUFFER: qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; strncpy(qctrl->name, "Decoder prebuffer", 32); qctrl->minimum = 0; qctrl->maximum = 1; qctrl->default_value = 1; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 1; break; default: IVTV_DEBUG(IVTV_DEBUG_ERR, "qctrl: invalid control\n"); return -EINVAL; break; } } break; } switch (qctrl->id) { case V4L2_CID_BRIGHTNESS: qctrl->type = V4L2_CTRL_TYPE_INTEGER; strncpy(qctrl->name, "Brightness", 32); qctrl->minimum = 0; qctrl->maximum = 255; qctrl->step = 0; qctrl->default_value = 128; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 0; break; case V4L2_CID_HUE: qctrl->type = V4L2_CTRL_TYPE_INTEGER; strncpy(qctrl->name, "Hue", 32); qctrl->minimum = -128; qctrl->maximum = 127; qctrl->step = 0; qctrl->default_value = 0; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 0; break; case V4L2_CID_SATURATION: qctrl->type = V4L2_CTRL_TYPE_INTEGER; strncpy(qctrl->name, "Saturation", 32); qctrl->minimum = 0; qctrl->maximum = 127; qctrl->step = 0; qctrl->default_value = 64; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 0; break; case V4L2_CID_CONTRAST: qctrl->type = V4L2_CTRL_TYPE_INTEGER; strncpy(qctrl->name, "Contrast", 32); qctrl->minimum = 0; qctrl->maximum = 127; qctrl->step = 0; qctrl->default_value = 64; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 0; break; case V4L2_CID_AUDIO_VOLUME: qctrl->type = V4L2_CTRL_TYPE_INTEGER; strncpy(qctrl->name, "Volume", 32); qctrl->minimum = 0; qctrl->maximum = 65535; qctrl->step = 0; qctrl->default_value = 65535; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 0; break; case V4L2_CID_AUDIO_MUTE: qctrl->type = V4L2_CTRL_TYPE_INTEGER; strncpy(qctrl->name, "Mute", 32); qctrl->minimum = 0; qctrl->maximum = 1; qctrl->step = 0; qctrl->default_value = 1; qctrl->flags = 0; qctrl->reserved[0] = 0; qctrl->reserved[1] = 0; break; default: IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: invalid control\n"); return -EINVAL; } break; } case VIDIOC_S_CTRL: { struct v4l2_control *vctrl = (struct v4l2_control *)arg; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set control\n"); if (vctrl->id >= V4L2_CID_PRIVATE_BASE) { int off = vctrl->id - V4L2_CID_PRIVATE_BASE; s32 v = vctrl->value; if (off < IVTV_V4L2_AUDIO_MENUCOUNT) { if ((v<=itv->v4l2.audio_meta[off].ctrl->maximum) && (v>=itv->v4l2.audio_meta[off].ctrl->minimum)) { itv->v4l2.audio_meta[off].setting = v; /* presumably value has changed. * we should update the bitmap */ itv->v4l2.codec.audio_bitmap &= ~itv->v4l2.audio_meta[off].mask; itv->v4l2.codec.audio_bitmap |= itv->v4l2.audio_meta[off].table[v]; /* Also upade the digitizer setting */ if (0 == off) { /* audio input bitrate */ int vrate = (int)v; /* FIXME not obvious how this works * (see ivtv_ctrl_query_freq[]) */ ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_AUDIO,&vrate); } } else { IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: value out of range\n"); return -ERANGE; } } else { switch (vctrl->id) { case V4L2_CID_IVTV_DEC_SMOOTH_FF: if ((v < 0) || (v > 1)) return -ERANGE; itv->dec_options.smooth = vctrl->value; break; case V4L2_CID_IVTV_DEC_FR_MASK: if ((v < 0) || (v > 2)) return -ERANGE; itv->dec_options.fr_mask = vctrl->value; break; case V4L2_CID_IVTV_DEC_SP_MUTE: if ((v < 0) || (v > 1)) return -ERANGE; itv->dec_options.aud_mute = vctrl->value; break; case V4L2_CID_IVTV_DEC_FR_FIELD: if ((v < 0) || (v > 1)) return -ERANGE; itv->dec_options.fr_field = vctrl->value; break; case V4L2_CID_IVTV_DEC_AUD_SKIP: if ((v < 0) || (v > 15)) return -ERANGE; itv->dec_options.mute_frames = vctrl->value; break; case V4L2_CID_IVTV_DEC_NUM_BUFFERS: if ((v < 0) || (v > 1)) return -ERANGE; itv->dec_options.decbuffers = vctrl->value; break; case V4L2_CID_IVTV_DEC_PREBUFFER: if ((v < 0) || (v > 1)) return -ERANGE; itv->dec_options.prebuffer = vctrl->value; break; default: IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid control\n"); return -EINVAL; } } break; } switch (vctrl->id) { case V4L2_CID_BRIGHTNESS: { struct saa7114 pic; if (vctrl->value < 0 || vctrl->value > 255) { IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid brightness value: %d\n", vctrl->value); return -EINVAL; } ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); pic.bright = vctrl->value; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic); break; } case V4L2_CID_HUE: { struct saa7114 pic; if (vctrl->value < -128 || vctrl->value > 127) { IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid hue value: %d\n", vctrl->value); return -EINVAL; } ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); pic.hue = vctrl->value; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic); break; } case V4L2_CID_SATURATION: { struct saa7114 pic; if (vctrl->value < 0 || vctrl->value > 127) { IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid saturation value: %d\n", vctrl->value); return -EINVAL; } ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); pic.sat = vctrl->value; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic); break; } case V4L2_CID_CONTRAST: { struct saa7114 pic; if (vctrl->value < 0 || vctrl->value > 127) { IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid contrast value: %d\n", vctrl->value); return -EINVAL; } ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); pic.contrast = vctrl->value; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_SET_PICTURE,&pic); break; } case V4L2_CID_AUDIO_VOLUME: { struct video_audio va; if (vctrl->value > 65535 || vctrl->value < 0) { IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid value for volume: %d", vctrl->value); return -EINVAL; } ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va); va.volume = vctrl->value; ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCSAUDIO,&va); break; } case V4L2_CID_AUDIO_MUTE: { struct video_audio va; ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va); if (vctrl->value) va.flags |= VIDEO_AUDIO_MUTE; else va.flags = (va.flags & ~(VIDEO_AUDIO_MUTE)); ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCSAUDIO,&va); break; } default: IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid control\n"); return -EINVAL; } break; } case VIDIOC_G_CTRL: { struct v4l2_control *vctrl = (struct v4l2_control *)arg; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get control\n"); if (vctrl->id >= V4L2_CID_PRIVATE_BASE) { int off = vctrl->id - V4L2_CID_PRIVATE_BASE; if (off < IVTV_V4L2_AUDIO_MENUCOUNT) { vctrl->value =itv->v4l2.audio_meta[off].setting; } else { switch (vctrl->id) { case V4L2_CID_IVTV_DEC_SMOOTH_FF: vctrl->value = itv->dec_options.smooth; break; case V4L2_CID_IVTV_DEC_FR_MASK: vctrl->value = itv->dec_options.fr_mask; break; case V4L2_CID_IVTV_DEC_SP_MUTE: vctrl->value = itv->dec_options.aud_mute; break; case V4L2_CID_IVTV_DEC_FR_FIELD: vctrl->value = itv->dec_options.fr_field; break; case V4L2_CID_IVTV_DEC_AUD_SKIP: vctrl->value = itv->dec_options.mute_frames; break; case V4L2_CID_IVTV_DEC_NUM_BUFFERS: vctrl->value = itv->dec_options.decbuffers; break; case V4L2_CID_IVTV_DEC_PREBUFFER: vctrl->value = itv->dec_options.prebuffer; break; default: IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid control\n"); return -EINVAL; } } break; } switch (vctrl->id) { case V4L2_CID_BRIGHTNESS: { struct saa7114 pic; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); vctrl->value = pic.bright; break; } case V4L2_CID_HUE: { struct saa7114 pic; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); vctrl->value = pic.hue; break; } case V4L2_CID_SATURATION: { struct saa7114 pic; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); vctrl->value = pic.sat; break; } case V4L2_CID_CONTRAST: { struct saa7114 pic; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR,DECODER_GET_PICTURE,&pic); vctrl->value = pic.contrast; break; } case V4L2_CID_AUDIO_VOLUME: { struct video_audio va; ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va); vctrl->value = va.volume; break; } case V4L2_CID_AUDIO_MUTE: { struct video_audio va; ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,VIDIOCGAUDIO,&va); vctrl->value = (va.flags & VIDEO_AUDIO_MUTE); break; } default: IVTV_DEBUG(IVTV_DEBUG_ERR, "ctrl: invalid control\n"); return -EINVAL; } break; } case VIDIOC_QUERYCAP: { struct v4l2_capability *vcap = (struct v4l2_capability *)arg; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: querycap\n"); /* driver name */ strcpy(vcap->driver,IVTV_DRIVER_NAME); /* card type */ strcpy(vcap->card,id->itv->v4l2.streams[id->type].v4l2dev.name); /* bus info.. card # will do */ sprintf(vcap->bus_info, "%d", itv->num); /* version */ vcap->version = IVTV_DRIVER_VERSION; /* capabilities */ vcap->capabilities = itv->v4l2.capabilities; /* reserved.. must set to 0! */ vcap->reserved[0] = vcap->reserved[1] = vcap->reserved[2] = vcap->reserved[3] = 0; break; } case VIDIOC_ENUMINPUT: { struct v4l2_input *vin = (struct v4l2_input *)arg; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: enuminput\n"); if ((vin->index < 0) || (vin->index >= itv->v4l2.input.count)) return -EINVAL; /* set it to defaults from our table */ memcpy(vin, &itv->v4l2.input.table.input[vin->index], sizeof(struct v4l2_input)); /* set the standard to whatever our overall standard is */ vin->std = tmk_standards[itv->v4l2.standard.active].id; vin->status = 0; /*FIXME status isn't always ok... */ break; } case VIDIOC_G_FMT: { struct v4l2_format *vfmt = (struct v4l2_format *)arg; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get format\n"); /* FIXME switch on stream type */ memcpy (vfmt, &itv->v4l2.streams[0].format, sizeof(struct v4l2_format)); break; } case VIDIOC_S_FMT: { struct v4l2_format *vfmt = (struct v4l2_format *)arg; struct video_window wind; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set format\n"); /* FIXME only sets resolution for now */ wind.width = vfmt->fmt.pix.width; wind.height = vfmt->fmt.pix.height; ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, DECODER_SET_SIZE,&wind); /* FIXME switch on stream type, bounds checking */ memcpy (&itv->v4l2.streams[0].format, vfmt, sizeof(struct v4l2_format)); /* Adjust res in YUV also */ itv->v4l2.streams[1].format.fmt.pix.height = vfmt->fmt.pix.height; itv->v4l2.streams[1].format.fmt.pix.width = vfmt->fmt.pix.width; break; } case VIDIOC_G_INPUT: { int *inp = (int *)arg; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get input\n"); *inp = itv->v4l2.input.active; break; } case VIDIOC_S_INPUT: { int a_in,inp = *(int *)arg; struct msp_matrix mspm; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set input\n"); if ((inp < 0) || (inp >= itv->v4l2.input.count)) return -EINVAL; if (inp == itv->v4l2.input.active) { IVTV_DEBUG(IVTV_DEBUG_INFO, "Input unchanged\n"); } else { IVTV_DEBUG(IVTV_DEBUG_INFO, "Changing input from %d to %d\n", itv->v4l2.input.active, inp); itv->v4l2.input.active = inp; itv->v4l2.audio.active = itv->v4l2.input.table.input[inp].audioset; /* Mute sound to avoid pop */ mspm.input = 8; mspm.output = itv->v4l2.audio_output; ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR ,MSP_SET_MATRIX,&mspm); if (0 != ivtv_pause_encoder(itv, 0)) IVTV_DEBUG(IVTV_DEBUG_ERR, "Input: Error pausing stream\n"); ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, DECODER_SET_INPUT,&inp); /* Pause to let sound calm down */ ivtv_sleep_timeout(HZ/33); if (0 != ivtv_pause_encoder(itv, 1)) IVTV_DEBUG(IVTV_DEBUG_ERR, "Input: Error unpausing stream\n"); /* FIXME Needs to be card-specific */ a_in = ivtv_set_audio(itv,tmk_audio_mapping); if (a_in < 0) return a_in; } break; } case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *vf=(struct v4l2_frequency *)arg; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get frequency\n"); if ((vf->tuner < 0) || (vf->tuner >= itv->v4l2.tuner.count)) return -EINVAL; vf->frequency = itv->v4l2.freq.frequency; break; } case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *vf=(struct v4l2_frequency *)arg; struct msp_matrix mspm; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set frequency\n"); if ((vf->tuner < 0) || (vf->tuner >= itv->v4l2.tuner.count)) return -EINVAL; itv->v4l2.freq.frequency = vf->frequency; /* Mute sound to avoid pop */ mspm.input = 8; mspm.output = itv->v4l2.audio_output; ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,MSP_SET_MATRIX,&mspm); if (0 != ivtv_pause_encoder(itv, 0)) IVTV_DEBUG(IVTV_DEBUG_ERR, "Freq: Error pausing stream\n"); /* Set frequency */ ivtv_call_i2c_client(itv,IVTV_TUNER_I2C_ADDR, VIDIOCSFREQ,&itv->v4l2.freq.frequency); /* Pause to let sound calm down */ ivtv_sleep_timeout(HZ/33); if (0 != ivtv_pause_encoder(itv, 1)) IVTV_DEBUG(IVTV_DEBUG_ERR, "Freq: Error unpausing stream\n"); /* Unmute */ ivtv_set_audio(itv,tmk_audio_mapping); break; } case VIDIOC_ENUMSTD: { struct v4l2_standard *vs=(struct v4l2_standard *)arg; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: enum standard\n"); if ((vs->index < 0) || (vs->index >= itv->v4l2.standard.count)) return -EINVAL; memcpy(vs, &itv->v4l2.standard.table.std[vs->index], sizeof(struct v4l2_standard)); break; } case VIDIOC_G_STD: { v4l2_std_id *vs=(v4l2_std_id *)arg; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get standard\n"); *vs = itv->v4l2.standard.table.std[itv->v4l2.standard.active].id; break; } case VIDIOC_S_STD: { v4l2_std_id *vs=(v4l2_std_id *)arg; struct video_channel v; int x; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set standard\n"); for (x = 0; x < itv->v4l2.standard.count; x++) { if (itv->v4l2.standard.table.std[x].id & *vs) { IVTV_DEBUG(IVTV_DEBUG_INFO, "Switching standard to %s.\n", itv->v4l2.standard.table.std[x].name); itv->v4l2.standard.active = x; /* fixme set standard here */ switch (itv->v4l2.standard.active) { case 0: /* NTSC */ v.norm = VIDEO_MODE_NTSC; break; case 1: /* PAL */ v.norm = VIDEO_MODE_PAL; break; case 2: /* SECAM */ v.norm = VIDEO_MODE_SECAM; break; default: break; } /* Tuner */ ivtv_call_i2c_client(itv, IVTV_TUNER_I2C_ADDR, VIDIOCSCHAN,&v); /* Tuner Audio */ ivtv_call_i2c_client(itv, IVTV_MSP3400_I2C_ADDR, VIDIOCSCHAN,&v); /* Digitizer */ ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, DECODER_SET_NORM,&v.norm); if (itv->v4l2.standard.active == 0) { // NTSC itv->v4l2.codec.framespergop = 15; itv->v4l2.codec.framerate = 0; } else { // PAL itv->v4l2.codec.framespergop = 12; itv->v4l2.codec.framerate = 1; } return 0; } } return -EINVAL; } case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: set tuner\n"); if ((vt->index < 0) || (vt->index >= itv->v4l2.tuner.count)) return -EINVAL; /* looks like tuner.c doesn't support selection * fallback to stereo... */ vt->audmode = V4L2_TUNER_MODE_STEREO; break; } case VIDIOC_G_TUNER: { struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; int sig=0; IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 ioctl: get tuner\n"); if ((vt->index < 0) || (vt->index >= itv->v4l2.tuner.count)) return -EINVAL; memcpy(vt, &itv->v4l2.tuner.table.tuner[vt->index], sizeof(struct v4l2_tuner)); ivtv_call_i2c_client(itv,IVTV_SAA7115_I2C_ADDR, DECODER_GET_STATUS,&sig); if (sig & DECODER_STATUS_GOOD) { vt->signal = 65535; /* best possible signal */ } else { vt->signal = 0; } break; } case MSP_SET_MATRIX: { struct msp_matrix *mspm = (struct msp_matrix *)arg; /* FIXME hardcoding! */ if ((mspm->input < 1) || (mspm->input > 8)) { IVTV_DEBUG(IVTV_DEBUG_ERR,"Invalid audio input!\n"); return -EINVAL; } if ((mspm->output < 0) || (mspm->output > 3)) { IVTV_DEBUG(IVTV_DEBUG_ERR,"Invalid audio output!\n"); return -EINVAL; } itv->v4l2.audio_output = mspm->output; IVTV_DEBUG(IVTV_DEBUG_INFO, "v4l2 ioctl: set matrix in=%d,out=%d\n", mspm->input, mspm->output); ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,MSP_SET_MATRIX, mspm); break; } case IVTV_IOC_G_CODEC: { struct ivtv_ioctl_codec *codec=(struct ivtv_ioctl_codec *)arg; /* FIXME: bounds check? */ memcpy(codec, &(itv->v4l2.codec), sizeof(struct ivtv_ioctl_codec)); break; } case IVTV_IOC_S_CODEC: { struct ivtv_ioctl_codec *codec=(struct ivtv_ioctl_codec *)arg; /* FIXME: insert abundant parameter validation here */ if((codec->bitrate == 0) || (codec->bitrate_peak == 0) || (codec->bitrate > codec->bitrate_peak) ) { IVTV_DEBUG(IVTV_DEBUG_ERR,"ivtv ioctl: set " "bitrate=%u < peak=%u: failed\n", codec->bitrate, codec->bitrate_peak); return -EINVAL; } else { /* Passed the garbage check */ memcpy(&(itv->v4l2.codec), codec, sizeof(struct ivtv_ioctl_codec)); } /* VCD streamtype has some quirks. Handle them here */ if ((codec->stream_type == IVTV_STREAM_VCD) || (codec->stream_type == IVTV_STREAM_MPEG1)) { struct v4l2_format *vfmt = (struct v4l2_format *)arg; struct video_window wind; int tmpsize = 480; if (itv->v4l2.standard.active == 1) tmpsize = 576; IVTV_DEBUG(IVTV_DEBUG_INFO,"ivtv ioctl: mpeg1_stream " "size %d\n", tmpsize); /* so far it looks like you can change width at will * * but the compressor is unhappy when the height changes * * to anything other than 240 */ wind.width = 352; wind.height = tmpsize; vfmt->fmt.pix.width = 352; vfmt->fmt.pix.height = tmpsize / 2; ivtv_call_i2c_client(itv, IVTV_SAA7115_I2C_ADDR,DECODER_SET_SIZE,&wind); memcpy (&itv->v4l2.streams[0].format, vfmt, sizeof(struct v4l2_format)); } break; } case IVTV_IOCTL_GET_DEBUG_LEVEL: { int *dbg_level = (int *)arg; IVTV_DEBUG(IVTV_DEBUG_INFO, "IVTV_IOCTL_GET_DEBUG_LEVEL ivtv_debug = " "0x%08x\n", ivtv_debug); if (dbg_level) { put_user(ivtv_debug, dbg_level); } else { printk("ivtv: Error: IVTV_IOCTL_GET_DEBUG_LEVEL called with " "NULL\n"); } break; } case IVTV_IOCTL_SET_DEBUG_LEVEL: { int *dbg_level = (int *)arg; int old_debug_level = ivtv_debug; get_user(ivtv_debug, dbg_level); if (!(ivtv_debug & IVTV_DEBUG_ERR)) ivtv_debug |= IVTV_DEBUG_ERR; IVTV_DEBUG(IVTV_DEBUG_INFO, "IVTV_IOCTL_SET_DEBUG_LEVEL ivtv_debug = " "0x%08x (old) 0x%08x (new)\n", ivtv_debug, old_debug_level); put_user(ivtv_debug, dbg_level); break; } /* DEBUGGING ONLY */ #if 0 case 0xFEAF: { /* tmk test msp call */ u32 *argarray = (u32 *)arg; ivtv_call_i2c_client(itv,IVTV_MSP3400_I2C_ADDR,0xFEAF, argarray); break; } #endif case 0x00005401: /* Handle isatty() calls */ return -EINVAL; default: /* If it got here, it's probably not supported.. */ IVTV_DEBUG(IVTV_DEBUG_ERR,"ivtv-api.c: unknown ioctl 0x%08x\n", cmd); return -ENOTTY; } return 0; }