/*
+ * $Id: saa7134-video.c,v 1.19 2004/11/07 14:44:59 kraxel Exp $
+ *
* device driver for philips saa7134 based TV cards
* video4linux video interface
*
static unsigned int noninterlaced = 0;
static unsigned int gbufsize = 720*576*4;
static unsigned int gbufsize_max = 720*576*4;
-MODULE_PARM(video_debug,"i");
+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_param(noninterlaced, int, 0644);
MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced");
#define dprintk(fmt, arg...) if (video_debug) \
static int video_out[][9] = {
[CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 },
};
-
+
static struct saa7134_format formats[] = {
{
.name = "8 bpp gray",
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;
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);
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);
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);
{
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) {
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)
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;
}
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)
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;
-
+ struct saa7134_fh *fh = q->priv_data;
+ struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+
saa7134_dma_free(fh->dev,buf);
}
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;
static int saa7134_resource(struct saa7134_fh *fh)
{
int res = 0;
-
+
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
res = RESOURCE_VIDEO;
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))
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) {
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();
up(&fh->cap.lock);
return POLLERR;
}
- if (0 != fh->cap.ops->buf_prepare(file,fh->cap.read_buf,fh->cap.field)) {
+ if (0 != fh->cap.ops->buf_prepare(&fh->cap,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.ops->buf_queue(&fh->cap,fh->cap.read_buf);
fh->cap.read_off = 0;
}
up(&fh->cap.lock);
/* 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);
}
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;
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;
#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:
}
}
-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:
{
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
(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:
}
}
-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;
unsigned int cmd, void *arg)
{
int err;
-
+
switch (cmd) {
case VIDIOC_QUERYCTRL:
{
case VIDIOC_S_INPUT:
{
int *i = arg;
-
+
if (*i < 0 || *i >= SAA7134_INPUT_MAX)
return -EINVAL;
if (NULL == card_in(dev,*i).name)
}
return 0;
}
+EXPORT_SYMBOL(saa7134_common_ioctl);
/*
* This function is _not_ called directly, but from
if (video_debug > 1)
saa7134_print_ioctl(dev->name,cmd);
-#ifdef VIDIOC_G_PRIORITY
switch (cmd) {
case VIDIOC_S_CTRL:
case VIDIOC_S_STD:
if (0 != err)
return err;
}
-#endif
switch (cmd) {
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = arg;
-
+
memset(cap,0,sizeof(*cap));
strcpy(cap->driver, "saa7134");
strlcpy(cap->card, saa7134_boards[dev->board].name,
V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_TUNER |
- V4L2_CAP_READWRITE |
+ V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
return 0;
}
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);
up(&dev->lock);
return 0;
}
-
+
/* --- control ioctls ---------------------------------------- */
case VIDIOC_ENUMINPUT:
case VIDIOC_G_INPUT:
return 0;
}
-#ifdef VIDIOC_G_PRIORITY
case VIDIOC_G_PRIORITY:
{
enum v4l2_priority *p = arg;
return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
}
-#endif
/* --- preview ioctls ---------------------------------------- */
case VIDIOC_ENUM_FMT:
strcpy(f->description,"vbi data");
break;
default:
- return -EINVAL;
+ return -EINVAL;
}
return 0;
}
{
struct v4l2_framebuffer *fb = arg;
struct saa7134_format *fmt;
-
+
if(!capable(CAP_SYS_ADMIN) &&
!capable(CAP_SYS_RAWIO))
return -EPERM;
struct v4l2_format *f = arg;
return saa7134_try_fmt(dev,fh,f);
}
-
+
case VIDIOCGMBUF:
{
struct video_mbuf *mbuf = arg;
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));
return 0;
}
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:
{
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);
{
struct saa7134_fh *fh = file->private_data;
struct saa7134_dev *dev = fh->dev;
-
+
if (video_debug > 1)
saa7134_print_ioctl(dev->name,cmd);
switch (cmd) {
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *i = arg;
-
+
if (i->index != 0)
return -EINVAL;
strcpy(i->name,"Radio");
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);
saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
}
-
+
return 0;
}
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);
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++;