X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Fsaa7134%2Fsaa7134-video.c;h=830617ea81cc5ca0b6c68fce66fe45be112a1fc8;hb=refs%2Fheads%2Fvserver;hp=0cd39439d13496eba546a568c728174f5bebfb83;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 0cd39439d..830617ea8 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1,4 +1,5 @@ /* + * * device driver for philips saa7134 based TV cards * video4linux video interface * @@ -22,38 +23,84 @@ #include #include #include +#include #include #include #include "saa7134-reg.h" #include "saa7134.h" +#include -#define V4L2_I2C_CLIENTS 1 +#ifdef CONFIG_VIDEO_V4L1_COMPAT +/* Include V4L1 specific functions. Should be removed soon */ +#include +#endif /* ------------------------------------------------------------------ */ static unsigned int video_debug = 0; static unsigned int gbuffers = 8; -static unsigned int noninterlaced = 0; +static unsigned int noninterlaced = 1; static unsigned int gbufsize = 720*576*4; static unsigned int gbufsize_max = 720*576*4; -MODULE_PARM(video_debug,"i"); +static char secam[] = "--"; +module_param(video_debug, int, 0644); MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); -MODULE_PARM(gbuffers,"i"); +module_param(gbuffers, int, 0444); MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32"); -MODULE_PARM(noninterlaced,"i"); -MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced"); +module_param(noninterlaced, int, 0644); +MODULE_PARM_DESC(noninterlaced,"capture non interlaced video"); +module_param_string(secam, secam, sizeof(secam), 0644); +MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); + #define dprintk(fmt, arg...) if (video_debug) \ printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) +/* ------------------------------------------------------------------ */ +/* Defines for Video Output Port Register at address 0x191 */ + +/* Bit 0: VIP code T bit polarity */ + +#define VP_T_CODE_P_NON_INVERTED 0x00 +#define VP_T_CODE_P_INVERTED 0x01 + +/* ------------------------------------------------------------------ */ +/* Defines for Video Output Port Register at address 0x195 */ + +/* Bit 2: Video output clock delay control */ + +#define VP_CLK_CTRL2_NOT_DELAYED 0x00 +#define VP_CLK_CTRL2_DELAYED 0x04 + +/* Bit 1: Video output clock invert control */ + +#define VP_CLK_CTRL1_NON_INVERTED 0x00 +#define VP_CLK_CTRL1_INVERTED 0x02 + +/* ------------------------------------------------------------------ */ +/* Defines for Video Output Port Register at address 0x196 */ + +/* Bits 2 to 0: VSYNC pin video vertical sync type */ + +#define VP_VS_TYPE_MASK 0x07 + +#define VP_VS_TYPE_OFF 0x00 +#define VP_VS_TYPE_V123 0x01 +#define VP_VS_TYPE_V_ITU 0x02 +#define VP_VS_TYPE_VGATE_L 0x03 +#define VP_VS_TYPE_RESERVED1 0x04 +#define VP_VS_TYPE_RESERVED2 0x05 +#define VP_VS_TYPE_F_ITU 0x06 +#define VP_VS_TYPE_SC_FID 0x07 + /* ------------------------------------------------------------------ */ /* data structs for video */ static int video_out[][9] = { [CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 }, }; - + static struct saa7134_format formats[] = { { .name = "8 bpp gray", @@ -155,18 +202,20 @@ static struct saa7134_format formats[] = { .h_stop = 719, \ .video_v_start = 24, \ .video_v_stop = 311, \ - .vbi_v_start = 7, \ - .vbi_v_stop = 22, \ + .vbi_v_start_0 = 7, \ + .vbi_v_stop_0 = 22, \ + .vbi_v_start_1 = 319, \ .src_timing = 4 #define NORM_525_60 \ .h_start = 0, \ .h_stop = 703, \ - .video_v_start = 22, \ - .video_v_stop = 22+239, \ - .vbi_v_start = 10, /* FIXME */ \ - .vbi_v_stop = 21, /* FIXME */ \ - .src_timing = 1 + .video_v_start = 23, \ + .video_v_stop = 262, \ + .vbi_v_start_0 = 10, \ + .vbi_v_stop_0 = 21, \ + .vbi_v_start_1 = 273, \ + .src_timing = 7 static struct saa7134_tvnorm tvnorms[] = { { @@ -234,7 +283,43 @@ static struct saa7134_tvnorm tvnorms[] = { .id = V4L2_STD_SECAM, NORM_625_50, - .sync_control = 0x18, /* old: 0x58, */ + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + + },{ + .name = "SECAM-DK", + .id = V4L2_STD_SECAM_DK, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + + },{ + .name = "SECAM-L", + .id = V4L2_STD_SECAM_L, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + + },{ + .name = "SECAM-Lc", + .id = V4L2_STD_SECAM_LC, + NORM_625_50, + + .sync_control = 0x18, .luma_control = 0x1b, .chroma_ctrl1 = 0xd1, .chroma_gain = 0x80, @@ -265,6 +350,25 @@ static struct saa7134_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x06, .vgate_misc = 0x1c, + },{ + .name = "PAL-60", + .id = V4L2_STD_PAL_60, + + .h_start = 0, + .h_stop = 719, + .video_v_start = 23, + .video_v_stop = 262, + .vbi_v_start_0 = 10, + .vbi_v_stop_0 = 21, + .vbi_v_start_1 = 273, + .src_timing = 7, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, } }; #define TVNORMS ARRAY_SIZE(tvnorms) @@ -314,8 +418,8 @@ static const struct v4l2_queryctrl video_ctrls[] = { .default_value = 0, .type = V4L2_CTRL_TYPE_INTEGER, },{ - .id = V4L2_CID_VFLIP, - .name = "vertical flip", + .id = V4L2_CID_HFLIP, + .name = "Mirror", .minimum = 0, .maximum = 1, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -371,7 +475,7 @@ static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); static const struct v4l2_queryctrl* ctrl_by_id(unsigned int id) { unsigned int i; - + for (i = 0; i < CTRLS; i++) if (video_ctrls[i].id == id) return video_ctrls+i; @@ -398,17 +502,17 @@ static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int return 1; /* is it free? */ - down(&dev->lock); + mutex_lock(&dev->lock); if (dev->resources & bit) { /* no, someone else uses it */ - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; } /* it's free, grab it */ fh->resources |= bit; dev->resources |= bit; dprintk("res: get %d\n",bit); - up(&dev->lock); + mutex_unlock(&dev->lock); return 1; } @@ -427,25 +531,23 @@ int res_locked(struct saa7134_dev *dev, unsigned int bit) static void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) { - if ((fh->resources & bits) != bits) - BUG(); + BUG_ON((fh->resources & bits) != bits); - down(&dev->lock); + mutex_lock(&dev->lock); fh->resources &= ~bits; dev->resources &= ~bits; dprintk("res: put %d\n",bits); - up(&dev->lock); + mutex_unlock(&dev->lock); } /* ------------------------------------------------------------------ */ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { - int luma_control,sync_control,mux,nosignal; + int luma_control,sync_control,mux; dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; - nosignal = (0 == (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)); mux = card_in(dev,dev->ctl_input).vmux; luma_control = norm->luma_control; @@ -453,7 +555,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) if (mux > 5) luma_control |= 0x80; /* svideo */ - if (noninterlaced || nosignal) + if (noninterlaced || dev->nosignal) sync_control |= 0x20; /* setup cropping */ @@ -462,7 +564,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) dev->crop_bounds.width = norm->h_stop - norm->h_start +1; dev->crop_defrect.width = norm->h_stop - norm->h_start +1; - dev->crop_bounds.top = (norm->vbi_v_stop+1)*2; + dev->crop_bounds.top = (norm->vbi_v_stop_0+1)*2; dev->crop_defrect.top = norm->video_v_start*2; dev->crop_bounds.height = ((norm->id & V4L2_STD_525_60) ? 524 : 624) - dev->crop_bounds.top; @@ -480,12 +582,12 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) saa_writeb(SAA7134_HSYNC_START, 0xeb); saa_writeb(SAA7134_HSYNC_STOP, 0xe0); saa_writeb(SAA7134_SOURCE_TIMING1, norm->src_timing); - + saa_writeb(SAA7134_SYNC_CTRL, sync_control); saa_writeb(SAA7134_LUMA_CTRL, luma_control); saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_contrast); - + saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation); saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1); @@ -501,22 +603,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); -#ifdef V4L2_I2C_CLIENTS saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id); -#else - { - /* pass down info to the i2c chips (v4l1) */ - struct video_channel c; - memset(&c,0,sizeof(c)); - c.channel = dev->ctl_input; - c.norm = VIDEO_MODE_PAL; - if (norm->id & V4L2_STD_NTSC) - c.norm = VIDEO_MODE_NTSC; - if (norm->id & V4L2_STD_SECAM) - c.norm = VIDEO_MODE_SECAM; - saa7134_i2c_call_clients(dev,VIDIOCSCHAN,&c); - } -#endif } static void video_mux(struct saa7134_dev *dev, int input) @@ -568,7 +655,7 @@ static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) static void set_v_scale(struct saa7134_dev *dev, int task, int yscale) { int val,mirror; - + saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale & 0xff); saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8); @@ -617,12 +704,12 @@ static void set_size(struct saa7134_dev *dev, int task, prescale = 1; xscale = 1024 * dev->crop_current.width / prescale / width; yscale = 512 * div * dev->crop_current.height / height; - dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); + dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); set_h_prescale(dev,task,prescale); saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff); saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8); set_v_scale(dev,task,yscale); - + saa_writeb(SAA7134_VIDEO_PIXELS1(task), width & 0xff); saa_writeb(SAA7134_VIDEO_PIXELS2(task), width >> 8); saa_writeb(SAA7134_VIDEO_LINES1(task), height/div & 0xff); @@ -649,7 +736,7 @@ static void sort_cliplist(struct cliplist *cl, int entries) { struct cliplist swap; int i,j,n; - + for (i = entries-2; i >= 0; i--) { for (n = 0, j = 0; j <= i; j++) { if (cl[j].position > cl[j+1].position) { @@ -747,20 +834,20 @@ static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win) maxh = dev->crop_current.height; if (V4L2_FIELD_ANY == field) { - field = (win->w.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } + field = (win->w.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_TOP; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } win->field = field; if (win->w.width > maxw) @@ -844,7 +931,7 @@ static int buffer_activate(struct saa7134_dev *dev, dprintk("buffer_activate buf=%p\n",buf); buf->vb.state = STATE_ACTIVE; buf->top_seen = 0; - + set_size(dev,TASK_A,buf->vb.width,buf->vb.height, V4L2_FIELD_HAS_BOTH(buf->vb.field)); if (buf->fmt->yuv) @@ -916,15 +1003,16 @@ static int buffer_activate(struct saa7134_dev *dev, return 0; } -static int buffer_prepare(struct file *file, struct videobuf_buffer *vb, +static int buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, enum v4l2_field field) { - struct saa7134_fh *fh = file->private_data; + struct saa7134_fh *fh = q->priv_data; struct saa7134_dev *dev = fh->dev; - struct saa7134_buf *buf = (struct saa7134_buf *)vb; + struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); unsigned int size; int err; - + /* sanity checks */ if (NULL == fh->fmt) return -EINVAL; @@ -947,7 +1035,7 @@ static int buffer_prepare(struct file *file, struct videobuf_buffer *vb, buf->vb.size != size || buf->vb.field != field || buf->fmt != fh->fmt) { - saa7134_dma_free(dev,buf); + saa7134_dma_free(q,buf); } if (STATE_NEEDS_INIT == buf->vb.state) { @@ -958,7 +1046,7 @@ static int buffer_prepare(struct file *file, struct videobuf_buffer *vb, buf->fmt = fh->fmt; buf->pt = &fh->pt_cap; - err = videobuf_iolock(dev->pci,&buf->vb,&dev->ovbuf); + err = videobuf_iolock(q,&buf->vb,&dev->ovbuf); if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, @@ -973,14 +1061,14 @@ static int buffer_prepare(struct file *file, struct videobuf_buffer *vb, return 0; oops: - saa7134_dma_free(dev,buf); + saa7134_dma_free(q,buf); return err; } static int -buffer_setup(struct file *file, unsigned int *count, unsigned int *size) +buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { - struct saa7134_fh *fh = file->private_data; + struct saa7134_fh *fh = q->priv_data; *size = fh->fmt->depth * fh->width * fh->height >> 3; if (0 == *count) @@ -989,20 +1077,19 @@ buffer_setup(struct file *file, unsigned int *count, unsigned int *size) return 0; } -static void buffer_queue(struct file *file, struct videobuf_buffer *vb) +static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) { - struct saa7134_fh *fh = file->private_data; - struct saa7134_buf *buf = (struct saa7134_buf *)vb; - + struct saa7134_fh *fh = q->priv_data; + struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); + saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf); } -static void buffer_release(struct file *file, struct videobuf_buffer *vb) +static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) { - struct saa7134_fh *fh = file->private_data; - struct saa7134_buf *buf = (struct saa7134_buf *)vb; - - saa7134_dma_free(fh->dev,buf); + struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); + + saa7134_dma_free(q,buf); } static struct videobuf_queue_ops video_qops = { @@ -1043,7 +1130,7 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c) case V4L2_CID_PRIVATE_INVERT: c->value = dev->ctl_invert; break; - case V4L2_CID_VFLIP: + case V4L2_CID_HFLIP: c->value = dev->ctl_mirror; break; case V4L2_CID_PRIVATE_Y_EVEN: @@ -1118,7 +1205,7 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); break; - case V4L2_CID_VFLIP: + case V4L2_CID_HFLIP: dev->ctl_mirror = c->value; restart_overlay = 1; break; @@ -1158,7 +1245,7 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh) { struct videobuf_queue* q = NULL; - + switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: q = &fh->cap; @@ -1175,7 +1262,7 @@ static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh) static int saa7134_resource(struct saa7134_fh *fh) { int res = 0; - + switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: res = RESOURCE_VIDEO; @@ -1197,7 +1284,6 @@ static int video_open(struct inode *inode, struct file *file) struct list_head *list; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int radio = 0; - list_for_each(list,&saa7134_devlist) { h = list_entry(list, struct saa7134_dev, devlist); if (h->video_dev && (h->video_dev->minor == minor)) @@ -1218,10 +1304,9 @@ static int video_open(struct inode *inode, struct file *file) v4l2_type_names[type]); /* allocate + initialize per filehandle data */ - fh = kmalloc(sizeof(*fh),GFP_KERNEL); + fh = kzalloc(sizeof(*fh),GFP_KERNEL); if (NULL == fh) return -ENOMEM; - memset(fh,0,sizeof(*fh)); file->private_data = fh; fh->dev = dev; fh->radio = radio; @@ -1229,35 +1314,32 @@ static int video_open(struct inode *inode, struct file *file) fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); fh->width = 720; fh->height = 576; -#ifdef VIDIOC_G_PRIORITY v4l2_prio_open(&dev->prio,&fh->prio); -#endif videobuf_queue_init(&fh->cap, &video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, - sizeof(struct saa7134_buf)); - init_MUTEX(&fh->cap.lock); - saa7134_pgtable_alloc(dev->pci,&fh->pt_cap); - + sizeof(struct saa7134_buf), + fh); videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, - sizeof(struct saa7134_buf)); - init_MUTEX(&fh->vbi.lock); + sizeof(struct saa7134_buf), + fh); + saa7134_pgtable_alloc(dev->pci,&fh->pt_cap); saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi); if (fh->radio) { /* switch to radio mode */ saa7134_tvaudio_setinput(dev,&card(dev).radio); - saa7134_i2c_call_clients(dev,AUDC_SET_RADIO,NULL); + saa7134_i2c_call_clients(dev,AUDC_SET_RADIO, NULL); } else { /* switch to video/vbi mode */ video_mux(dev,dev->ctl_input); } - return 0; + return 0; } static ssize_t @@ -1269,13 +1351,15 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) case V4L2_BUF_TYPE_VIDEO_CAPTURE: if (res_locked(fh->dev,RESOURCE_VIDEO)) return -EBUSY; - return videobuf_read_one(file, saa7134_queue(fh), - data, count, ppos); + return videobuf_read_one(saa7134_queue(fh), + data, count, ppos, + file->f_flags & O_NONBLOCK); case V4L2_BUF_TYPE_VBI_CAPTURE: if (!res_get(fh->dev,fh,RESOURCE_VBI)) return -EBUSY; - return videobuf_read_stream(file, saa7134_queue(fh), - data, count, ppos, 1); + return videobuf_read_stream(saa7134_queue(fh), + data, count, ppos, 1, + file->f_flags & O_NONBLOCK); break; default: BUG(); @@ -1296,21 +1380,21 @@ video_poll(struct file *file, struct poll_table_struct *wait) if (!list_empty(&fh->cap.stream)) buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); } else { - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); if (UNSET == fh->cap.read_off) { - /* need to capture a new frame */ + /* need to capture a new frame */ if (res_locked(fh->dev,RESOURCE_VIDEO)) { - up(&fh->cap.lock); - return POLLERR; - } - if (0 != fh->cap.ops->buf_prepare(file,fh->cap.read_buf,fh->cap.field)) { - up(&fh->cap.lock); - return POLLERR; - } - fh->cap.ops->buf_queue(file,fh->cap.read_buf); - fh->cap.read_off = 0; + mutex_unlock(&fh->cap.lock); + return POLLERR; + } + if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) { + mutex_unlock(&fh->cap.lock); + return POLLERR; + } + fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); + fh->cap.read_off = 0; } - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); buf = fh->cap.read_buf; } @@ -1340,29 +1424,38 @@ static int video_release(struct inode *inode, struct file *file) /* stop video capture */ if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_streamoff(file,&fh->cap); + videobuf_streamoff(&fh->cap); res_free(dev,fh,RESOURCE_VIDEO); } if (fh->cap.read_buf) { - buffer_release(file,fh->cap.read_buf); + buffer_release(&fh->cap,fh->cap.read_buf); kfree(fh->cap.read_buf); } /* stop vbi capture */ if (res_check(fh, RESOURCE_VBI)) { if (fh->vbi.streaming) - videobuf_streamoff(file,&fh->vbi); + videobuf_streamoff(&fh->vbi); if (fh->vbi.reading) - videobuf_read_stop(file,&fh->vbi); + videobuf_read_stop(&fh->vbi); res_free(dev,fh,RESOURCE_VBI); } + /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/ + saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0); + saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0); + saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); + saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); + + saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); + + /* free stuff */ + videobuf_mmap_free(&fh->cap); + videobuf_mmap_free(&fh->vbi); saa7134_pgtable_free(dev->pci,&fh->pt_cap); saa7134_pgtable_free(dev->pci,&fh->pt_vbi); -#ifdef VIDIOC_G_PRIORITY v4l2_prio_close(&dev->prio,&fh->prio); -#endif file->private_data = NULL; kfree(fh); return 0; @@ -1372,13 +1465,13 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma) { struct saa7134_fh *fh = file->private_data; - - return videobuf_mmap_mapper(vma,saa7134_queue(fh)); + + return videobuf_mmap_mapper(saa7134_queue(fh), vma); } /* ------------------------------------------------------------------ */ -void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) +static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) { struct saa7134_tvnorm *norm = dev->tvnorm; @@ -1386,23 +1479,16 @@ void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; f->fmt.vbi.offset = 64 * 4; - f->fmt.vbi.start[0] = norm->vbi_v_start; - f->fmt.vbi.count[0] = norm->vbi_v_stop - norm->vbi_v_start +1; - f->fmt.vbi.start[1] = norm->video_v_stop + norm->vbi_v_start +1; + f->fmt.vbi.start[0] = norm->vbi_v_start_0; + f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1; + f->fmt.vbi.start[1] = norm->vbi_v_start_1; f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ -#if 0 - if (V4L2_STD_PAL == norm->id) { - /* FIXME */ - f->fmt.vbi.start[0] += 3; - f->fmt.vbi.start[1] += 3*2; - } -#endif } -int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, - struct v4l2_format *f) +static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, + struct v4l2_format *f) { switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -1417,6 +1503,10 @@ int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, f->fmt.pix.height * f->fmt.pix.bytesperline; return 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } f->fmt.win = fh->win; return 0; case V4L2_BUF_TYPE_VBI_CAPTURE: @@ -1427,11 +1517,11 @@ int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, } } -int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, - struct v4l2_format *f) +static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, + struct v4l2_format *f) { int err; - + switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { @@ -1446,7 +1536,7 @@ int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, field = f->fmt.pix.field; maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); - + if (V4L2_FIELD_ANY == field) { field = (f->fmt.pix.height > maxh/2) ? V4L2_FIELD_INTERLACED @@ -1472,14 +1562,19 @@ int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, f->fmt.pix.width = maxw; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; + f->fmt.pix.width &= ~0x03; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - + return 0; } case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } err = verify_preview(dev,&f->fmt.win); if (0 != err) return err; @@ -1492,36 +1587,40 @@ int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, } } -int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, - struct v4l2_format *f) +static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, + struct v4l2_format *f) { unsigned long flags; int err; - + switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: err = saa7134_try_fmt(dev,fh,f); if (0 != err) return err; - + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); fh->width = f->fmt.pix.width; fh->height = f->fmt.pix.height; fh->cap.field = f->fmt.pix.field; return 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } err = verify_preview(dev,&f->fmt.win); if (0 != err) return err; - down(&dev->lock); + mutex_lock(&dev->lock); fh->win = f->fmt.win; fh->nclips = f->fmt.win.clipcount; if (fh->nclips > 8) fh->nclips = 8; if (copy_from_user(fh->clips,f->fmt.win.clips, sizeof(struct v4l2_clip)*fh->nclips)) { - up(&dev->lock); + mutex_unlock(&dev->lock); return -EFAULT; } @@ -1531,7 +1630,7 @@ int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; case V4L2_BUF_TYPE_VBI_CAPTURE: saa7134_vbi_fmt(dev,f); @@ -1545,7 +1644,7 @@ int saa7134_common_ioctl(struct saa7134_dev *dev, unsigned int cmd, void *arg) { int err; - + switch (cmd) { case VIDIOC_QUERYCTRL: { @@ -1565,9 +1664,9 @@ int saa7134_common_ioctl(struct saa7134_dev *dev, return get_control(dev,arg); case VIDIOC_S_CTRL: { - down(&dev->lock); + mutex_lock(&dev->lock); err = set_control(dev,NULL,arg); - up(&dev->lock); + mutex_unlock(&dev->lock); return err; } /* --- input switching --------------------------------------- */ @@ -1612,20 +1711,21 @@ int saa7134_common_ioctl(struct saa7134_dev *dev, case VIDIOC_S_INPUT: { int *i = arg; - + if (*i < 0 || *i >= SAA7134_INPUT_MAX) return -EINVAL; if (NULL == card_in(dev,*i).name) return -EINVAL; - down(&dev->lock); + mutex_lock(&dev->lock); video_mux(dev,*i); - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; } } return 0; } +EXPORT_SYMBOL(saa7134_common_ioctl); /* * This function is _not_ called directly, but from @@ -1641,9 +1741,8 @@ static int video_do_ioctl(struct inode *inode, struct file *file, int err; if (video_debug > 1) - saa7134_print_ioctl(dev->name,cmd); + v4l_print_ioctl(dev->name,cmd); -#ifdef VIDIOC_G_PRIORITY switch (cmd) { case VIDIOC_S_CTRL: case VIDIOC_S_STD: @@ -1654,26 +1753,32 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (0 != err) return err; } -#endif switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; - + unsigned int tuner_type = dev->tuner_type; + memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "saa7134"); + strcpy(cap->driver, "saa7134"); strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); cap->version = SAA7134_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_TUNER | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_TUNER; + if (saa7134_no_overlay <= 0) { + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + } + + if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) + cap->capabilities &= ~V4L2_CAP_TUNER; + return 0; } @@ -1704,6 +1809,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, { v4l2_std_id *id = arg; unsigned int i; + v4l2_std_id fixup; for (i = 0; i < TVNORMS; i++) if (*id == tvnorms[i].id) @@ -1714,18 +1820,33 @@ static int video_do_ioctl(struct inode *inode, struct file *file, break; if (i == TVNORMS) return -EINVAL; - - down(&dev->lock); + if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { + if (secam[0] == 'L' || secam[0] == 'l') { + if (secam[1] == 'C' || secam[1] == 'c') + fixup = V4L2_STD_SECAM_LC; + else + fixup = V4L2_STD_SECAM_L; + } else { + if (secam[0] == 'D' || secam[0] == 'd') + fixup = V4L2_STD_SECAM_DK; + else + fixup = V4L2_STD_SECAM; + } + for (i = 0; i < TVNORMS; i++) + if (fixup == tvnorms[i].id) + break; + } + mutex_lock(&dev->lock); if (res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); stop_preview(dev,fh); set_tvnorm(dev,&tvnorms[i]); start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); - } else + } else set_tvnorm(dev,&tvnorms[i]); saa7134_tvaudio_do_scan(dev); - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; } @@ -1787,9 +1908,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file, crop->c.height = b->top - crop->c.top + b->height; if (crop->c.left < b->left) - crop->c.top = b->left; + crop->c.left = b->left; if (crop->c.left > b->left + b->width) - crop->c.top = b->left + b->width; + crop->c.left = b->left + b->width; if (crop->c.width > b->left - crop->c.left + b->width) crop->c.width = b->left - crop->c.left + b->width; @@ -1811,6 +1932,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, break; if (NULL != card_in(dev,n).name) { strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | @@ -1857,18 +1979,16 @@ static int video_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) return -EINVAL; - down(&dev->lock); + mutex_lock(&dev->lock); dev->ctl_freq = f->frequency; -#ifdef V4L2_I2C_CLIENTS + saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f); -#else - saa7134_i2c_call_clients(dev,VIDIOCSFREQ,&dev->ctl_freq); -#endif + saa7134_tvaudio_do_scan(dev); - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; } - + /* --- control ioctls ---------------------------------------- */ case VIDIOC_ENUMINPUT: case VIDIOC_G_INPUT: @@ -1888,28 +2008,26 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_S_AUDIO: return 0; - case VIDIOC_G_PARM: - { - struct v4l2_captureparm *parm = arg; - memset(parm,0,sizeof(*parm)); - return 0; - } - -#ifdef VIDIOC_G_PRIORITY - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; - - *p = v4l2_prio_max(&dev->prio); - return 0; - } - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; - - return v4l2_prio_change(&dev->prio, &fh->prio, *prio); - } -#endif + case VIDIOC_G_PARM: + { + struct v4l2_captureparm *parm = arg; + memset(parm,0,sizeof(*parm)); + return 0; + } + + case VIDIOC_G_PRIORITY: + { + enum v4l2_priority *p = arg; + + *p = v4l2_prio_max(&dev->prio); + return 0; + } + case VIDIOC_S_PRIORITY: + { + enum v4l2_priority *prio = arg; + + return v4l2_prio_change(&dev->prio, &fh->prio, *prio); + } /* --- preview ioctls ---------------------------------------- */ case VIDIOC_ENUM_FMT: @@ -1923,6 +2041,10 @@ static int video_do_ioctl(struct inode *inode, struct file *file, switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } if (index >= FORMATS) return -EINVAL; if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && @@ -1944,7 +2066,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, strcpy(f->description,"vbi data"); break; default: - return -EINVAL; + return -EINVAL; } return 0; } @@ -1960,7 +2082,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_framebuffer *fb = arg; struct saa7134_format *fmt; - + if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) return -EPERM; @@ -1983,6 +2105,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file, int *on = arg; if (*on) { + if (saa7134_no_overlay > 0) { + printk ("no_overlay\n"); + return -EINVAL; + } + if (!res_get(dev,fh,RESOURCE_OVERLAY)) return -EBUSY; spin_lock_irqsave(&dev->slock,flags); @@ -2016,7 +2143,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_format *f = arg; return saa7134_try_fmt(dev,fh,f); } - +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; @@ -2029,7 +2156,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, req.type = q->type; req.count = gbuffers; req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(file,q,&req); + err = videobuf_reqbufs(q,&req); if (err < 0) return err; memset(mbuf,0,sizeof(*mbuf)); @@ -2041,31 +2168,33 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } return 0; } +#endif case VIDIOC_REQBUFS: - return videobuf_reqbufs(file,saa7134_queue(fh),arg); + return videobuf_reqbufs(saa7134_queue(fh),arg); case VIDIOC_QUERYBUF: return videobuf_querybuf(saa7134_queue(fh),arg); case VIDIOC_QBUF: - return videobuf_qbuf(file,saa7134_queue(fh),arg); + return videobuf_qbuf(saa7134_queue(fh),arg); case VIDIOC_DQBUF: - return videobuf_dqbuf(file,saa7134_queue(fh),arg); + return videobuf_dqbuf(saa7134_queue(fh),arg, + file->f_flags & O_NONBLOCK); case VIDIOC_STREAMON: { int res = saa7134_resource(fh); - if (!res_get(dev,fh,res)) + if (!res_get(dev,fh,res)) return -EBUSY; - return videobuf_streamon(file,saa7134_queue(fh)); + return videobuf_streamon(saa7134_queue(fh)); } case VIDIOC_STREAMOFF: { int res = saa7134_resource(fh); - err = videobuf_streamoff(file,saa7134_queue(fh)); + err = videobuf_streamoff(saa7134_queue(fh)); if (err < 0) return err; res_free(dev,fh,res); @@ -2090,16 +2219,16 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, { struct saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; - + if (video_debug > 1) - saa7134_print_ioctl(dev->name,cmd); + v4l_print_ioctl(dev->name,cmd); switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "saa7134"); + strcpy(cap->driver, "saa7134"); strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); @@ -2116,25 +2245,31 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, memset(t,0,sizeof(*t)); strcpy(t->name, "Radio"); - t->rangelow = (int)(65*16); - t->rangehigh = (int)(108*16); - -#ifdef V4L2_I2C_CLIENTS - saa7134_i2c_call_clients(dev,VIDIOC_G_TUNER,t); -#else - { - struct video_tuner vt; - memset(&vt,0,sizeof(vt)); - saa7134_i2c_call_clients(dev,VIDIOCGTUNER,&vt); - t->signal = vt.signal; + t->type = V4L2_TUNER_RADIO; + + saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); + if (dev->input->amux == TV) { + t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); + t->rxsubchans = (saa_readb(0x529) & 0x08) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } -#endif + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *t = arg; + + if (0 != t->index) + return -EINVAL; + + saa7134_i2c_call_clients(dev,VIDIOC_S_TUNER,t); + return 0; } case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; - + if (i->index != 0) return -EINVAL; strcpy(i->name,"Radio"); @@ -2162,7 +2297,6 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, return 0; } case VIDIOC_S_AUDIO: - case VIDIOC_S_TUNER: case VIDIOC_S_INPUT: case VIDIOC_S_STD: return 0; @@ -2188,7 +2322,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_G_FREQUENCY: case VIDIOC_S_FREQUENCY: return video_do_ioctl(inode,file,cmd,arg); - + default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, radio_do_ioctl); @@ -2211,6 +2345,7 @@ static struct file_operations video_fops = .poll = video_poll, .mmap = video_mmap, .ioctl = video_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -2220,6 +2355,7 @@ static struct file_operations radio_fops = .open = video_open, .release = video_release, .ioctl = radio_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -2229,8 +2365,8 @@ static struct file_operations radio_fops = struct video_device saa7134_video_template = { .name = "saa7134-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY| - VID_TYPE_CLIPPING|VID_TYPE_SCALES, + .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER| + VID_TYPE_CLIPPING|VID_TYPE_SCALES, .hardware = 0, .fops = &video_fops, .minor = -1, @@ -2269,7 +2405,7 @@ int saa7134_video_init1(struct saa7134_dev *dev) dev->ctl_hue = ctrl_by_id(V4L2_CID_HUE)->default_value; dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value; dev->ctl_volume = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value; - dev->ctl_mute = ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value; + dev->ctl_mute = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value; dev->ctl_invert = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value; dev->ctl_automute = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value; @@ -2277,7 +2413,7 @@ int saa7134_video_init1(struct saa7134_dev *dev) dev->tda9887_conf |= TDA9887_AUTOMUTE; dev->automute = 0; - INIT_LIST_HEAD(&dev->video_q.queue); + INIT_LIST_HEAD(&dev->video_q.queue); init_timer(&dev->video_q.timeout); dev->video_q.timeout.function = saa7134_buffer_timeout; dev->video_q.timeout.data = (unsigned long)(&dev->video_q); @@ -2286,17 +2422,32 @@ int saa7134_video_init1(struct saa7134_dev *dev) if (saa7134_boards[dev->board].video_out) { /* enable video output */ int vo = saa7134_boards[dev->board].video_out; + int video_reg; + unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]); + video_reg = video_out[vo][1]; + if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) + video_reg &= ~VP_T_CODE_P_INVERTED; + saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_out[vo][5]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_out[vo][6]); + video_reg = video_out[vo][5]; + if (vid_port_opts & SET_CLOCK_NOT_DELAYED) + video_reg &= ~VP_CLK_CTRL2_DELAYED; + if (vid_port_opts & SET_CLOCK_INVERTED) + video_reg |= VP_CLK_CTRL1_INVERTED; + saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); + video_reg = video_out[vo][6]; + if (vid_port_opts & SET_VSYNC_OFF) { + video_reg &= ~VP_VS_TYPE_MASK; + video_reg |= VP_VS_TYPE_OFF; + } + saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); } - + return 0; } @@ -2319,30 +2470,37 @@ int saa7134_video_fini(struct saa7134_dev *dev) void saa7134_irq_video_intl(struct saa7134_dev *dev) { static const char *st[] = { - "no signal", "found NTSC", "found PAL", "found SECAM" }; - int norm; - - norm = saa_readb(SAA7134_STATUS_VIDEO1) & 0x03; - dprintk("DCSDT: %s\n",st[norm]); - - if (0 != norm) { - /* wake up tvaudio audio carrier scan thread */ - saa7134_tvaudio_do_scan(dev); - if (!noninterlaced) - saa_clearb(SAA7134_SYNC_CTRL, 0x20); - } else { + "(no signal)", "NTSC", "PAL", "SECAM" }; + u32 st1,st2; + + st1 = saa_readb(SAA7134_STATUS_VIDEO1); + st2 = saa_readb(SAA7134_STATUS_VIDEO2); + dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n", + (st1 & 0x40) ? "not locked" : "locked", + (st2 & 0x40) ? "no" : "yes", + st[st1 & 0x03]); + dev->nosignal = (st1 & 0x40) || (st2 & 0x40); + + if (dev->nosignal) { /* no video signal -> mute audio */ if (dev->ctl_automute) dev->automute = 1; saa7134_tvaudio_setmute(dev); saa_setb(SAA7134_SYNC_CTRL, 0x20); + } else { + /* wake up tvaudio audio carrier scan thread */ + saa7134_tvaudio_do_scan(dev); + if (!noninterlaced) + saa_clearb(SAA7134_SYNC_CTRL, 0x20); } + if (dev->mops && dev->mops->signal_change) + dev->mops->signal_change(dev); } void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) { enum v4l2_field field; - + spin_lock(&dev->slock); if (dev->video_q.curr) { dev->video_fieldcount++;