#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <asm/div64.h>
#include "cx23885.h"
#include "cx23885-video.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include "cx23885-ioctl.h"
#include "tuner-xc2028.h"
#include <media/cx25840.h>
MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------------ */
static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
module_param_array(video_nr, int, NULL, 0444);
module_param_array(vbi_nr, int, NULL, 0444);
module_param_array(radio_nr, int, NULL, 0444);
MODULE_PARM_DESC(video_nr, "video device numbers");
MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
MODULE_PARM_DESC(radio_nr, "radio device numbers");
static unsigned int video_debug;
module_param(video_debug, int, 0644);
MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
static unsigned int irq_debug;
module_param(irq_debug, int, 0644);
MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
static unsigned int vid_limit = 16;
module_param(vid_limit, int, 0644);
MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
#define dprintk(level, fmt, arg...)\
do { if (video_debug >= level)\
printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\
} while (0)
/* ------------------------------------------------------------------- */
/* static data */
#define FORMAT_FLAGS_PACKED 0x01
#if 0
static struct cx23885_fmt formats[] = {
{
.name = "8 bpp, gray",
.fourcc = V4L2_PIX_FMT_GREY,
.depth = 8,
.flags = FORMAT_FLAGS_PACKED,
}, {
.name = "15 bpp RGB, le",
.fourcc = V4L2_PIX_FMT_RGB555,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
}, {
.name = "15 bpp RGB, be",
.fourcc = V4L2_PIX_FMT_RGB555X,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
}, {
.name = "16 bpp RGB, le",
.fourcc = V4L2_PIX_FMT_RGB565,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
}, {
.name = "16 bpp RGB, be",
.fourcc = V4L2_PIX_FMT_RGB565X,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
}, {
.name = "24 bpp RGB, le",
.fourcc = V4L2_PIX_FMT_BGR24,
.depth = 24,
.flags = FORMAT_FLAGS_PACKED,
}, {
.name = "32 bpp RGB, le",
.fourcc = V4L2_PIX_FMT_BGR32,
.depth = 32,
.flags = FORMAT_FLAGS_PACKED,
}, {
.name = "32 bpp RGB, be",
.fourcc = V4L2_PIX_FMT_RGB32,
.depth = 32,
.flags = FORMAT_FLAGS_PACKED,
}, {
.name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
}, {
.name = "4:2:2, packed, UYVY",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
},
};
#else
static struct cx23885_fmt formats[] = {
{
#if 0
.name = "4:2:2, packed, UYVY",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
}, {
#endif
.name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
}
};
#endif
static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(formats); i++)
if (formats[i].fourcc == fourcc)
return formats+i;
printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__,
(fourcc & 0xff),
((fourcc >> 8) & 0xff),
((fourcc >> 16) & 0xff),
((fourcc >> 24) & 0xff)
);
return NULL;
}
/* ------------------------------------------------------------------- */
static const struct v4l2_queryctrl no_ctl = {
.name = "42",
.flags = V4L2_CTRL_FLAG_DISABLED,
};
static struct cx23885_ctrl cx23885_ctls[] = {
/* --- video --- */
{
.v = {
.id = V4L2_CID_BRIGHTNESS,
.name = "Brightness",
.minimum = 0x00,
.maximum = 0xff,
.step = 1,
.default_value = 0x7f,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.off = 128,
.reg = LUMA_CTRL,
.mask = 0x00ff,
.shift = 0,
}, {
.v = {
.id = V4L2_CID_CONTRAST,
.name = "Contrast",
.minimum = 0,
.maximum = 0x7f,
.step = 1,
.default_value = 0x3f,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.off = 0,
.reg = LUMA_CTRL,
.mask = 0xff00,
.shift = 8,
}, {
.v = {
.id = V4L2_CID_HUE,
.name = "Hue",
.minimum = -127,
.maximum = 128,
.step = 1,
.default_value = 0x0,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.off = 128,
.reg = CHROMA_CTRL,
.mask = 0xff0000,
.shift = 16,
}, {
/* strictly, this only describes only U saturation.
* V saturation is handled specially through code.
*/
.v = {
.id = V4L2_CID_SATURATION,
.name = "Saturation",
.minimum = 0,
.maximum = 0x7f,
.step = 1,
.default_value = 0x3f,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.off = 0,
.reg = CHROMA_CTRL,
.mask = 0x00ff,
.shift = 0,
}, {
/* --- audio --- */
.v = {
.id = V4L2_CID_AUDIO_MUTE,
.name = "Mute",
.minimum = 0,
.maximum = 1,
.default_value = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
},
.reg = PATH1_CTL1,
.mask = (0x1f << 24),
.shift = 24,
}, {
.v = {
.id = V4L2_CID_AUDIO_VOLUME,
.name = "Volume",
.minimum = 0,
.maximum = 65535,
.step = 65535 / 100,
.default_value = 65535,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.reg = PATH1_VOL_CTL,
.mask = 0xff,
.shift = 0,
}
};
static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
/* Must be sorted from low to high control ID! */
static const u32 cx23885_user_ctrls[] = {
V4L2_CID_USER_CLASS,
V4L2_CID_BRIGHTNESS,
V4L2_CID_CONTRAST,
V4L2_CID_SATURATION,
V4L2_CID_HUE,
V4L2_CID_AUDIO_VOLUME,
V4L2_CID_AUDIO_MUTE,
0
};
static const u32 *ctrl_classes[] = {
cx23885_user_ctrls,
NULL
};
void cx23885_video_wakeup(struct cx23885_dev *dev,
struct cx23885_dmaqueue *q, u32 count)
{
struct cx23885_buffer *buf;
int bc;
for (bc = 0;; bc++) {
if (list_empty(&q->active))
break;
buf = list_entry(q->active.next,
struct cx23885_buffer, vb.queue);
/* count comes from the hw and is is 16bit wide --
* this trick handles wrap-arounds correctly for
* up to 32767 buffers in flight... */
if ((s16) (count - buf->count) < 0)
break;
v4l2_get_timestamp(&buf->vb.ts);
dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
count, buf->count);
buf->vb.state = VIDEOBUF_DONE;
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
}
if (list_empty(&q->active))
del_timer(&q->timeout);
else
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
if (bc != 1)
printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
__func__, bc);
}
int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
{
dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
__func__,
(unsigned int)norm,
v4l2_norm_to_name(norm));
dev->tvnorm = norm;
call_all(dev, core, s_std, norm);
return 0;
}
static struct video_de
评论1