From: Gerd Knorr This is a update for the saa7134 driver. Changes: * add cropping support. * fix Makefile to build the saa6752hs module. * fix locking bug in oss dsp driver. * infrared remote keytable update. * some card-specific fixes. --- 25-akpm/drivers/media/video/saa7134/Makefile | 2 25-akpm/drivers/media/video/saa7134/saa7134-cards.c | 6 25-akpm/drivers/media/video/saa7134/saa7134-core.c | 4 25-akpm/drivers/media/video/saa7134/saa7134-input.c | 24 +- 25-akpm/drivers/media/video/saa7134/saa7134-oss.c | 53 ++++-- 25-akpm/drivers/media/video/saa7134/saa7134-tvaudio.c | 7 25-akpm/drivers/media/video/saa7134/saa7134-video.c | 153 +++++++++++++----- 25-akpm/drivers/media/video/saa7134/saa7134.h | 12 - 8 files changed, 186 insertions(+), 75 deletions(-) diff -puN drivers/media/video/saa7134/Makefile~v4l-saa7134-update drivers/media/video/saa7134/Makefile --- 25/drivers/media/video/saa7134/Makefile~v4l-saa7134-update Mon Apr 5 14:46:34 2004 +++ 25-akpm/drivers/media/video/saa7134/Makefile Mon Apr 5 14:46:34 2004 @@ -3,6 +3,6 @@ saa7134-objs := saa7134-cards.o saa7134- saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o \ saa7134-vbi.o saa7134-video.o saa7134-input.o -obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o +obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa6752hs.o EXTRA_CFLAGS = -I$(src)/.. diff -puN drivers/media/video/saa7134/saa7134-cards.c~v4l-saa7134-update drivers/media/video/saa7134/saa7134-cards.c --- 25/drivers/media/video/saa7134/saa7134-cards.c~v4l-saa7134-update Mon Apr 5 14:46:34 2004 +++ 25-akpm/drivers/media/video/saa7134/saa7134-cards.c Mon Apr 5 14:46:34 2004 @@ -2,7 +2,7 @@ * device driver for philips saa7134 based TV cards * card-specific stuff. * - * (c) 2001-03 Gerd Knorr [SuSE Labs] + * (c) 2001-04 Gerd Knorr [SuSE Labs] * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -732,7 +732,9 @@ struct saa7134_board saa7134_boards[] = [SAA7134_BOARD_ASUSTEK_TVFM7133] = { .name = "ASUS TV-FM 7133", .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1236_MK3, + // probably wrong, the 7133 one is the NTSC version ... + // .tuner_type = TUNER_PHILIPS_FM1236_MK3 + .tuner_type = TUNER_LG_NTSC_NEW_TAPC, .need_tda9887 = 1, .inputs = {{ .name = name_tv, diff -puN drivers/media/video/saa7134/saa7134-core.c~v4l-saa7134-update drivers/media/video/saa7134/saa7134-core.c --- 25/drivers/media/video/saa7134/saa7134-core.c~v4l-saa7134-update Mon Apr 5 14:46:34 2004 +++ 25-akpm/drivers/media/video/saa7134/saa7134-core.c Mon Apr 5 14:46:34 2004 @@ -101,7 +101,7 @@ unsigned int saa7134_devcount; /* debug help functions */ static const char *v4l1_ioctls[] = { - "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", + "0", "GCAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", @@ -466,7 +466,7 @@ int saa7134_set_dmabits(struct saa7134_d } /* audio capture -- dma 3 */ - if (dev->oss.recording) { + if (dev->oss.dma_running) { ctrl |= SAA7134_MAIN_CTRL_TE6; irq |= SAA7134_IRQ1_INTE_RA3_1 | SAA7134_IRQ1_INTE_RA3_0; diff -puN drivers/media/video/saa7134/saa7134.h~v4l-saa7134-update drivers/media/video/saa7134/saa7134.h --- 25/drivers/media/video/saa7134/saa7134.h~v4l-saa7134-update Mon Apr 5 14:46:34 2004 +++ 25-akpm/drivers/media/video/saa7134/saa7134.h Mon Apr 5 14:46:34 2004 @@ -19,7 +19,7 @@ */ #include -#define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,9) +#define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,11) #include #include @@ -73,8 +73,6 @@ enum saa7134_video_out { struct saa7134_tvnorm { char *name; v4l2_std_id id; - unsigned int width; - unsigned int height; /* video decoder */ unsigned int sync_control; @@ -301,7 +299,8 @@ struct saa7134_oss { unsigned int afmt; unsigned int rate; unsigned int channels; - unsigned int recording; + unsigned int recording_on; + unsigned int dma_running; unsigned int blocks; unsigned int blksize; unsigned int bufsize; @@ -395,6 +394,11 @@ struct saa7134_dev { int ctl_y_odd; int ctl_y_even; + /* crop */ + struct v4l2_rect crop_bounds; + struct v4l2_rect crop_defrect; + struct v4l2_rect crop_current; + /* other global state info */ unsigned int automute; struct saa7134_thread thread; diff -puN drivers/media/video/saa7134/saa7134-input.c~v4l-saa7134-update drivers/media/video/saa7134/saa7134-input.c --- 25/drivers/media/video/saa7134/saa7134-input.c~v4l-saa7134-update Mon Apr 5 14:46:34 2004 +++ 25-akpm/drivers/media/video/saa7134/saa7134-input.c Mon Apr 5 14:46:34 2004 @@ -100,42 +100,42 @@ static IR_KEYTAB_TYPE cinergy_codes[IR_K [ 0x23 ] = KEY_STOP, }; -/* Alfons Geser */ +/* Alfons Geser + * updates from Job D. R. Borges */ static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = { [ 18 ] = KEY_POWER, [ 1 ] = KEY_TV, // DVR - [ 21 ] = KEY_VIDEO, // DVD + [ 21 ] = KEY_DVD, // DVD [ 23 ] = KEY_AUDIO, // music - // DVR mode / DVD mode / music mode [ 27 ] = KEY_MUTE, // mute - [ 2 ] = KEY_RESERVED, // MTS/SAP / audio /autoseek - [ 30 ] = KEY_RESERVED, // closed captioning / subtitle / seek + [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek + [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek [ 22 ] = KEY_ZOOM, // full screen - [ 28 ] = KEY_RESERVED, // video source / eject /delall - [ 29 ] = KEY_RESERVED, // playback / angle /del + [ 28 ] = KEY_VIDEO, // video source / eject / delall + [ 29 ] = KEY_RESTART, // playback / angle / del [ 47 ] = KEY_SEARCH, // scan / menu / playlist - [ 48 ] = KEY_RESERVED, // CH surfing / bookmark / memo + [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo [ 49 ] = KEY_HELP, // help - [ 50 ] = KEY_RESERVED, // num/memo + [ 50 ] = KEY_MODE, // num/memo [ 51 ] = KEY_ESC, // cancel [ 12 ] = KEY_UP, // up [ 16 ] = KEY_DOWN, // down [ 8 ] = KEY_LEFT, // left [ 4 ] = KEY_RIGHT, // right - [ 3 ] = KEY_ENTER, // select + [ 3 ] = KEY_SELECT, // select [ 31 ] = KEY_REWIND, // rewind [ 32 ] = KEY_PLAYPAUSE, // play/pause [ 41 ] = KEY_FORWARD, // forward - [ 20 ] = KEY_RESERVED, // repeat + [ 20 ] = KEY_AGAIN, // repeat [ 43 ] = KEY_RECORD, // recording [ 44 ] = KEY_STOP, // stop [ 45 ] = KEY_PLAY, // play - [ 46 ] = KEY_RESERVED, // snapshot + [ 46 ] = KEY_SHUFFLE, // snapshot / shuffle [ 0 ] = KEY_KP0, [ 5 ] = KEY_KP1, diff -puN drivers/media/video/saa7134/saa7134-oss.c~v4l-saa7134-update drivers/media/video/saa7134/saa7134-oss.c --- 25/drivers/media/video/saa7134/saa7134-oss.c~v4l-saa7134-update Mon Apr 5 14:46:34 2004 +++ 25-akpm/drivers/media/video/saa7134/saa7134-oss.c Mon Apr 5 14:46:34 2004 @@ -64,7 +64,7 @@ static int dsp_buffer_conf(struct saa713 dev->oss.bufsize = blksize * blocks; dprintk("buffer config: %d blocks / %d bytes, %d kB total\n", - blocks,blksize,blksize * blocks / 1024); + blocks,blksize,blksize * blocks / 1024); return 0; } @@ -74,6 +74,7 @@ static int dsp_buffer_init(struct saa713 if (!dev->oss.bufsize) BUG(); + videobuf_dma_init(&dev->oss.dma); err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE, dev->oss.bufsize >> PAGE_SHIFT); if (0 != err) @@ -92,6 +93,20 @@ static int dsp_buffer_free(struct saa713 return 0; } +static void dsp_dma_start(struct saa7134_dev *dev) +{ + dev->oss.dma_blk = 0; + dev->oss.dma_running = 1; + saa7134_set_dmabits(dev); +} + +static void dsp_dma_stop(struct saa7134_dev *dev) +{ + dev->oss.dma_blk = -1; + dev->oss.dma_running = 0; + saa7134_set_dmabits(dev); +} + static int dsp_rec_start(struct saa7134_dev *dev) { int err, bswap, sign; @@ -178,10 +193,9 @@ static int dsp_rec_start(struct saa7134_ saa_writel(SAA7134_RS_CONTROL(6),control); /* start dma */ + dev->oss.recording_on = 1; spin_lock_irqsave(&dev->slock,flags); - dev->oss.recording = 1; - dev->oss.dma_blk = 0; - saa7134_set_dmabits(dev); + dsp_dma_start(dev); spin_unlock_irqrestore(&dev->slock,flags); return 0; @@ -199,10 +213,9 @@ static int dsp_rec_stop(struct saa7134_d dprintk("rec_stop dma_blk=%d\n",dev->oss.dma_blk); /* stop dma */ + dev->oss.recording_on = 0; spin_lock_irqsave(&dev->slock,flags); - dev->oss.dma_blk = -1; - dev->oss.recording = 0; - saa7134_set_dmabits(dev); + dsp_dma_stop(dev); spin_unlock_irqrestore(&dev->slock,flags); /* unlock buffer */ @@ -259,7 +272,7 @@ static int dsp_release(struct inode *ino struct saa7134_dev *dev = file->private_data; down(&dev->oss.lock); - if (dev->oss.recording) + if (dev->oss.recording_on) dsp_rec_stop(dev); dsp_buffer_free(dev); dev->oss.users_dsp--; @@ -274,6 +287,7 @@ static ssize_t dsp_read(struct file *fil struct saa7134_dev *dev = file->private_data; DECLARE_WAITQUEUE(wait, current); unsigned int bytes; + unsigned long flags; int err,ret = 0; add_wait_queue(&dev->oss.wq, &wait); @@ -281,7 +295,7 @@ static ssize_t dsp_read(struct file *fil while (count > 0) { /* wait for data if needed */ if (0 == dev->oss.read_count) { - if (!dev->oss.recording) { + if (!dev->oss.recording_on) { err = dsp_rec_start(dev); if (err < 0) { if (0 == ret) @@ -289,6 +303,13 @@ static ssize_t dsp_read(struct file *fil break; } } + if (dev->oss.recording_on && + !dev->oss.dma_running) { + /* recover from overruns */ + spin_lock_irqsave(&dev->slock,flags); + dsp_dma_start(dev); + spin_unlock_irqrestore(&dev->slock,flags); + } if (file->f_flags & O_NONBLOCK) { if (0 == ret) ret = -EAGAIN; @@ -365,7 +386,7 @@ static int dsp_ioctl(struct inode *inode return -EFAULT; down(&dev->oss.lock); dev->oss.channels = val ? 2 : 1; - if (dev->oss.recording) { + if (dev->oss.recording_on) { dsp_rec_stop(dev); dsp_rec_start(dev); } @@ -379,7 +400,7 @@ static int dsp_ioctl(struct inode *inode return -EINVAL; down(&dev->oss.lock); dev->oss.channels = val; - if (dev->oss.recording) { + if (dev->oss.recording_on) { dsp_rec_stop(dev); dsp_rec_start(dev); } @@ -408,7 +429,7 @@ static int dsp_ioctl(struct inode *inode case AFMT_S16_BE: down(&dev->oss.lock); dev->oss.afmt = val; - if (dev->oss.recording) { + if (dev->oss.recording_on) { dsp_rec_stop(dev); dsp_rec_start(dev); } @@ -438,7 +459,7 @@ static int dsp_ioctl(struct inode *inode case SNDCTL_DSP_RESET: down(&dev->oss.lock); - if (dev->oss.recording) + if (dev->oss.recording_on) dsp_rec_stop(dev); up(&dev->oss.lock); return 0; @@ -448,7 +469,7 @@ static int dsp_ioctl(struct inode *inode case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, (int*)arg)) return -EFAULT; - if (dev->oss.recording) + if (dev->oss.recording_on) return -EBUSY; dsp_buffer_free(dev); dsp_buffer_conf(dev,1 << (val & 0xffff), (arg >> 16) & 0xffff); @@ -484,7 +505,7 @@ static unsigned int dsp_poll(struct file if (0 == dev->oss.read_count) { down(&dev->oss.lock); - if (!dev->oss.recording) + if (!dev->oss.recording_on) dsp_rec_start(dev); up(&dev->oss.lock); } else @@ -800,7 +821,7 @@ void saa7134_irq_oss_done(struct saa7134 if (dev->oss.read_count >= dev->oss.blksize * (dev->oss.blocks-2)) { dprintk("irq: overrun [full=%d/%d]\n",dev->oss.read_count, dev->oss.bufsize); - dsp_rec_stop(dev); + dsp_dma_stop(dev); goto done; } diff -puN drivers/media/video/saa7134/saa7134-tvaudio.c~v4l-saa7134-update drivers/media/video/saa7134/saa7134-tvaudio.c --- 25/drivers/media/video/saa7134/saa7134-tvaudio.c~v4l-saa7134-update Mon Apr 5 14:46:34 2004 +++ 25-akpm/drivers/media/video/saa7134/saa7134-tvaudio.c Mon Apr 5 14:46:34 2004 @@ -60,8 +60,9 @@ MODULE_PARM_DESC(audio_clock_tweak, "Aud #define print_regb(reg) printk("%s: reg 0x%03x [%-16s]: 0x%02x\n", \ dev->name,(SAA7134_##reg),(#reg),saa_readb((SAA7134_##reg))) -#define SCAN_INITIAL_DELAY (HZ) -#define SCAN_SAMPLE_DELAY (HZ/5) +#define SCAN_INITIAL_DELAY (HZ) +#define SCAN_SAMPLE_DELAY (HZ/5) +#define SCAN_SUBCARRIER_DELAY (HZ*2) /* ------------------------------------------------------------------ */ /* saa7134 code */ @@ -557,7 +558,7 @@ static int tvaudio_thread(void *data) if (UNSET == audio) audio = i; tvaudio_setmode(dev,&tvaudio[i],"trying"); - if (tvaudio_sleep(dev,HZ*2)) + if (tvaudio_sleep(dev,SCAN_SUBCARRIER_DELAY)) goto restart; if (-1 != tvaudio_getstereo(dev,&tvaudio[i])) { audio = i; diff -puN drivers/media/video/saa7134/saa7134-video.c~v4l-saa7134-update drivers/media/video/saa7134/saa7134-video.c --- 25/drivers/media/video/saa7134/saa7134-video.c~v4l-saa7134-update Mon Apr 5 14:46:34 2004 +++ 25-akpm/drivers/media/video/saa7134/saa7134-video.c Mon Apr 5 14:46:34 2004 @@ -30,14 +30,17 @@ /* ------------------------------------------------------------------ */ -static unsigned int video_debug = 0; -static unsigned int gbuffers = 8; -static unsigned int gbufsize = 768*576*4; -static unsigned int gbufsize_max = 768*576*4; +static unsigned int video_debug = 0; +static unsigned int gbuffers = 8; +static unsigned int noninterlaced = 0; +static unsigned int gbufsize = 768*576*4; +static unsigned int gbufsize_max = 768*576*4; MODULE_PARM(video_debug,"i"); MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); MODULE_PARM(gbuffers,"i"); MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32"); +MODULE_PARM(noninterlaced,"i"); +MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced"); #define dprintk(fmt, arg...) if (video_debug) \ printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) @@ -149,8 +152,6 @@ static struct saa7134_tvnorm tvnorms[] = { .name = "PAL", .id = V4L2_STD_PAL, - .width = 720, - .height = 576, .sync_control = 0x18, .luma_control = 0x40, @@ -169,8 +170,6 @@ static struct saa7134_tvnorm tvnorms[] = },{ .name = "NTSC", .id = V4L2_STD_NTSC, - .width = 720, - .height = 480, .sync_control = 0x59, .luma_control = 0x40, @@ -189,8 +188,6 @@ static struct saa7134_tvnorm tvnorms[] = },{ .name = "SECAM", .id = V4L2_STD_SECAM, - .width = 720, - .height = 576, .sync_control = 0x18, /* old: 0x58, */ .luma_control = 0x1b, @@ -209,8 +206,6 @@ static struct saa7134_tvnorm tvnorms[] = },{ .name = "PAL-M", .id = V4L2_STD_PAL_M, - .width = 720, - .height = 480, .sync_control = 0x59, .luma_control = 0x40, @@ -229,8 +224,6 @@ static struct saa7134_tvnorm tvnorms[] = },{ .name = "PAL-Nc", .id = V4L2_STD_PAL_Nc, - .width = 720, - .height = 576, .sync_control = 0x18, .luma_control = 0x40, @@ -437,15 +430,33 @@ void res_free(struct saa7134_dev *dev, s static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { struct video_channel c; - int luma_control,mux; + int luma_control,sync_control,mux; dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; mux = card_in(dev,dev->ctl_input).vmux; luma_control = norm->luma_control; + sync_control = norm->sync_control; + if (mux > 5) luma_control |= 0x80; /* svideo */ + if (noninterlaced) + sync_control |= 0x20; + + /* setup cropping */ + dev->crop_bounds.left = norm->h_start; + dev->crop_defrect.left = norm->h_start; + 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_defrect.top = norm->video_v_start*2; + dev->crop_bounds.height = ((norm->id & V4L2_STD_525_60) ? 524 : 624) + - dev->crop_bounds.top; + dev->crop_defrect.height = (norm->video_v_stop - norm->video_v_start +1)*2; + + dev->crop_current = dev->crop_defrect; /* setup video decoder */ saa_writeb(SAA7134_INCR_DELAY, 0x08); @@ -458,7 +469,7 @@ static void set_tvnorm(struct saa7134_de saa_writeb(SAA7134_HSYNC_STOP, 0xe0); saa_writeb(SAA7134_SOURCE_TIMING1, norm->src_timing); - saa_writeb(SAA7134_SYNC_CTRL, norm->sync_control); + 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); @@ -563,25 +574,30 @@ static void set_v_scale(struct saa7134_d static void set_size(struct saa7134_dev *dev, int task, int width, int height, int interlace) { - struct saa7134_tvnorm *norm = dev->tvnorm; int prescale,xscale,yscale,y_even,y_odd; + int h_start, h_stop, v_start, v_stop; int div = interlace ? 2 : 1; /* setup video scaler */ - saa_writeb(SAA7134_VIDEO_H_START1(task), norm->h_start & 0xff); - saa_writeb(SAA7134_VIDEO_H_START2(task), norm->h_start >> 8); - saa_writeb(SAA7134_VIDEO_H_STOP1(task), norm->h_stop & 0xff); - saa_writeb(SAA7134_VIDEO_H_STOP2(task), norm->h_stop >> 8); - saa_writeb(SAA7134_VIDEO_V_START1(task), norm->video_v_start & 0xff); - saa_writeb(SAA7134_VIDEO_V_START2(task), norm->video_v_start >> 8); - saa_writeb(SAA7134_VIDEO_V_STOP1(task), norm->video_v_stop & 0xff); - saa_writeb(SAA7134_VIDEO_V_STOP2(task), norm->video_v_stop >> 8); + h_start = dev->crop_current.left; + v_start = dev->crop_current.top/2; + h_stop = (dev->crop_current.left + dev->crop_current.width -1); + v_stop = (dev->crop_current.top + dev->crop_current.height -1)/2; + + saa_writeb(SAA7134_VIDEO_H_START1(task), h_start & 0xff); + saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8); + saa_writeb(SAA7134_VIDEO_H_STOP1(task), h_stop & 0xff); + saa_writeb(SAA7134_VIDEO_H_STOP2(task), h_stop >> 8); + saa_writeb(SAA7134_VIDEO_V_START1(task), v_start & 0xff); + saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8); + saa_writeb(SAA7134_VIDEO_V_STOP1(task), v_stop & 0xff); + saa_writeb(SAA7134_VIDEO_V_STOP2(task), v_stop >> 8); - prescale = norm->width / width; + prescale = dev->crop_defrect.width / width; if (0 == prescale) prescale = 1; - xscale = 1024 * norm->width / prescale / width; - yscale = 512 * div * norm->height / height; + xscale = 1024 * dev->crop_defrect.width / prescale / width; + yscale = 512 * div * dev->crop_defrect.height / height; 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); @@ -708,8 +724,8 @@ static int verify_preview(struct saa7134 return -EINVAL; field = win->field; - maxw = dev->tvnorm->width; - maxh = dev->tvnorm->height; + maxw = dev->crop_current.width; + maxh = dev->crop_current.height; if (V4L2_FIELD_ANY == field) { field = (win->w.height > maxh/2) @@ -895,8 +911,8 @@ static int buffer_prepare(struct file *f return -EINVAL; if (fh->width < 48 || fh->height < 32 || - fh->width > dev->tvnorm->width || - fh->height > dev->tvnorm->height) + fh->width > dev->crop_current.width || + fh->height > dev->crop_current.height) return -EINVAL; size = (fh->width * fh->height * fh->fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < size) @@ -1393,8 +1409,8 @@ int saa7134_try_fmt(struct saa7134_dev * return -EINVAL; field = f->fmt.pix.field; - maxw = dev->tvnorm->width; - maxh = dev->tvnorm->height; + maxw = dev->crop_current.width; + maxh = dev->crop_current.height; if (V4L2_FIELD_ANY == field) { field = (f->fmt.pix.height > maxh/2) @@ -1482,7 +1498,6 @@ int saa7134_s_fmt(struct saa7134_dev *de } up(&dev->lock); return 0; - break; case V4L2_BUF_TYPE_VBI_CAPTURE: saa7134_vbi_fmt(dev,f); return 0; @@ -1674,6 +1689,74 @@ static int video_do_ioctl(struct inode * return 0; } + case VIDIOC_CROPCAP: + { + struct v4l2_cropcap *cap = arg; + + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + cap->bounds = dev->crop_bounds; + cap->defrect = dev->crop_defrect; + cap->pixelaspect.numerator = 1; + cap->pixelaspect.denominator = 1; + if (dev->tvnorm->id & V4L2_STD_525_60) { + cap->pixelaspect.numerator = 11; + cap->pixelaspect.denominator = 10; + } + if (dev->tvnorm->id & V4L2_STD_625_50) { + cap->pixelaspect.numerator = 54; + cap->pixelaspect.denominator = 59; + } + return 0; + } + + case VIDIOC_G_CROP: + { + struct v4l2_crop * crop = arg; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + crop->c = dev->crop_current; + return 0; + } + case VIDIOC_S_CROP: + { + struct v4l2_crop *crop = arg; + struct v4l2_rect *b = &dev->crop_bounds; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + if (crop->c.height < 0) + return -EINVAL; + if (crop->c.width < 0) + return -EINVAL; + + if (res_locked(fh->dev,RESOURCE_OVERLAY)) + return -EBUSY; + if (res_locked(fh->dev,RESOURCE_VIDEO)) + return -EBUSY; + + if (crop->c.top < b->top) + crop->c.top = b->top; + if (crop->c.top > b->top + b->height) + crop->c.top = b->top + b->height; + if (crop->c.height > b->top - crop->c.top + b->height) + crop->c.height = b->top - crop->c.top + b->height; + + if (crop->c.left < b->left) + crop->c.top = b->left; + if (crop->c.left > b->left + b->width) + crop->c.top = 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; + + dev->crop_current = crop->c; + return 0; + } + /* --- tuner ioctls ------------------------------------------ */ case VIDIOC_G_TUNER: { _