mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-22 20:30:58 +02:00
Merge branch 'tbsdtv_linux_media/latest' into tbsdtv_linux_media/gse
This commit is contained in:
@@ -1480,7 +1480,7 @@ static int af9013_probe(struct i2c_client *client)
|
||||
goto err_regmap_exit;
|
||||
}
|
||||
state->muxc->priv = state;
|
||||
ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(state->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_regmap_exit;
|
||||
|
||||
|
@@ -810,10 +810,10 @@ struct dvb_frontend *gx1133_attach(const struct gx1133_config *cfg,
|
||||
goto err1;
|
||||
}
|
||||
priv->muxc->priv = priv;
|
||||
ret = i2c_mux_add_adapter(priv->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(priv->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err1;
|
||||
ret = i2c_mux_add_adapter(priv->muxc, 0, 1, 0);
|
||||
ret = i2c_mux_add_adapter(priv->muxc, 0, 1);
|
||||
if (ret)
|
||||
goto err1;
|
||||
priv->i2c_demod = priv->muxc->adapter[0];
|
||||
|
@@ -516,7 +516,7 @@ static int gx1503_probe(struct i2c_client *client)
|
||||
goto err_regmap_exit;
|
||||
}
|
||||
dev->muxc->priv = client;
|
||||
ret = i2c_mux_add_adapter(dev->muxc,0,0,0);
|
||||
ret = i2c_mux_add_adapter(dev->muxc,0,0);
|
||||
if(ret)
|
||||
goto err_regmap_exit;
|
||||
|
||||
|
@@ -2203,7 +2203,7 @@ static int lgdt3306a_probe(struct i2c_client *client)
|
||||
goto err_kfree;
|
||||
}
|
||||
state->muxc->priv = client;
|
||||
ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(state->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_kfree;
|
||||
|
||||
|
@@ -1866,7 +1866,7 @@ static int m88ds3103_probe(struct i2c_client *client)
|
||||
goto err_kfree;
|
||||
}
|
||||
dev->muxc->priv = dev;
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_kfree;
|
||||
|
||||
|
@@ -838,7 +838,7 @@ static int rtl2830_probe(struct i2c_client *client)
|
||||
goto err_regmap_exit;
|
||||
}
|
||||
dev->muxc->priv = client;
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_regmap_exit;
|
||||
|
||||
|
@@ -1082,7 +1082,7 @@ static int rtl2832_probe(struct i2c_client *client)
|
||||
goto err_regmap_exit;
|
||||
}
|
||||
dev->muxc->priv = dev;
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_regmap_exit;
|
||||
|
||||
|
@@ -911,7 +911,7 @@ static int si2168_probe(struct i2c_client *client)
|
||||
goto err_kfree;
|
||||
}
|
||||
dev->muxc->priv = client;
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(dev->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_kfree;
|
||||
|
||||
|
@@ -1734,7 +1734,7 @@ static int si2183_probe(struct i2c_client *client)
|
||||
goto err_base_kfree;
|
||||
}
|
||||
base->muxc->priv = client;
|
||||
ret = i2c_mux_add_adapter(base->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(base->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err_base_kfree;
|
||||
base->tuner_adapter = base->muxc->adapter[0];
|
||||
|
@@ -624,10 +624,10 @@ struct dvb_frontend *tas2101_attach(const struct tas2101_config *cfg,
|
||||
goto err1;
|
||||
}
|
||||
priv->muxc->priv = priv;
|
||||
ret = i2c_mux_add_adapter(priv->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(priv->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err1;
|
||||
ret = i2c_mux_add_adapter(priv->muxc, 0, 1, 0);
|
||||
ret = i2c_mux_add_adapter(priv->muxc, 0, 1);
|
||||
if (ret)
|
||||
goto err1;
|
||||
priv->i2c_demod = priv->muxc->adapter[0];
|
||||
|
@@ -294,10 +294,10 @@ struct dvb_frontend *tas2971_attach(const struct tas2101_config *cfg,
|
||||
goto err1;
|
||||
}
|
||||
base->muxc->priv = priv;
|
||||
ret = i2c_mux_add_adapter(base->muxc, 0, 0, 0);
|
||||
ret = i2c_mux_add_adapter(base->muxc, 0, 0);
|
||||
if (ret)
|
||||
goto err1;
|
||||
ret = i2c_mux_add_adapter(base->muxc, 0, 1, 0);
|
||||
ret = i2c_mux_add_adapter(base->muxc, 0, 1);
|
||||
if (ret)
|
||||
goto err1;
|
||||
base->i2c_demod = base->muxc->adapter[0];
|
||||
|
@@ -382,7 +382,7 @@ static int max9286_i2c_mux_init(struct max9286_priv *priv)
|
||||
for_each_source(priv, source) {
|
||||
unsigned int index = to_index(priv, source);
|
||||
|
||||
ret = i2c_mux_add_adapter(priv->mux, 0, index, 0);
|
||||
ret = i2c_mux_add_adapter(priv->mux, 0, index);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ config VIDEO_BT848
|
||||
tristate "BT848 Video For Linux"
|
||||
depends on PCI && I2C && VIDEO_DEV
|
||||
select I2C_ALGOBIT
|
||||
select VIDEOBUF_DMA_SG
|
||||
select VIDEOBUF2_DMA_SG
|
||||
depends on RC_CORE
|
||||
depends on MEDIA_RADIO_SUPPORT
|
||||
select VIDEO_TUNER
|
||||
|
@@ -231,7 +231,15 @@
|
||||
|
||||
#define BT848_INT_ETBF (1<<23)
|
||||
|
||||
#define BT848_RISC_VIDEO 1
|
||||
#define BT848_RISC_TOP 2
|
||||
#define BT848_RISC_VBI 4
|
||||
|
||||
#define BT848_INT_RISCS (0xf<<28)
|
||||
#define BT848_INT_RISCS_VIDEO (BT848_RISC_VIDEO << 28)
|
||||
#define BT848_INT_RISCS_TOP (BT848_RISC_TOP << 28)
|
||||
#define BT848_INT_RISCS_VBI (BT848_RISC_VBI << 28)
|
||||
|
||||
#define BT848_INT_RISC_EN (1<<27)
|
||||
#define BT848_INT_RACK (1<<25)
|
||||
#define BT848_INT_FIELD (1<<24)
|
||||
|
@@ -563,4 +563,5 @@ static void __exit bt878_cleanup_module(void)
|
||||
module_init(bt878_init_module);
|
||||
module_exit(bt878_cleanup_module);
|
||||
|
||||
MODULE_DESCRIPTION("DVB/ATSC Support for bt878 based TV cards");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -293,16 +293,8 @@ void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
if (!set) {
|
||||
/* Not much to do here */
|
||||
t->audmode = V4L2_TUNER_MODE_LANG1;
|
||||
t->rxsubchans = V4L2_TUNER_SUB_MONO |
|
||||
V4L2_TUNER_SUB_STEREO |
|
||||
V4L2_TUNER_SUB_LANG1 |
|
||||
V4L2_TUNER_SUB_LANG2;
|
||||
|
||||
if (!set)
|
||||
return;
|
||||
}
|
||||
|
||||
/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
|
||||
switch (t->audmode) {
|
||||
|
@@ -126,6 +126,7 @@ MODULE_PARM_DESC(audiodev, "specify audio device:\n"
|
||||
"\t\t 3 = tvaudio");
|
||||
MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition.");
|
||||
|
||||
MODULE_FIRMWARE("hcwamc.rbf");
|
||||
|
||||
/* I2C addresses list */
|
||||
#define I2C_ADDR_TDA7432 0x8a
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@ static void bttv_sub_remove(struct device *dev)
|
||||
sub->remove(sdev);
|
||||
}
|
||||
|
||||
struct bus_type bttv_sub_bus_type = {
|
||||
const struct bus_type bttv_sub_bus_type = {
|
||||
.name = "bttv-sub",
|
||||
.match = &bttv_sub_bus_match,
|
||||
.probe = bttv_sub_probe,
|
||||
|
@@ -67,8 +67,8 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
/* scan lines */
|
||||
sg = sglist;
|
||||
for (line = 0; line < store_lines; line++) {
|
||||
if ((btv->opt_vcr_hack) &&
|
||||
(line >= (store_lines - VCR_HACK_LINES)))
|
||||
if ((line >= (store_lines - VCR_HACK_LINES)) &&
|
||||
btv->opt_vcr_hack)
|
||||
continue;
|
||||
while (offset && offset >= sg_dma_len(sg)) {
|
||||
offset -= sg_dma_len(sg);
|
||||
@@ -106,7 +106,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
|
||||
/* save pointer to jmp instruction address */
|
||||
risc->jmp = rp;
|
||||
BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
|
||||
WARN_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
|
||||
/* save pointer to jmp instruction address */
|
||||
risc->jmp = rp;
|
||||
BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
|
||||
WARN_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -360,21 +360,75 @@ bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
|
||||
/* ---------------------------------------------------------- */
|
||||
/* risc group / risc main loop / dma management */
|
||||
|
||||
void
|
||||
bttv_set_dma(struct bttv *btv, int override)
|
||||
static void bttv_set_risc_status(struct bttv *btv)
|
||||
{
|
||||
unsigned long cmd;
|
||||
int capctl;
|
||||
unsigned long cmd = BT848_RISC_JUMP;
|
||||
if (btv->loop_irq) {
|
||||
cmd |= BT848_RISC_IRQ;
|
||||
cmd |= (btv->loop_irq & 0x0f) << 16;
|
||||
cmd |= (~btv->loop_irq & 0x0f) << 20;
|
||||
}
|
||||
btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
|
||||
}
|
||||
|
||||
btv->cap_ctl = 0;
|
||||
if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
|
||||
if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
|
||||
if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c;
|
||||
static void bttv_set_irq_timer(struct bttv *btv)
|
||||
{
|
||||
if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi)
|
||||
mod_timer(&btv->timeout, jiffies + BTTV_TIMEOUT);
|
||||
else
|
||||
del_timer(&btv->timeout);
|
||||
}
|
||||
|
||||
capctl = 0;
|
||||
capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
|
||||
capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */
|
||||
capctl |= override;
|
||||
static int bttv_set_capture_control(struct bttv *btv, int start_capture)
|
||||
{
|
||||
int capctl = 0;
|
||||
|
||||
if (btv->curr.top || btv->curr.bottom)
|
||||
capctl = BT848_CAP_CTL_CAPTURE_ODD |
|
||||
BT848_CAP_CTL_CAPTURE_EVEN;
|
||||
|
||||
if (btv->cvbi)
|
||||
capctl |= BT848_CAP_CTL_CAPTURE_VBI_ODD |
|
||||
BT848_CAP_CTL_CAPTURE_VBI_EVEN;
|
||||
|
||||
capctl |= start_capture;
|
||||
|
||||
btaor(capctl, ~0x0f, BT848_CAP_CTL);
|
||||
|
||||
return capctl;
|
||||
}
|
||||
|
||||
static void bttv_start_dma(struct bttv *btv)
|
||||
{
|
||||
if (btv->dma_on)
|
||||
return;
|
||||
btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
|
||||
btor(BT848_GPIO_DMA_CTL_RISC_ENABLE | BT848_GPIO_DMA_CTL_FIFO_ENABLE,
|
||||
BT848_GPIO_DMA_CTL);
|
||||
btv->dma_on = 1;
|
||||
}
|
||||
|
||||
static void bttv_stop_dma(struct bttv *btv)
|
||||
{
|
||||
if (!btv->dma_on)
|
||||
return;
|
||||
btand(~(BT848_GPIO_DMA_CTL_RISC_ENABLE |
|
||||
BT848_GPIO_DMA_CTL_FIFO_ENABLE), BT848_GPIO_DMA_CTL);
|
||||
btv->dma_on = 0;
|
||||
}
|
||||
|
||||
void bttv_set_dma(struct bttv *btv, int start_capture)
|
||||
{
|
||||
int capctl = 0;
|
||||
|
||||
bttv_set_risc_status(btv);
|
||||
bttv_set_irq_timer(btv);
|
||||
capctl = bttv_set_capture_control(btv, start_capture);
|
||||
|
||||
if (capctl)
|
||||
bttv_start_dma(btv);
|
||||
else
|
||||
bttv_stop_dma(btv);
|
||||
|
||||
d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n",
|
||||
btv->c.nr,capctl,btv->loop_irq,
|
||||
@@ -382,34 +436,6 @@ bttv_set_dma(struct bttv *btv, int override)
|
||||
btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
|
||||
btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,
|
||||
btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
|
||||
|
||||
cmd = BT848_RISC_JUMP;
|
||||
if (btv->loop_irq) {
|
||||
cmd |= BT848_RISC_IRQ;
|
||||
cmd |= (btv->loop_irq & 0x0f) << 16;
|
||||
cmd |= (~btv->loop_irq & 0x0f) << 20;
|
||||
}
|
||||
if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
|
||||
mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
|
||||
} else {
|
||||
del_timer(&btv->timeout);
|
||||
}
|
||||
btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
|
||||
|
||||
btaor(capctl, ~0x0f, BT848_CAP_CTL);
|
||||
if (capctl) {
|
||||
if (btv->dma_on)
|
||||
return;
|
||||
btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
|
||||
btor(3, BT848_GPIO_DMA_CTL);
|
||||
btv->dma_on = 1;
|
||||
} else {
|
||||
if (!btv->dma_on)
|
||||
return;
|
||||
btand(~3, BT848_GPIO_DMA_CTL);
|
||||
btv->dma_on = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -478,17 +504,50 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
|
||||
int bttv_buffer_risc_vbi(struct bttv *btv, struct bttv_buffer *buf)
|
||||
{
|
||||
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
||||
int r = 0;
|
||||
unsigned int offset;
|
||||
unsigned int bpl = 2044; /* max. vbipack */
|
||||
unsigned int padding = VBI_BPL - bpl;
|
||||
unsigned int skip_lines0 = 0;
|
||||
unsigned int skip_lines1 = 0;
|
||||
unsigned int min_vdelay = MIN_VDELAY;
|
||||
|
||||
videobuf_waiton(q, &buf->vb, 0, 0);
|
||||
videobuf_dma_unmap(q->dev, dma);
|
||||
videobuf_dma_free(dma);
|
||||
btcx_riscmem_free(btv->c.pci,&buf->bottom);
|
||||
btcx_riscmem_free(btv->c.pci,&buf->top);
|
||||
buf->vb.state = VIDEOBUF_NEEDS_INIT;
|
||||
const struct bttv_tvnorm *tvnorm = btv->vbi_fmt.tvnorm;
|
||||
struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
|
||||
struct scatterlist *list = sgt->sgl;
|
||||
|
||||
if (btv->vbi_fmt.fmt.count[0] > 0)
|
||||
skip_lines0 = max(0, (btv->vbi_fmt.fmt.start[0] -
|
||||
tvnorm->vbistart[0]));
|
||||
if (btv->vbi_fmt.fmt.count[1] > 0)
|
||||
skip_lines1 = max(0, (btv->vbi_fmt.fmt.start[1] -
|
||||
tvnorm->vbistart[1]));
|
||||
|
||||
if (btv->vbi_fmt.fmt.count[0] > 0) {
|
||||
r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, padding,
|
||||
skip_lines0, btv->vbi_fmt.fmt.count[0]);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (btv->vbi_fmt.fmt.count[1] > 0) {
|
||||
offset = btv->vbi_fmt.fmt.count[0] * VBI_BPL;
|
||||
r = bttv_risc_packed(btv, &buf->bottom, list, offset, bpl,
|
||||
padding, skip_lines1,
|
||||
btv->vbi_fmt.fmt.count[1]);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (btv->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
|
||||
min_vdelay += btv->vbi_fmt.end - tvnorm->cropcap.bounds.top;
|
||||
|
||||
/* For bttv_buffer_activate_vbi(). */
|
||||
buf->geo.vdelay = min_vdelay;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -508,8 +567,7 @@ bttv_buffer_activate_vbi(struct bttv *btv,
|
||||
if (vbi) {
|
||||
unsigned int crop, vdelay;
|
||||
|
||||
vbi->vb.state = VIDEOBUF_ACTIVE;
|
||||
list_del(&vbi->vb.queue);
|
||||
list_del(&vbi->list);
|
||||
|
||||
/* VDELAY is start of video, end of VBI capturing. */
|
||||
crop = btread(BT848_E_CROP);
|
||||
@@ -525,12 +583,12 @@ bttv_buffer_activate_vbi(struct bttv *btv,
|
||||
btwrite(crop, BT848_O_CROP);
|
||||
}
|
||||
|
||||
if (vbi->vbi_count[0] > 0) {
|
||||
if (btv->vbi_count[0] > 0) {
|
||||
top = &vbi->top;
|
||||
top_irq_flags = 4;
|
||||
}
|
||||
|
||||
if (vbi->vbi_count[1] > 0) {
|
||||
if (btv->vbi_count[1] > 0) {
|
||||
top_irq_flags = 0;
|
||||
bottom = &vbi->bottom;
|
||||
bottom_irq_flags = 4;
|
||||
@@ -550,16 +608,13 @@ bttv_buffer_activate_video(struct bttv *btv,
|
||||
/* video capture */
|
||||
if (NULL != set->top && NULL != set->bottom) {
|
||||
if (set->top == set->bottom) {
|
||||
set->top->vb.state = VIDEOBUF_ACTIVE;
|
||||
if (set->top->vb.queue.next)
|
||||
list_del(&set->top->vb.queue);
|
||||
if (set->top->list.next)
|
||||
list_del(&set->top->list);
|
||||
} else {
|
||||
set->top->vb.state = VIDEOBUF_ACTIVE;
|
||||
set->bottom->vb.state = VIDEOBUF_ACTIVE;
|
||||
if (set->top->vb.queue.next)
|
||||
list_del(&set->top->vb.queue);
|
||||
if (set->bottom->vb.queue.next)
|
||||
list_del(&set->bottom->vb.queue);
|
||||
if (set->top->list.next)
|
||||
list_del(&set->top->list);
|
||||
if (set->bottom->list.next)
|
||||
list_del(&set->bottom->list);
|
||||
}
|
||||
bttv_apply_geo(btv, &set->top->geo, 1);
|
||||
bttv_apply_geo(btv, &set->bottom->geo,0);
|
||||
@@ -572,9 +627,8 @@ bttv_buffer_activate_video(struct bttv *btv,
|
||||
btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
|
||||
~0x0f, BT848_COLOR_CTL);
|
||||
} else if (NULL != set->top) {
|
||||
set->top->vb.state = VIDEOBUF_ACTIVE;
|
||||
if (set->top->vb.queue.next)
|
||||
list_del(&set->top->vb.queue);
|
||||
if (set->top->list.next)
|
||||
list_del(&set->top->list);
|
||||
bttv_apply_geo(btv, &set->top->geo,1);
|
||||
bttv_apply_geo(btv, &set->top->geo,0);
|
||||
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
|
||||
@@ -583,9 +637,8 @@ bttv_buffer_activate_video(struct bttv *btv,
|
||||
btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
|
||||
btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
|
||||
} else if (NULL != set->bottom) {
|
||||
set->bottom->vb.state = VIDEOBUF_ACTIVE;
|
||||
if (set->bottom->vb.queue.next)
|
||||
list_del(&set->bottom->vb.queue);
|
||||
if (set->bottom->list.next)
|
||||
list_del(&set->bottom->list);
|
||||
bttv_apply_geo(btv, &set->bottom->geo,1);
|
||||
bttv_apply_geo(btv, &set->bottom->geo,0);
|
||||
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
|
||||
@@ -606,156 +659,146 @@ bttv_buffer_activate_video(struct bttv *btv,
|
||||
int
|
||||
bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
|
||||
{
|
||||
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
|
||||
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
||||
|
||||
dprintk("%d: buffer field: %s format: 0x%08x size: %dx%d\n",
|
||||
btv->c.nr, v4l2_field_names[buf->vb.field],
|
||||
buf->fmt->fourcc, buf->vb.width, buf->vb.height);
|
||||
int r = 0;
|
||||
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + btv->tvnorm;
|
||||
struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
|
||||
struct scatterlist *list = sgt->sgl;
|
||||
unsigned long size = (btv->fmt->depth * btv->width * btv->height) >> 3;
|
||||
|
||||
/* packed pixel modes */
|
||||
if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
|
||||
int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
|
||||
int bpf = bpl * (buf->vb.height >> 1);
|
||||
if (btv->fmt->flags & FORMAT_FLAGS_PACKED) {
|
||||
int bpl = (btv->fmt->depth >> 3) * btv->width;
|
||||
int bpf = bpl * (btv->height >> 1);
|
||||
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
|
||||
V4L2_FIELD_HAS_BOTH(buf->vb.field),
|
||||
tvnorm,&buf->crop);
|
||||
|
||||
switch (buf->vb.field) {
|
||||
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||
V4L2_FIELD_HAS_BOTH(buf->vbuf.field), tvnorm,
|
||||
&btv->crop[!!btv->do_crop].rect);
|
||||
switch (buf->vbuf.field) {
|
||||
case V4L2_FIELD_TOP:
|
||||
bttv_risc_packed(btv,&buf->top,dma->sglist,
|
||||
/* offset */ 0,bpl,
|
||||
/* padding */ 0,/* skip_lines */ 0,
|
||||
buf->vb.height);
|
||||
r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
|
||||
0, btv->height);
|
||||
break;
|
||||
case V4L2_FIELD_BOTTOM:
|
||||
bttv_risc_packed(btv,&buf->bottom,dma->sglist,
|
||||
0,bpl,0,0,buf->vb.height);
|
||||
r = bttv_risc_packed(btv, &buf->bottom, list, 0, bpl,
|
||||
0, 0, btv->height);
|
||||
break;
|
||||
case V4L2_FIELD_INTERLACED:
|
||||
bttv_risc_packed(btv,&buf->top,dma->sglist,
|
||||
0,bpl,bpl,0,buf->vb.height >> 1);
|
||||
bttv_risc_packed(btv,&buf->bottom,dma->sglist,
|
||||
bpl,bpl,bpl,0,buf->vb.height >> 1);
|
||||
r = bttv_risc_packed(btv, &buf->top, list, 0, bpl,
|
||||
bpl, 0, btv->height >> 1);
|
||||
r = bttv_risc_packed(btv, &buf->bottom, list, bpl,
|
||||
bpl, bpl, 0, btv->height >> 1);
|
||||
break;
|
||||
case V4L2_FIELD_SEQ_TB:
|
||||
bttv_risc_packed(btv,&buf->top,dma->sglist,
|
||||
0,bpl,0,0,buf->vb.height >> 1);
|
||||
bttv_risc_packed(btv,&buf->bottom,dma->sglist,
|
||||
bpf,bpl,0,0,buf->vb.height >> 1);
|
||||
r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
|
||||
0, btv->height >> 1);
|
||||
r = bttv_risc_packed(btv, &buf->bottom, list, bpf,
|
||||
bpl, 0, 0, btv->height >> 1);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* planar modes */
|
||||
if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
|
||||
if (btv->fmt->flags & FORMAT_FLAGS_PLANAR) {
|
||||
int uoffset, voffset;
|
||||
int ypadding, cpadding, lines;
|
||||
|
||||
/* calculate chroma offsets */
|
||||
uoffset = buf->vb.width * buf->vb.height;
|
||||
voffset = buf->vb.width * buf->vb.height;
|
||||
if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
|
||||
uoffset = btv->width * btv->height;
|
||||
voffset = btv->width * btv->height;
|
||||
if (btv->fmt->flags & FORMAT_FLAGS_CrCb) {
|
||||
/* Y-Cr-Cb plane order */
|
||||
uoffset >>= buf->fmt->hshift;
|
||||
uoffset >>= buf->fmt->vshift;
|
||||
uoffset >>= btv->fmt->hshift;
|
||||
uoffset >>= btv->fmt->vshift;
|
||||
uoffset += voffset;
|
||||
} else {
|
||||
/* Y-Cb-Cr plane order */
|
||||
voffset >>= buf->fmt->hshift;
|
||||
voffset >>= buf->fmt->vshift;
|
||||
voffset >>= btv->fmt->hshift;
|
||||
voffset >>= btv->fmt->vshift;
|
||||
voffset += uoffset;
|
||||
}
|
||||
|
||||
switch (buf->vb.field) {
|
||||
switch (buf->vbuf.field) {
|
||||
case V4L2_FIELD_TOP:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,/* both_fields */ 0,
|
||||
tvnorm,&buf->crop);
|
||||
bttv_risc_planar(btv, &buf->top, dma->sglist,
|
||||
0,buf->vb.width,0,buf->vb.height,
|
||||
uoffset,voffset,buf->fmt->hshift,
|
||||
buf->fmt->vshift,0);
|
||||
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||
0, tvnorm,
|
||||
&btv->crop[!!btv->do_crop].rect);
|
||||
r = bttv_risc_planar(btv, &buf->top, list, 0,
|
||||
btv->width, 0, btv->height,
|
||||
uoffset, voffset,
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, 0);
|
||||
break;
|
||||
case V4L2_FIELD_BOTTOM:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,0,
|
||||
tvnorm,&buf->crop);
|
||||
bttv_risc_planar(btv, &buf->bottom, dma->sglist,
|
||||
0,buf->vb.width,0,buf->vb.height,
|
||||
uoffset,voffset,buf->fmt->hshift,
|
||||
buf->fmt->vshift,0);
|
||||
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||
0, tvnorm,
|
||||
&btv->crop[!!btv->do_crop].rect);
|
||||
r = bttv_risc_planar(btv, &buf->bottom, list, 0,
|
||||
btv->width, 0, btv->height,
|
||||
uoffset, voffset,
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, 0);
|
||||
break;
|
||||
case V4L2_FIELD_INTERLACED:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,1,
|
||||
tvnorm,&buf->crop);
|
||||
lines = buf->vb.height >> 1;
|
||||
ypadding = buf->vb.width;
|
||||
cpadding = buf->vb.width >> buf->fmt->hshift;
|
||||
bttv_risc_planar(btv,&buf->top,
|
||||
dma->sglist,
|
||||
0,buf->vb.width,ypadding,lines,
|
||||
uoffset,voffset,
|
||||
buf->fmt->hshift,
|
||||
buf->fmt->vshift,
|
||||
cpadding);
|
||||
bttv_risc_planar(btv,&buf->bottom,
|
||||
dma->sglist,
|
||||
ypadding,buf->vb.width,ypadding,lines,
|
||||
uoffset+cpadding,
|
||||
voffset+cpadding,
|
||||
buf->fmt->hshift,
|
||||
buf->fmt->vshift,
|
||||
cpadding);
|
||||
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||
1, tvnorm,
|
||||
&btv->crop[!!btv->do_crop].rect);
|
||||
lines = btv->height >> 1;
|
||||
ypadding = btv->width;
|
||||
cpadding = btv->width >> btv->fmt->hshift;
|
||||
r = bttv_risc_planar(btv, &buf->top, list, 0,
|
||||
btv->width, ypadding, lines,
|
||||
uoffset, voffset,
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, cpadding);
|
||||
|
||||
r = bttv_risc_planar(btv, &buf->bottom, list,
|
||||
ypadding, btv->width, ypadding,
|
||||
lines, uoffset + cpadding,
|
||||
voffset + cpadding,
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, cpadding);
|
||||
break;
|
||||
case V4L2_FIELD_SEQ_TB:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,1,
|
||||
tvnorm,&buf->crop);
|
||||
lines = buf->vb.height >> 1;
|
||||
ypadding = buf->vb.width;
|
||||
cpadding = buf->vb.width >> buf->fmt->hshift;
|
||||
bttv_risc_planar(btv,&buf->top,
|
||||
dma->sglist,
|
||||
0,buf->vb.width,0,lines,
|
||||
uoffset >> 1,
|
||||
voffset >> 1,
|
||||
buf->fmt->hshift,
|
||||
buf->fmt->vshift,
|
||||
0);
|
||||
bttv_risc_planar(btv,&buf->bottom,
|
||||
dma->sglist,
|
||||
lines * ypadding,buf->vb.width,0,lines,
|
||||
lines * ypadding + (uoffset >> 1),
|
||||
lines * ypadding + (voffset >> 1),
|
||||
buf->fmt->hshift,
|
||||
buf->fmt->vshift,
|
||||
0);
|
||||
bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
|
||||
1, tvnorm,
|
||||
&btv->crop[!!btv->do_crop].rect);
|
||||
lines = btv->height >> 1;
|
||||
ypadding = btv->width;
|
||||
cpadding = btv->width >> btv->fmt->hshift;
|
||||
r = bttv_risc_planar(btv, &buf->top, list, 0,
|
||||
btv->width, 0, lines,
|
||||
uoffset >> 1, voffset >> 1,
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, 0);
|
||||
r = bttv_risc_planar(btv, &buf->bottom, list,
|
||||
lines * ypadding,
|
||||
btv->width, 0, lines,
|
||||
lines * ypadding + (uoffset >> 1),
|
||||
lines * ypadding + (voffset >> 1),
|
||||
btv->fmt->hshift,
|
||||
btv->fmt->vshift, 0);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* raw data */
|
||||
if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
|
||||
if (btv->fmt->flags & FORMAT_FLAGS_RAW) {
|
||||
/* build risc code */
|
||||
buf->vb.field = V4L2_FIELD_SEQ_TB;
|
||||
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
|
||||
1,tvnorm,&buf->crop);
|
||||
bttv_risc_packed(btv, &buf->top, dma->sglist,
|
||||
/* offset */ 0, RAW_BPL, /* padding */ 0,
|
||||
/* skip_lines */ 0, RAW_LINES);
|
||||
bttv_risc_packed(btv, &buf->bottom, dma->sglist,
|
||||
buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
|
||||
buf->vbuf.field = V4L2_FIELD_SEQ_TB;
|
||||
bttv_calc_geo(btv, &buf->geo, tvnorm->swidth, tvnorm->sheight,
|
||||
1, tvnorm, &btv->crop[!!btv->do_crop].rect);
|
||||
r = bttv_risc_packed(btv, &buf->top, list, 0, RAW_BPL, 0, 0,
|
||||
RAW_LINES);
|
||||
r = bttv_risc_packed(btv, &buf->bottom, list, size / 2,
|
||||
RAW_BPL, 0, 0, RAW_LINES);
|
||||
}
|
||||
|
||||
/* copy format info */
|
||||
buf->btformat = buf->fmt->btformat;
|
||||
buf->btswap = buf->fmt->btswap;
|
||||
return 0;
|
||||
buf->btformat = btv->fmt->btformat;
|
||||
buf->btswap = btv->fmt->btswap;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@@ -34,16 +34,6 @@
|
||||
to be about 244. */
|
||||
#define VBI_OFFSET 244
|
||||
|
||||
/* 2048 for compatibility with earlier driver versions. The driver
|
||||
really stores 1024 + tvnorm->vbipack * 4 samples per line in the
|
||||
buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI
|
||||
is 0x1FF DWORDs) and VBI read()s store a frame counter in the last
|
||||
four bytes of the VBI image. */
|
||||
#define VBI_BPL 2048
|
||||
|
||||
/* Compatibility. */
|
||||
#define VBI_DEFLINES 16
|
||||
|
||||
static unsigned int vbibufs = 4;
|
||||
static unsigned int vbi_debug;
|
||||
|
||||
@@ -67,165 +57,121 @@ do { \
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* vbi risc code + mm */
|
||||
|
||||
static int vbi_buffer_setup(struct videobuf_queue *q,
|
||||
unsigned int *count, unsigned int *size)
|
||||
static int queue_setup_vbi(struct vb2_queue *q, unsigned int *num_buffers,
|
||||
unsigned int *num_planes, unsigned int sizes[],
|
||||
struct device *alloc_devs[])
|
||||
{
|
||||
struct bttv_fh *fh = q->priv_data;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv *btv = vb2_get_drv_priv(q);
|
||||
unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);
|
||||
|
||||
if (0 == *count)
|
||||
*count = vbibufs;
|
||||
|
||||
*size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
|
||||
|
||||
dprintk("setup: samples=%u start=%d,%d count=%u,%u\n",
|
||||
fh->vbi_fmt.fmt.samples_per_line,
|
||||
fh->vbi_fmt.fmt.start[0],
|
||||
fh->vbi_fmt.fmt.start[1],
|
||||
fh->vbi_fmt.fmt.count[0],
|
||||
fh->vbi_fmt.fmt.count[1]);
|
||||
if (*num_planes)
|
||||
return sizes[0] < size ? -EINVAL : 0;
|
||||
*num_planes = 1;
|
||||
sizes[0] = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vbi_buffer_prepare(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb,
|
||||
enum v4l2_field field)
|
||||
static void buf_queue_vbi(struct vb2_buffer *vb)
|
||||
{
|
||||
struct bttv_fh *fh = q->priv_data;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
unsigned int skip_lines0, skip_lines1, min_vdelay;
|
||||
int redo_dma_risc;
|
||||
int rc;
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct vb2_queue *vq = vb->vb2_queue;
|
||||
struct bttv *btv = vb2_get_drv_priv(vq);
|
||||
struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
|
||||
unsigned long flags;
|
||||
|
||||
buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
|
||||
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
|
||||
spin_lock_irqsave(&btv->s_lock, flags);
|
||||
if (list_empty(&btv->vcapture)) {
|
||||
btv->loop_irq = BT848_RISC_VBI;
|
||||
if (vb2_is_streaming(&btv->capq))
|
||||
btv->loop_irq |= BT848_RISC_VIDEO;
|
||||
bttv_set_dma(btv, BT848_CAP_CTL_CAPTURE_VBI_ODD |
|
||||
BT848_CAP_CTL_CAPTURE_VBI_EVEN);
|
||||
}
|
||||
list_add_tail(&buf->list, &btv->vcapture);
|
||||
spin_unlock_irqrestore(&btv->s_lock, flags);
|
||||
}
|
||||
|
||||
static int buf_prepare_vbi(struct vb2_buffer *vb)
|
||||
{
|
||||
int ret = 0;
|
||||
struct vb2_queue *vq = vb->vb2_queue;
|
||||
struct bttv *btv = vb2_get_drv_priv(vq);
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
|
||||
unsigned int size = IMAGE_SIZE(&btv->vbi_fmt.fmt);
|
||||
|
||||
if (vb2_plane_size(vb, 0) < size)
|
||||
return -EINVAL;
|
||||
vb2_set_plane_payload(vb, 0, size);
|
||||
buf->vbuf.field = V4L2_FIELD_NONE;
|
||||
ret = bttv_buffer_risc_vbi(btv, buf);
|
||||
|
||||
tvnorm = fh->vbi_fmt.tvnorm;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* There's no VBI_VDELAY register, RISC must skip the lines
|
||||
we don't want. With default parameters we skip zero lines
|
||||
as earlier driver versions did. The driver permits video
|
||||
standard changes while capturing, so we use vbi_fmt.tvnorm
|
||||
instead of btv->tvnorm to skip zero lines after video
|
||||
standard changes as well. */
|
||||
static void buf_cleanup_vbi(struct vb2_buffer *vb)
|
||||
{
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct bttv_buffer *buf = container_of(vbuf, struct bttv_buffer, vbuf);
|
||||
struct vb2_queue *vq = vb->vb2_queue;
|
||||
struct bttv *btv = vb2_get_drv_priv(vq);
|
||||
|
||||
skip_lines0 = 0;
|
||||
skip_lines1 = 0;
|
||||
btcx_riscmem_free(btv->c.pci, &buf->top);
|
||||
btcx_riscmem_free(btv->c.pci, &buf->bottom);
|
||||
}
|
||||
|
||||
if (fh->vbi_fmt.fmt.count[0] > 0)
|
||||
skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0]
|
||||
- tvnorm->vbistart[0]));
|
||||
if (fh->vbi_fmt.fmt.count[1] > 0)
|
||||
skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1]
|
||||
- tvnorm->vbistart[1]));
|
||||
static int start_streaming_vbi(struct vb2_queue *q, unsigned int count)
|
||||
{
|
||||
int seqnr = 0;
|
||||
struct bttv_buffer *buf;
|
||||
struct bttv *btv = vb2_get_drv_priv(q);
|
||||
|
||||
redo_dma_risc = 0;
|
||||
|
||||
if (buf->vbi_skip[0] != skip_lines0 ||
|
||||
buf->vbi_skip[1] != skip_lines1 ||
|
||||
buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] ||
|
||||
buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) {
|
||||
buf->vbi_skip[0] = skip_lines0;
|
||||
buf->vbi_skip[1] = skip_lines1;
|
||||
buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0];
|
||||
buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1];
|
||||
redo_dma_risc = 1;
|
||||
}
|
||||
|
||||
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
|
||||
redo_dma_risc = 1;
|
||||
if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (redo_dma_risc) {
|
||||
unsigned int bpl, padding, offset;
|
||||
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
||||
|
||||
bpl = 2044; /* max. vbipack */
|
||||
padding = VBI_BPL - bpl;
|
||||
|
||||
if (fh->vbi_fmt.fmt.count[0] > 0) {
|
||||
rc = bttv_risc_packed(btv, &buf->top,
|
||||
dma->sglist,
|
||||
/* offset */ 0, bpl,
|
||||
padding, skip_lines0,
|
||||
fh->vbi_fmt.fmt.count[0]);
|
||||
if (0 != rc)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (fh->vbi_fmt.fmt.count[1] > 0) {
|
||||
offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
|
||||
|
||||
rc = bttv_risc_packed(btv, &buf->bottom,
|
||||
dma->sglist,
|
||||
offset, bpl,
|
||||
padding, skip_lines1,
|
||||
fh->vbi_fmt.fmt.count[1]);
|
||||
if (0 != rc)
|
||||
goto fail;
|
||||
btv->framedrop = 0;
|
||||
if (!check_alloc_btres_lock(btv, RESOURCE_VBI)) {
|
||||
if (btv->field_count)
|
||||
seqnr++;
|
||||
while (!list_empty(&btv->vcapture)) {
|
||||
buf = list_entry(btv->vcapture.next,
|
||||
struct bttv_buffer, list);
|
||||
list_del(&buf->list);
|
||||
buf->vbuf.sequence = (btv->field_count >> 1) + seqnr++;
|
||||
vb2_buffer_done(&buf->vbuf.vb2_buf,
|
||||
VB2_BUF_STATE_QUEUED);
|
||||
}
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!vb2_is_streaming(&btv->capq)) {
|
||||
init_irqreg(btv);
|
||||
btv->field_count = 0;
|
||||
}
|
||||
|
||||
/* VBI capturing ends at VDELAY, start of video capturing,
|
||||
no matter where the RISC program ends. VDELAY minimum is 2,
|
||||
bounds.top is the corresponding first field line number
|
||||
times two. VDELAY counts half field lines. */
|
||||
min_vdelay = MIN_VDELAY;
|
||||
if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
|
||||
min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top;
|
||||
|
||||
/* For bttv_buffer_activate_vbi(). */
|
||||
buf->geo.vdelay = min_vdelay;
|
||||
|
||||
buf->vb.state = VIDEOBUF_PREPARED;
|
||||
buf->vb.field = field;
|
||||
dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
|
||||
vb, &buf->top, &buf->bottom,
|
||||
v4l2_field_names[buf->vb.field]);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
bttv_dma_free(q,btv,buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
||||
static void stop_streaming_vbi(struct vb2_queue *q)
|
||||
{
|
||||
struct bttv_fh *fh = q->priv_data;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
|
||||
struct bttv *btv = vb2_get_drv_priv(q);
|
||||
unsigned long flags;
|
||||
|
||||
dprintk("queue %p\n",vb);
|
||||
buf->vb.state = VIDEOBUF_QUEUED;
|
||||
list_add_tail(&buf->vb.queue,&btv->vcapture);
|
||||
if (NULL == btv->cvbi) {
|
||||
fh->btv->loop_irq |= 4;
|
||||
bttv_set_dma(btv,0x0c);
|
||||
vb2_wait_for_all_buffers(q);
|
||||
spin_lock_irqsave(&btv->s_lock, flags);
|
||||
free_btres_lock(btv, RESOURCE_VBI);
|
||||
if (!vb2_is_streaming(&btv->capq)) {
|
||||
/* stop field counter */
|
||||
btand(~BT848_INT_VSYNC, BT848_INT_MASK);
|
||||
}
|
||||
spin_unlock_irqrestore(&btv->s_lock, flags);
|
||||
}
|
||||
|
||||
static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
||||
{
|
||||
struct bttv_fh *fh = q->priv_data;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
|
||||
|
||||
dprintk("free %p\n",vb);
|
||||
bttv_dma_free(q,fh->btv,buf);
|
||||
}
|
||||
|
||||
const struct videobuf_queue_ops bttv_vbi_qops = {
|
||||
.buf_setup = vbi_buffer_setup,
|
||||
.buf_prepare = vbi_buffer_prepare,
|
||||
.buf_queue = vbi_buffer_queue,
|
||||
.buf_release = vbi_buffer_release,
|
||||
const struct vb2_ops bttv_vbi_qops = {
|
||||
.queue_setup = queue_setup_vbi,
|
||||
.buf_queue = buf_queue_vbi,
|
||||
.buf_prepare = buf_prepare_vbi,
|
||||
.buf_cleanup = buf_cleanup_vbi,
|
||||
.start_streaming = start_streaming_vbi,
|
||||
.stop_streaming = stop_streaming_vbi,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
@@ -250,7 +196,7 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
|
||||
if (min_start > max_start)
|
||||
return -EBUSY;
|
||||
|
||||
BUG_ON(max_start >= max_end);
|
||||
WARN_ON(max_start >= max_end);
|
||||
|
||||
f->sampling_rate = tvnorm->Fsc;
|
||||
f->samples_per_line = VBI_BPL;
|
||||
@@ -299,8 +245,7 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
|
||||
|
||||
int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
{
|
||||
struct bttv_fh *fh = f;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv *btv = video_drvdata(file);
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
__s32 crop_start;
|
||||
|
||||
@@ -317,8 +262,7 @@ int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
|
||||
int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
{
|
||||
struct bttv_fh *fh = f;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv *btv = video_drvdata(file);
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
__s32 start1, end;
|
||||
int rc;
|
||||
@@ -326,7 +270,7 @@ int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
mutex_lock(&btv->lock);
|
||||
|
||||
rc = -EBUSY;
|
||||
if (fh->resources & RESOURCE_VBI)
|
||||
if (btv->resources & RESOURCE_VBI)
|
||||
goto fail;
|
||||
|
||||
tvnorm = &bttv_tvnorms[btv->tvnorm];
|
||||
@@ -346,13 +290,9 @@ int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
because vbi_fmt.end counts field lines times two. */
|
||||
end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
|
||||
|
||||
mutex_lock(&fh->vbi.vb_lock);
|
||||
|
||||
fh->vbi_fmt.fmt = frt->fmt.vbi;
|
||||
fh->vbi_fmt.tvnorm = tvnorm;
|
||||
fh->vbi_fmt.end = end;
|
||||
|
||||
mutex_unlock(&fh->vbi.vb_lock);
|
||||
btv->vbi_fmt.fmt = frt->fmt.vbi;
|
||||
btv->vbi_fmt.tvnorm = tvnorm;
|
||||
btv->vbi_fmt.end = end;
|
||||
|
||||
rc = 0;
|
||||
|
||||
@@ -365,14 +305,14 @@ int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
|
||||
int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
{
|
||||
struct bttv_fh *fh = f;
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
struct bttv *btv = video_drvdata(file);
|
||||
|
||||
frt->fmt.vbi = fh->vbi_fmt.fmt;
|
||||
frt->fmt.vbi = btv->vbi_fmt.fmt;
|
||||
|
||||
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
|
||||
tvnorm = &bttv_tvnorms[btv->tvnorm];
|
||||
|
||||
if (tvnorm != fh->vbi_fmt.tvnorm) {
|
||||
if (tvnorm != btv->vbi_fmt.tvnorm) {
|
||||
__s32 max_end;
|
||||
unsigned int i;
|
||||
|
||||
@@ -388,9 +328,8 @@ int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
for (i = 0; i < 2; ++i) {
|
||||
__s32 new_start;
|
||||
|
||||
new_start = frt->fmt.vbi.start[i]
|
||||
+ tvnorm->vbistart[i]
|
||||
- fh->vbi_fmt.tvnorm->vbistart[i];
|
||||
new_start = frt->fmt.vbi.start[i] + tvnorm->vbistart[i]
|
||||
- btv->vbi_fmt.tvnorm->vbistart[i];
|
||||
|
||||
frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
|
||||
frt->fmt.vbi.count[i] =
|
||||
@@ -430,8 +369,8 @@ void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm)
|
||||
real_count = ((tvnorm->cropcap.defrect.top >> 1)
|
||||
- tvnorm->vbistart[0]);
|
||||
|
||||
BUG_ON(real_samples_per_line > VBI_BPL);
|
||||
BUG_ON(real_count > VBI_DEFLINES);
|
||||
WARN_ON(real_samples_per_line > VBI_BPL);
|
||||
WARN_ON(real_count > VBI_DEFLINES);
|
||||
|
||||
f->tvnorm = tvnorm;
|
||||
|
||||
|
@@ -26,7 +26,7 @@
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/videobuf-dma-sg.h>
|
||||
#include <media/videobuf2-dma-sg.h>
|
||||
#include <media/tveeprom.h>
|
||||
#include <media/rc-core.h>
|
||||
#include <media/i2c/ir-kbd-i2c.h>
|
||||
@@ -142,19 +142,15 @@ struct bttv_geometry {
|
||||
|
||||
struct bttv_buffer {
|
||||
/* common v4l buffer stuff -- must be first */
|
||||
struct videobuf_buffer vb;
|
||||
struct vb2_v4l2_buffer vbuf;
|
||||
struct list_head list;
|
||||
|
||||
/* bttv specific */
|
||||
const struct bttv_format *fmt;
|
||||
unsigned int tvnorm;
|
||||
int btformat;
|
||||
int btswap;
|
||||
struct bttv_geometry geo;
|
||||
struct btcx_riscmem top;
|
||||
struct btcx_riscmem bottom;
|
||||
struct v4l2_rect crop;
|
||||
unsigned int vbi_skip[2];
|
||||
unsigned int vbi_count[2];
|
||||
};
|
||||
|
||||
struct bttv_buffer_set {
|
||||
@@ -176,6 +172,8 @@ struct bttv_vbi_fmt {
|
||||
};
|
||||
|
||||
/* bttv-vbi.c */
|
||||
extern const struct vb2_ops bttv_vbi_qops;
|
||||
|
||||
void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm);
|
||||
|
||||
struct bttv_crop {
|
||||
@@ -192,31 +190,6 @@ struct bttv_crop {
|
||||
__s32 max_scaled_height;
|
||||
};
|
||||
|
||||
struct bttv_fh {
|
||||
/* This must be the first field in this struct */
|
||||
struct v4l2_fh fh;
|
||||
|
||||
struct bttv *btv;
|
||||
int resources;
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
/* video capture */
|
||||
struct videobuf_queue cap;
|
||||
const struct bttv_format *fmt;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
/* Application called VIDIOC_S_SELECTION. */
|
||||
int do_crop;
|
||||
|
||||
/* vbi capture */
|
||||
struct videobuf_queue vbi;
|
||||
/* Current VBI capture window as seen through this fh (cannot
|
||||
be global for compatibility with earlier drivers). Protected
|
||||
by struct bttv.lock and struct bttv_fh.vbi.lock. */
|
||||
struct bttv_vbi_fmt vbi_fmt;
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-risc.c */
|
||||
|
||||
@@ -237,24 +210,31 @@ int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
|
||||
int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf);
|
||||
int bttv_buffer_activate_video(struct bttv *btv,
|
||||
struct bttv_buffer_set *set);
|
||||
int bttv_buffer_risc_vbi(struct bttv *btv, struct bttv_buffer *buf);
|
||||
int bttv_buffer_activate_vbi(struct bttv *btv,
|
||||
struct bttv_buffer *vbi);
|
||||
void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv,
|
||||
struct bttv_buffer *buf);
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-vbi.c */
|
||||
|
||||
/*
|
||||
* 2048 for compatibility with earlier driver versions. The driver really
|
||||
* stores 1024 + tvnorm->vbipack * 4 samples per line in the buffer. Note
|
||||
* tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI is 0x1FF DWORDs) and
|
||||
* VBI read()s store a frame counter in the last four bytes of the VBI image.
|
||||
*/
|
||||
#define VBI_BPL 2048
|
||||
|
||||
#define VBI_DEFLINES 16
|
||||
|
||||
int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
||||
int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
||||
int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
||||
|
||||
extern const struct videobuf_queue_ops bttv_vbi_qops;
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-gpio.c */
|
||||
|
||||
extern struct bus_type bttv_sub_bus_type;
|
||||
extern const struct bus_type bttv_sub_bus_type;
|
||||
int bttv_sub_add_device(struct bttv_core *core, char *name);
|
||||
int bttv_sub_del_devices(struct bttv_core *core);
|
||||
|
||||
@@ -275,6 +255,8 @@ extern int fini_bttv_i2c(struct bttv *btv);
|
||||
extern unsigned int bttv_verbose;
|
||||
extern unsigned int bttv_debug;
|
||||
extern unsigned int bttv_gpio;
|
||||
int check_alloc_btres_lock(struct bttv *btv, int bit);
|
||||
void free_btres_lock(struct bttv *btv, int bits);
|
||||
extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
|
||||
|
||||
#define dprintk(fmt, ...) \
|
||||
@@ -396,7 +378,7 @@ struct bttv {
|
||||
v4l2_std_id std;
|
||||
int hue, contrast, bright, saturation;
|
||||
struct v4l2_framebuffer fbuf;
|
||||
unsigned int field_count;
|
||||
__u32 field_count;
|
||||
|
||||
/* various options */
|
||||
int opt_combfilter;
|
||||
@@ -436,7 +418,6 @@ struct bttv {
|
||||
int loop_irq;
|
||||
int new_input;
|
||||
|
||||
unsigned long cap_ctl;
|
||||
unsigned long dma_on;
|
||||
struct timer_list timeout;
|
||||
struct bttv_suspend_state state;
|
||||
@@ -448,7 +429,25 @@ struct bttv {
|
||||
unsigned int irq_me;
|
||||
|
||||
unsigned int users;
|
||||
struct bttv_fh init;
|
||||
struct v4l2_fh fh;
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
enum v4l2_field field;
|
||||
int field_last;
|
||||
|
||||
/* video capture */
|
||||
struct vb2_queue capq;
|
||||
const struct bttv_format *fmt;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
/* vbi capture */
|
||||
struct vb2_queue vbiq;
|
||||
struct bttv_vbi_fmt vbi_fmt;
|
||||
unsigned int vbi_count[2];
|
||||
|
||||
/* Application called VIDIOC_S_SELECTION. */
|
||||
int do_crop;
|
||||
|
||||
/* used to make dvb-bt8xx autoloadable */
|
||||
struct work_struct request_module_wk;
|
||||
@@ -487,6 +486,8 @@ static inline unsigned int bttv_muxsel(const struct bttv *btv,
|
||||
|
||||
#endif
|
||||
|
||||
void init_irqreg(struct bttv *btv);
|
||||
|
||||
#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr))
|
||||
#define btread(adr) readl(btv->bt848_mmio+(adr))
|
||||
|
||||
|
@@ -190,11 +190,15 @@ static int cx24108_tuner_set_params(struct dvb_frontend *fe)
|
||||
u32 freq = c->frequency;
|
||||
int i, a, n, pump;
|
||||
u32 band, pll;
|
||||
u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000,
|
||||
1576000,1718000,1856000,2036000,2150000};
|
||||
u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000,
|
||||
0x00102000,0x00104000,0x00108000,0x00110000,
|
||||
0x00120000,0x00140000};
|
||||
static const u32 osci[] = {
|
||||
950000, 1019000, 1075000, 1178000, 1296000, 1432000,
|
||||
1576000, 1718000, 1856000, 2036000, 2150000
|
||||
};
|
||||
static const u32 bandsel[] = {
|
||||
0, 0x00020000, 0x00040000, 0x00100800, 0x00101000,
|
||||
0x00102000, 0x00104000, 0x00108000, 0x00110000,
|
||||
0x00120000, 0x00140000
|
||||
};
|
||||
|
||||
#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
|
||||
dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq);
|
||||
|
@@ -135,7 +135,7 @@ static void netup_i2c_fifo_tx(struct netup_i2c *i2c)
|
||||
(readw(&i2c->regs->tx_fifo.stat_ctrl) & 0x3f);
|
||||
u32 msg_length = i2c->msg->len - i2c->xmit_size;
|
||||
|
||||
msg_length = (msg_length < fifo_space ? msg_length : fifo_space);
|
||||
msg_length = min(msg_length, fifo_space);
|
||||
while (msg_length--) {
|
||||
data = i2c->msg->buf[i2c->xmit_size++];
|
||||
writeb(data, &i2c->regs->tx_fifo.data8);
|
||||
@@ -289,7 +289,7 @@ static const struct i2c_algorithm netup_i2c_algorithm = {
|
||||
static const struct i2c_adapter netup_i2c_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = NETUP_UNIDVB_NAME,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.algo = &netup_i2c_algorithm,
|
||||
};
|
||||
|
||||
|
@@ -841,6 +841,69 @@ struct tbsecp3_board tbsecp3_boards[] = {
|
||||
.ts_in = 7,
|
||||
.i2c_bus_nr = 0,
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
[TBSECP3_BOARD_TBS6312X] = {
|
||||
.board_id = TBSECP3_BOARD_TBS6312X,
|
||||
.name = "TurboSight TBS 6312X HDMI Capture",
|
||||
.adapters = 12,
|
||||
.i2c_speed = 39,
|
||||
.eeprom_i2c = 1,
|
||||
.eeprom_addr = 0x10,
|
||||
.adap_config = {
|
||||
{
|
||||
.ts_in = 0,
|
||||
.i2c_bus_nr = 0,
|
||||
},
|
||||
{
|
||||
.ts_in = 1,
|
||||
.i2c_bus_nr = 0,
|
||||
},
|
||||
{
|
||||
.ts_in = 2,
|
||||
.i2c_bus_nr = 0,
|
||||
},
|
||||
{
|
||||
.ts_in = 3,
|
||||
.i2c_bus_nr = 0,
|
||||
},
|
||||
{
|
||||
.ts_in = 4,
|
||||
.i2c_bus_nr = 0,
|
||||
},
|
||||
{
|
||||
.ts_in = 5,
|
||||
.i2c_bus_nr = 0,
|
||||
},
|
||||
{
|
||||
.ts_in = 6,
|
||||
.i2c_bus_nr = 0,
|
||||
},
|
||||
{
|
||||
.ts_in = 7,
|
||||
.i2c_bus_nr = 0,
|
||||
|
||||
},
|
||||
{
|
||||
.ts_in = 8,
|
||||
.i2c_bus_nr = 0,
|
||||
|
||||
},
|
||||
{
|
||||
.ts_in = 9,
|
||||
.i2c_bus_nr = 0,
|
||||
|
||||
},
|
||||
{
|
||||
.ts_in = 10,
|
||||
.i2c_bus_nr = 0,
|
||||
|
||||
},
|
||||
{
|
||||
.ts_in = 11,
|
||||
.i2c_bus_nr = 0,
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@@ -366,6 +366,7 @@ static const struct pci_device_id tbsecp3_id_table[] = {
|
||||
TBSECP3_ID(TBSECP3_BOARD_TBS6304,0x6304,0x0001),
|
||||
TBSECP3_ID(TBSECP3_BOARD_TBS6308,0x6308,0x0001),
|
||||
TBSECP3_ID(TBSECP3_BOARD_TBS6308X,0x6308,0x0010),
|
||||
TBSECP3_ID(TBSECP3_BOARD_TBS6312X,0x6312,0x0010),
|
||||
TBSECP3_ID(TBSECP3_BOARD_TBS6909X,0x6909,0x0010),
|
||||
TBSECP3_ID(TBSECP3_BOARD_TBS6909X,0x6909,0x0009),
|
||||
TBSECP3_ID(TBSECP3_BOARD_TBS6909X,0x6909,0x0019),
|
||||
|
@@ -1872,6 +1872,12 @@ static int tbsecp3_frontend_attach(struct tbsecp3_adapter *adapter)
|
||||
if (adapter->fe == NULL)
|
||||
goto frontend_atach_fail;
|
||||
|
||||
break;
|
||||
case TBSECP3_BOARD_TBS6312X:
|
||||
adapter->fe = dvb_attach(tas2971_attach, &tbs6308_demod_cfg, i2c);
|
||||
if (adapter->fe == NULL)
|
||||
goto frontend_atach_fail;
|
||||
|
||||
break;
|
||||
case TBSECP3_BOARD_TBS6304:
|
||||
adapter->fe = dvb_attach(tas2971_attach, &tbs6304_demod_cfg[adapter->nr], i2c);
|
||||
|
@@ -88,7 +88,8 @@
|
||||
#define TBSECP3_BOARD_TBS6504H 44
|
||||
#define TBSECP3_BOARD_TBS6590SE 45
|
||||
#define TBSECP3_BOARD_TBS6308X 46
|
||||
#define TBSECP3_BOARD_TBS6916 47
|
||||
#define TBSECP3_BOARD_TBS6916 47
|
||||
#define TBSECP3_BOARD_TBS6312X 48
|
||||
|
||||
|
||||
#define TBSECP3_MAX_ADAPTERS (16)
|
||||
@@ -221,7 +222,7 @@ struct tbsecp3_dev {
|
||||
bool msi;
|
||||
|
||||
/* dvb adapters */
|
||||
struct tbsecp3_adapter adapter[16];
|
||||
struct tbsecp3_adapter adapter[TBSECP3_MAX_ADAPTERS];
|
||||
|
||||
/* i2c */
|
||||
struct tbsecp3_i2c i2c_bus[TBSECP3_MAX_I2C_BUS];
|
||||
|
@@ -599,10 +599,7 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev)
|
||||
|
||||
int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
|
||||
{
|
||||
return i2c_mux_add_adapter(dev->muxc,
|
||||
0,
|
||||
mux_no /* chan_id */,
|
||||
0 /* class */);
|
||||
return i2c_mux_add_adapter(dev->muxc, 0, mux_no);
|
||||
}
|
||||
|
||||
void cx231xx_i2c_mux_unregister(struct cx231xx *dev)
|
||||
|
@@ -73,19 +73,3 @@ config V4L2_FWNODE
|
||||
|
||||
config V4L2_ASYNC
|
||||
tristate
|
||||
|
||||
# Used by drivers that need Videobuf modules
|
||||
config VIDEOBUF_GEN
|
||||
tristate
|
||||
|
||||
config VIDEOBUF_DMA_SG
|
||||
tristate
|
||||
select VIDEOBUF_GEN
|
||||
|
||||
config VIDEOBUF_VMALLOC
|
||||
tristate
|
||||
select VIDEOBUF_GEN
|
||||
|
||||
config VIDEOBUF_DMA_CONTIG
|
||||
tristate
|
||||
select VIDEOBUF_GEN
|
||||
|
@@ -32,10 +32,5 @@ obj-$(CONFIG_V4L2_JPEG_HELPER) += v4l2-jpeg.o
|
||||
obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
|
||||
obj-$(CONFIG_V4L2_VP9) += v4l2-vp9.o
|
||||
|
||||
obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
|
||||
obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
|
||||
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
|
||||
obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
|
||||
obj-$(CONFIG_VIDEO_DEV) += v4l2-dv-timings.o videodev.o
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,402 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* helper functions for physically contiguous capture buffers
|
||||
*
|
||||
* The functions support hardware lacking scatter gather support
|
||||
* (i.e. the buffers must be linear in physical memory)
|
||||
*
|
||||
* Copyright (c) 2008 Magnus Damm
|
||||
*
|
||||
* Based on videobuf-vmalloc.c,
|
||||
* (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <media/videobuf-dma-contig.h>
|
||||
|
||||
struct videobuf_dma_contig_memory {
|
||||
u32 magic;
|
||||
void *vaddr;
|
||||
dma_addr_t dma_handle;
|
||||
unsigned long size;
|
||||
};
|
||||
|
||||
#define MAGIC_DC_MEM 0x0733ac61
|
||||
#define MAGIC_CHECK(is, should) \
|
||||
if (unlikely((is) != (should))) { \
|
||||
pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
|
||||
BUG(); \
|
||||
}
|
||||
|
||||
static int __videobuf_dc_alloc(struct device *dev,
|
||||
struct videobuf_dma_contig_memory *mem,
|
||||
unsigned long size)
|
||||
{
|
||||
mem->size = size;
|
||||
mem->vaddr = dma_alloc_coherent(dev, mem->size, &mem->dma_handle,
|
||||
GFP_KERNEL);
|
||||
if (!mem->vaddr) {
|
||||
dev_err(dev, "memory alloc size %ld failed\n", mem->size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __videobuf_dc_free(struct device *dev,
|
||||
struct videobuf_dma_contig_memory *mem)
|
||||
{
|
||||
dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
|
||||
|
||||
mem->vaddr = NULL;
|
||||
}
|
||||
|
||||
static void videobuf_vm_open(struct vm_area_struct *vma)
|
||||
{
|
||||
struct videobuf_mapping *map = vma->vm_private_data;
|
||||
|
||||
dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
|
||||
map, map->count, vma->vm_start, vma->vm_end);
|
||||
|
||||
map->count++;
|
||||
}
|
||||
|
||||
static void videobuf_vm_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct videobuf_mapping *map = vma->vm_private_data;
|
||||
struct videobuf_queue *q = map->q;
|
||||
int i;
|
||||
|
||||
dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
|
||||
map, map->count, vma->vm_start, vma->vm_end);
|
||||
|
||||
map->count--;
|
||||
if (0 == map->count) {
|
||||
struct videobuf_dma_contig_memory *mem;
|
||||
|
||||
dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
|
||||
videobuf_queue_lock(q);
|
||||
|
||||
/* We need first to cancel streams, before unmapping */
|
||||
if (q->streaming)
|
||||
videobuf_queue_cancel(q);
|
||||
|
||||
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
|
||||
if (NULL == q->bufs[i])
|
||||
continue;
|
||||
|
||||
if (q->bufs[i]->map != map)
|
||||
continue;
|
||||
|
||||
mem = q->bufs[i]->priv;
|
||||
if (mem) {
|
||||
/* This callback is called only if kernel has
|
||||
allocated memory and this memory is mmapped.
|
||||
In this case, memory should be freed,
|
||||
in order to do memory unmap.
|
||||
*/
|
||||
|
||||
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
|
||||
|
||||
/* vfree is not atomic - can't be
|
||||
called with IRQ's disabled
|
||||
*/
|
||||
dev_dbg(q->dev, "buf[%d] freeing %p\n",
|
||||
i, mem->vaddr);
|
||||
|
||||
__videobuf_dc_free(q->dev, mem);
|
||||
mem->vaddr = NULL;
|
||||
}
|
||||
|
||||
q->bufs[i]->map = NULL;
|
||||
q->bufs[i]->baddr = 0;
|
||||
}
|
||||
|
||||
kfree(map);
|
||||
|
||||
videobuf_queue_unlock(q);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct videobuf_vm_ops = {
|
||||
.open = videobuf_vm_open,
|
||||
.close = videobuf_vm_close,
|
||||
};
|
||||
|
||||
/**
|
||||
* videobuf_dma_contig_user_put() - reset pointer to user space buffer
|
||||
* @mem: per-buffer private videobuf-dma-contig data
|
||||
*
|
||||
* This function resets the user space pointer
|
||||
*/
|
||||
static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
|
||||
{
|
||||
mem->dma_handle = 0;
|
||||
mem->size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* videobuf_dma_contig_user_get() - setup user space memory pointer
|
||||
* @mem: per-buffer private videobuf-dma-contig data
|
||||
* @vb: video buffer to map
|
||||
*
|
||||
* This function validates and sets up a pointer to user space memory.
|
||||
* Only physically contiguous pfn-mapped memory is accepted.
|
||||
*
|
||||
* Returns 0 if successful.
|
||||
*/
|
||||
static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
|
||||
struct videobuf_buffer *vb)
|
||||
{
|
||||
unsigned long untagged_baddr = untagged_addr(vb->baddr);
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct vm_area_struct *vma;
|
||||
unsigned long prev_pfn, this_pfn;
|
||||
unsigned long pages_done, user_address;
|
||||
unsigned int offset;
|
||||
int ret;
|
||||
|
||||
offset = untagged_baddr & ~PAGE_MASK;
|
||||
mem->size = PAGE_ALIGN(vb->size + offset);
|
||||
ret = -EINVAL;
|
||||
|
||||
mmap_read_lock(mm);
|
||||
|
||||
vma = find_vma(mm, untagged_baddr);
|
||||
if (!vma)
|
||||
goto out_up;
|
||||
|
||||
if ((untagged_baddr + mem->size) > vma->vm_end)
|
||||
goto out_up;
|
||||
|
||||
pages_done = 0;
|
||||
prev_pfn = 0; /* kill warning */
|
||||
user_address = untagged_baddr;
|
||||
|
||||
while (pages_done < (mem->size >> PAGE_SHIFT)) {
|
||||
ret = follow_pfn(vma, user_address, &this_pfn);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (pages_done == 0)
|
||||
mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
|
||||
else if (this_pfn != (prev_pfn + 1))
|
||||
ret = -EFAULT;
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
prev_pfn = this_pfn;
|
||||
user_address += PAGE_SIZE;
|
||||
pages_done++;
|
||||
}
|
||||
|
||||
out_up:
|
||||
mmap_read_unlock(current->mm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct videobuf_buffer *__videobuf_alloc(size_t size)
|
||||
{
|
||||
struct videobuf_dma_contig_memory *mem;
|
||||
struct videobuf_buffer *vb;
|
||||
|
||||
vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
|
||||
if (vb) {
|
||||
vb->priv = ((char *)vb) + size;
|
||||
mem = vb->priv;
|
||||
mem->magic = MAGIC_DC_MEM;
|
||||
}
|
||||
|
||||
return vb;
|
||||
}
|
||||
|
||||
static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
|
||||
{
|
||||
struct videobuf_dma_contig_memory *mem = buf->priv;
|
||||
|
||||
BUG_ON(!mem);
|
||||
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
|
||||
|
||||
return mem->vaddr;
|
||||
}
|
||||
|
||||
static int __videobuf_iolock(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb,
|
||||
struct v4l2_framebuffer *fbuf)
|
||||
{
|
||||
struct videobuf_dma_contig_memory *mem = vb->priv;
|
||||
|
||||
BUG_ON(!mem);
|
||||
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
|
||||
|
||||
switch (vb->memory) {
|
||||
case V4L2_MEMORY_MMAP:
|
||||
dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
|
||||
|
||||
/* All handling should be done by __videobuf_mmap_mapper() */
|
||||
if (!mem->vaddr) {
|
||||
dev_err(q->dev, "memory is not allocated/mmapped.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case V4L2_MEMORY_USERPTR:
|
||||
dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
|
||||
|
||||
/* handle pointer from user space */
|
||||
if (vb->baddr)
|
||||
return videobuf_dma_contig_user_get(mem, vb);
|
||||
|
||||
/* allocate memory for the read() method */
|
||||
if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size)))
|
||||
return -ENOMEM;
|
||||
break;
|
||||
case V4L2_MEMORY_OVERLAY:
|
||||
default:
|
||||
dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __videobuf_mmap_mapper(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *buf,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct videobuf_dma_contig_memory *mem;
|
||||
struct videobuf_mapping *map;
|
||||
int retval;
|
||||
|
||||
dev_dbg(q->dev, "%s\n", __func__);
|
||||
|
||||
/* create mapping + update buffer list */
|
||||
map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
buf->map = map;
|
||||
map->q = q;
|
||||
|
||||
buf->baddr = vma->vm_start;
|
||||
|
||||
mem = buf->priv;
|
||||
BUG_ON(!mem);
|
||||
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
|
||||
|
||||
if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize)))
|
||||
goto error;
|
||||
|
||||
/* the "vm_pgoff" is just used in v4l2 to find the
|
||||
* corresponding buffer data structure which is allocated
|
||||
* earlier and it does not mean the offset from the physical
|
||||
* buffer start address as usual. So set it to 0 to pass
|
||||
* the sanity check in dma_mmap_coherent().
|
||||
*/
|
||||
vma->vm_pgoff = 0;
|
||||
retval = dma_mmap_coherent(q->dev, vma, mem->vaddr, mem->dma_handle,
|
||||
mem->size);
|
||||
if (retval) {
|
||||
dev_err(q->dev, "mmap: remap failed with error %d. ",
|
||||
retval);
|
||||
dma_free_coherent(q->dev, mem->size,
|
||||
mem->vaddr, mem->dma_handle);
|
||||
goto error;
|
||||
}
|
||||
|
||||
vma->vm_ops = &videobuf_vm_ops;
|
||||
vm_flags_set(vma, VM_DONTEXPAND);
|
||||
vma->vm_private_data = map;
|
||||
|
||||
dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
|
||||
map, q, vma->vm_start, vma->vm_end,
|
||||
(long int)buf->bsize, vma->vm_pgoff, buf->i);
|
||||
|
||||
videobuf_vm_open(vma);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static struct videobuf_qtype_ops qops = {
|
||||
.magic = MAGIC_QTYPE_OPS,
|
||||
.alloc_vb = __videobuf_alloc,
|
||||
.iolock = __videobuf_iolock,
|
||||
.mmap_mapper = __videobuf_mmap_mapper,
|
||||
.vaddr = __videobuf_to_vaddr,
|
||||
};
|
||||
|
||||
void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
|
||||
const struct videobuf_queue_ops *ops,
|
||||
struct device *dev,
|
||||
spinlock_t *irqlock,
|
||||
enum v4l2_buf_type type,
|
||||
enum v4l2_field field,
|
||||
unsigned int msize,
|
||||
void *priv,
|
||||
struct mutex *ext_lock)
|
||||
{
|
||||
videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
|
||||
priv, &qops, ext_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
|
||||
|
||||
dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
|
||||
{
|
||||
struct videobuf_dma_contig_memory *mem = buf->priv;
|
||||
|
||||
BUG_ON(!mem);
|
||||
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
|
||||
|
||||
return mem->dma_handle;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
|
||||
|
||||
void videobuf_dma_contig_free(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *buf)
|
||||
{
|
||||
struct videobuf_dma_contig_memory *mem = buf->priv;
|
||||
|
||||
/* mmapped memory can't be freed here, otherwise mmapped region
|
||||
would be released, while still needed. In this case, the memory
|
||||
release should happen inside videobuf_vm_close().
|
||||
So, it should free memory only if the memory were allocated for
|
||||
read() operation.
|
||||
*/
|
||||
if (buf->memory != V4L2_MEMORY_USERPTR)
|
||||
return;
|
||||
|
||||
if (!mem)
|
||||
return;
|
||||
|
||||
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
|
||||
|
||||
/* handle user space pointer case */
|
||||
if (buf->baddr) {
|
||||
videobuf_dma_contig_user_put(mem);
|
||||
return;
|
||||
}
|
||||
|
||||
/* read() method */
|
||||
if (mem->vaddr) {
|
||||
__videobuf_dc_free(q->dev, mem);
|
||||
mem->vaddr = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
|
||||
|
||||
MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
|
||||
MODULE_AUTHOR("Magnus Damm");
|
||||
MODULE_LICENSE("GPL");
|
@@ -1,681 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* helper functions for SG DMA video4linux capture buffers
|
||||
*
|
||||
* The functions expect the hardware being able to scatter gather
|
||||
* (i.e. the buffers are not linear in physical memory, but fragmented
|
||||
* into PAGE_SIZE chunks). They also assume the driver does not need
|
||||
* to touch the video data.
|
||||
*
|
||||
* (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org>
|
||||
*
|
||||
* Highly based on video-buf written originally by:
|
||||
* (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
|
||||
* (c) 2006 Mauro Carvalho Chehab, <mchehab@kernel.org>
|
||||
* (c) 2006 Ted Walther and John Sokol
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pgtable.h>
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include <media/videobuf-dma-sg.h>
|
||||
|
||||
#define MAGIC_DMABUF 0x19721112
|
||||
#define MAGIC_SG_MEM 0x17890714
|
||||
|
||||
#define MAGIC_CHECK(is, should) \
|
||||
if (unlikely((is) != (should))) { \
|
||||
printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \
|
||||
is, should); \
|
||||
BUG(); \
|
||||
}
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
|
||||
MODULE_DESCRIPTION("helper module to manage video4linux dma sg buffers");
|
||||
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define dprintk(level, fmt, arg...) \
|
||||
if (debug >= level) \
|
||||
printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Return a scatterlist for some page-aligned vmalloc()'ed memory
|
||||
* block (NULL on errors). Memory for the scatterlist is allocated
|
||||
* using kmalloc. The caller must free the memory.
|
||||
*/
|
||||
static struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt,
|
||||
int nr_pages)
|
||||
{
|
||||
struct scatterlist *sglist;
|
||||
struct page *pg;
|
||||
int i;
|
||||
|
||||
sglist = vzalloc(array_size(nr_pages, sizeof(*sglist)));
|
||||
if (NULL == sglist)
|
||||
return NULL;
|
||||
sg_init_table(sglist, nr_pages);
|
||||
for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
|
||||
pg = vmalloc_to_page(virt);
|
||||
if (NULL == pg)
|
||||
goto err;
|
||||
BUG_ON(PageHighMem(pg));
|
||||
sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);
|
||||
}
|
||||
return sglist;
|
||||
|
||||
err:
|
||||
vfree(sglist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a scatterlist for a an array of userpages (NULL on errors).
|
||||
* Memory for the scatterlist is allocated using kmalloc. The caller
|
||||
* must free the memory.
|
||||
*/
|
||||
static struct scatterlist *videobuf_pages_to_sg(struct page **pages,
|
||||
int nr_pages, int offset, size_t size)
|
||||
{
|
||||
struct scatterlist *sglist;
|
||||
int i;
|
||||
|
||||
if (NULL == pages[0])
|
||||
return NULL;
|
||||
sglist = vmalloc(array_size(nr_pages, sizeof(*sglist)));
|
||||
if (NULL == sglist)
|
||||
return NULL;
|
||||
sg_init_table(sglist, nr_pages);
|
||||
|
||||
if (PageHighMem(pages[0]))
|
||||
/* DMA to highmem pages might not work */
|
||||
goto highmem;
|
||||
sg_set_page(&sglist[0], pages[0],
|
||||
min_t(size_t, PAGE_SIZE - offset, size), offset);
|
||||
size -= min_t(size_t, PAGE_SIZE - offset, size);
|
||||
for (i = 1; i < nr_pages; i++) {
|
||||
if (NULL == pages[i])
|
||||
goto nopage;
|
||||
if (PageHighMem(pages[i]))
|
||||
goto highmem;
|
||||
sg_set_page(&sglist[i], pages[i], min_t(size_t, PAGE_SIZE, size), 0);
|
||||
size -= min_t(size_t, PAGE_SIZE, size);
|
||||
}
|
||||
return sglist;
|
||||
|
||||
nopage:
|
||||
dprintk(2, "sgl: oops - no page\n");
|
||||
vfree(sglist);
|
||||
return NULL;
|
||||
|
||||
highmem:
|
||||
dprintk(2, "sgl: oops - highmem page\n");
|
||||
vfree(sglist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf)
|
||||
{
|
||||
struct videobuf_dma_sg_memory *mem = buf->priv;
|
||||
BUG_ON(!mem);
|
||||
|
||||
MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
|
||||
|
||||
return &mem->dma;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(videobuf_to_dma);
|
||||
|
||||
static void videobuf_dma_init(struct videobuf_dmabuf *dma)
|
||||
{
|
||||
memset(dma, 0, sizeof(*dma));
|
||||
dma->magic = MAGIC_DMABUF;
|
||||
}
|
||||
|
||||
static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
|
||||
int direction, unsigned long data, unsigned long size)
|
||||
{
|
||||
unsigned int gup_flags = FOLL_LONGTERM;
|
||||
unsigned long first, last;
|
||||
int err;
|
||||
|
||||
dma->direction = direction;
|
||||
switch (dma->direction) {
|
||||
case DMA_FROM_DEVICE:
|
||||
gup_flags |= FOLL_WRITE;
|
||||
break;
|
||||
case DMA_TO_DEVICE:
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
first = (data & PAGE_MASK) >> PAGE_SHIFT;
|
||||
last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
|
||||
dma->offset = data & ~PAGE_MASK;
|
||||
dma->size = size;
|
||||
dma->nr_pages = last-first+1;
|
||||
dma->pages = kmalloc_array(dma->nr_pages, sizeof(struct page *),
|
||||
GFP_KERNEL);
|
||||
if (NULL == dma->pages)
|
||||
return -ENOMEM;
|
||||
|
||||
dprintk(1, "init user [0x%lx+0x%lx => %lu pages]\n",
|
||||
data, size, dma->nr_pages);
|
||||
|
||||
err = pin_user_pages(data & PAGE_MASK, dma->nr_pages, gup_flags,
|
||||
dma->pages);
|
||||
|
||||
if (err != dma->nr_pages) {
|
||||
dma->nr_pages = (err >= 0) ? err : 0;
|
||||
dprintk(1, "pin_user_pages: err=%d [%lu]\n", err,
|
||||
dma->nr_pages);
|
||||
return err < 0 ? err : -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
|
||||
unsigned long data, unsigned long size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mmap_read_lock(current->mm);
|
||||
ret = videobuf_dma_init_user_locked(dma, direction, data, size);
|
||||
mmap_read_unlock(current->mm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
|
||||
unsigned long nr_pages)
|
||||
{
|
||||
int i;
|
||||
|
||||
dprintk(1, "init kernel [%lu pages]\n", nr_pages);
|
||||
|
||||
dma->direction = direction;
|
||||
dma->vaddr_pages = kcalloc(nr_pages, sizeof(*dma->vaddr_pages),
|
||||
GFP_KERNEL);
|
||||
if (!dma->vaddr_pages)
|
||||
return -ENOMEM;
|
||||
|
||||
dma->dma_addr = kcalloc(nr_pages, sizeof(*dma->dma_addr), GFP_KERNEL);
|
||||
if (!dma->dma_addr) {
|
||||
kfree(dma->vaddr_pages);
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
void *addr;
|
||||
|
||||
addr = dma_alloc_coherent(dma->dev, PAGE_SIZE,
|
||||
&(dma->dma_addr[i]), GFP_KERNEL);
|
||||
if (addr == NULL)
|
||||
goto out_free_pages;
|
||||
|
||||
dma->vaddr_pages[i] = virt_to_page(addr);
|
||||
}
|
||||
dma->vaddr = vmap(dma->vaddr_pages, nr_pages, VM_MAP | VM_IOREMAP,
|
||||
PAGE_KERNEL);
|
||||
if (NULL == dma->vaddr) {
|
||||
dprintk(1, "vmalloc_32(%lu pages) failed\n", nr_pages);
|
||||
goto out_free_pages;
|
||||
}
|
||||
|
||||
dprintk(1, "vmalloc is at addr %p, size=%lu\n",
|
||||
dma->vaddr, nr_pages << PAGE_SHIFT);
|
||||
|
||||
memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT);
|
||||
dma->nr_pages = nr_pages;
|
||||
|
||||
return 0;
|
||||
out_free_pages:
|
||||
while (i > 0) {
|
||||
void *addr;
|
||||
|
||||
i--;
|
||||
addr = page_address(dma->vaddr_pages[i]);
|
||||
dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]);
|
||||
}
|
||||
kfree(dma->dma_addr);
|
||||
dma->dma_addr = NULL;
|
||||
kfree(dma->vaddr_pages);
|
||||
dma->vaddr_pages = NULL;
|
||||
|
||||
return -ENOMEM;
|
||||
|
||||
}
|
||||
|
||||
static int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
|
||||
dma_addr_t addr, unsigned long nr_pages)
|
||||
{
|
||||
dprintk(1, "init overlay [%lu pages @ bus 0x%lx]\n",
|
||||
nr_pages, (unsigned long)addr);
|
||||
dma->direction = direction;
|
||||
|
||||
if (0 == addr)
|
||||
return -EINVAL;
|
||||
|
||||
dma->bus_addr = addr;
|
||||
dma->nr_pages = nr_pages;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
|
||||
{
|
||||
MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
|
||||
BUG_ON(0 == dma->nr_pages);
|
||||
|
||||
if (dma->pages) {
|
||||
dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
|
||||
dma->offset, dma->size);
|
||||
}
|
||||
if (dma->vaddr) {
|
||||
dma->sglist = videobuf_vmalloc_to_sg(dma->vaddr,
|
||||
dma->nr_pages);
|
||||
}
|
||||
if (dma->bus_addr) {
|
||||
dma->sglist = vmalloc(sizeof(*dma->sglist));
|
||||
if (NULL != dma->sglist) {
|
||||
dma->sglen = 1;
|
||||
sg_dma_address(&dma->sglist[0]) = dma->bus_addr
|
||||
& PAGE_MASK;
|
||||
dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK;
|
||||
sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
if (NULL == dma->sglist) {
|
||||
dprintk(1, "scatterlist is NULL\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!dma->bus_addr) {
|
||||
dma->sglen = dma_map_sg(dev, dma->sglist,
|
||||
dma->nr_pages, dma->direction);
|
||||
if (0 == dma->sglen) {
|
||||
printk(KERN_WARNING
|
||||
"%s: videobuf_map_sg failed\n", __func__);
|
||||
vfree(dma->sglist);
|
||||
dma->sglist = NULL;
|
||||
dma->sglen = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
|
||||
{
|
||||
MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
|
||||
|
||||
if (!dma->sglen)
|
||||
return 0;
|
||||
|
||||
dma_unmap_sg(dev, dma->sglist, dma->nr_pages, dma->direction);
|
||||
|
||||
vfree(dma->sglist);
|
||||
dma->sglist = NULL;
|
||||
dma->sglen = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
|
||||
|
||||
int videobuf_dma_free(struct videobuf_dmabuf *dma)
|
||||
{
|
||||
int i;
|
||||
MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
|
||||
BUG_ON(dma->sglen);
|
||||
|
||||
if (dma->pages) {
|
||||
unpin_user_pages_dirty_lock(dma->pages, dma->nr_pages,
|
||||
dma->direction == DMA_FROM_DEVICE);
|
||||
kfree(dma->pages);
|
||||
dma->pages = NULL;
|
||||
}
|
||||
|
||||
if (dma->dma_addr) {
|
||||
for (i = 0; i < dma->nr_pages; i++) {
|
||||
void *addr;
|
||||
|
||||
addr = page_address(dma->vaddr_pages[i]);
|
||||
dma_free_coherent(dma->dev, PAGE_SIZE, addr,
|
||||
dma->dma_addr[i]);
|
||||
}
|
||||
kfree(dma->dma_addr);
|
||||
dma->dma_addr = NULL;
|
||||
kfree(dma->vaddr_pages);
|
||||
dma->vaddr_pages = NULL;
|
||||
vunmap(dma->vaddr);
|
||||
dma->vaddr = NULL;
|
||||
}
|
||||
|
||||
if (dma->bus_addr)
|
||||
dma->bus_addr = 0;
|
||||
dma->direction = DMA_NONE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(videobuf_dma_free);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static void videobuf_vm_open(struct vm_area_struct *vma)
|
||||
{
|
||||
struct videobuf_mapping *map = vma->vm_private_data;
|
||||
|
||||
dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map,
|
||||
map->count, vma->vm_start, vma->vm_end);
|
||||
|
||||
map->count++;
|
||||
}
|
||||
|
||||
static void videobuf_vm_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct videobuf_mapping *map = vma->vm_private_data;
|
||||
struct videobuf_queue *q = map->q;
|
||||
struct videobuf_dma_sg_memory *mem;
|
||||
int i;
|
||||
|
||||
dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map,
|
||||
map->count, vma->vm_start, vma->vm_end);
|
||||
|
||||
map->count--;
|
||||
if (0 == map->count) {
|
||||
dprintk(1, "munmap %p q=%p\n", map, q);
|
||||
videobuf_queue_lock(q);
|
||||
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
|
||||
if (NULL == q->bufs[i])
|
||||
continue;
|
||||
mem = q->bufs[i]->priv;
|
||||
if (!mem)
|
||||
continue;
|
||||
|
||||
MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
|
||||
|
||||
if (q->bufs[i]->map != map)
|
||||
continue;
|
||||
q->bufs[i]->map = NULL;
|
||||
q->bufs[i]->baddr = 0;
|
||||
q->ops->buf_release(q, q->bufs[i]);
|
||||
}
|
||||
videobuf_queue_unlock(q);
|
||||
kfree(map);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a anonymous page for the mapping. Make sure we can DMA to that
|
||||
* memory location with 32bit PCI devices (i.e. don't use highmem for
|
||||
* now ...). Bounce buffers don't work very well for the data rates
|
||||
* video capture has.
|
||||
*/
|
||||
static vm_fault_t videobuf_vm_fault(struct vm_fault *vmf)
|
||||
{
|
||||
struct vm_area_struct *vma = vmf->vma;
|
||||
struct page *page;
|
||||
|
||||
dprintk(3, "fault: fault @ %08lx [vma %08lx-%08lx]\n",
|
||||
vmf->address, vma->vm_start, vma->vm_end);
|
||||
|
||||
page = alloc_page(GFP_USER | __GFP_DMA32);
|
||||
if (!page)
|
||||
return VM_FAULT_OOM;
|
||||
clear_user_highpage(page, vmf->address);
|
||||
vmf->page = page;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct videobuf_vm_ops = {
|
||||
.open = videobuf_vm_open,
|
||||
.close = videobuf_vm_close,
|
||||
.fault = videobuf_vm_fault,
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* SG handlers for the generic methods
|
||||
*/
|
||||
|
||||
/* Allocated area consists on 3 parts:
|
||||
struct video_buffer
|
||||
struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
|
||||
struct videobuf_dma_sg_memory
|
||||
*/
|
||||
|
||||
static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
|
||||
{
|
||||
struct videobuf_dma_sg_memory *mem;
|
||||
struct videobuf_buffer *vb;
|
||||
|
||||
vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
|
||||
if (!vb)
|
||||
return vb;
|
||||
|
||||
mem = vb->priv = ((char *)vb) + size;
|
||||
mem->magic = MAGIC_SG_MEM;
|
||||
|
||||
videobuf_dma_init(&mem->dma);
|
||||
|
||||
dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
|
||||
__func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb),
|
||||
mem, (long)sizeof(*mem));
|
||||
|
||||
return vb;
|
||||
}
|
||||
|
||||
static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
|
||||
{
|
||||
struct videobuf_dma_sg_memory *mem = buf->priv;
|
||||
BUG_ON(!mem);
|
||||
|
||||
MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
|
||||
|
||||
return mem->dma.vaddr;
|
||||
}
|
||||
|
||||
static int __videobuf_iolock(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb,
|
||||
struct v4l2_framebuffer *fbuf)
|
||||
{
|
||||
struct videobuf_dma_sg_memory *mem = vb->priv;
|
||||
unsigned long pages;
|
||||
dma_addr_t bus;
|
||||
int err;
|
||||
|
||||
BUG_ON(!mem);
|
||||
|
||||
MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
|
||||
|
||||
if (!mem->dma.dev)
|
||||
mem->dma.dev = q->dev;
|
||||
else
|
||||
WARN_ON(mem->dma.dev != q->dev);
|
||||
|
||||
switch (vb->memory) {
|
||||
case V4L2_MEMORY_MMAP:
|
||||
case V4L2_MEMORY_USERPTR:
|
||||
if (0 == vb->baddr) {
|
||||
/* no userspace addr -- kernel bounce buffer */
|
||||
pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
|
||||
err = videobuf_dma_init_kernel(&mem->dma,
|
||||
DMA_FROM_DEVICE,
|
||||
pages);
|
||||
if (0 != err)
|
||||
return err;
|
||||
} else if (vb->memory == V4L2_MEMORY_USERPTR) {
|
||||
/* dma directly to userspace */
|
||||
err = videobuf_dma_init_user(&mem->dma,
|
||||
DMA_FROM_DEVICE,
|
||||
vb->baddr, vb->bsize);
|
||||
if (0 != err)
|
||||
return err;
|
||||
} else {
|
||||
/* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP
|
||||
buffers can only be called from videobuf_qbuf
|
||||
we take current->mm->mmap_lock there, to prevent
|
||||
locking inversion, so don't take it here */
|
||||
|
||||
err = videobuf_dma_init_user_locked(&mem->dma,
|
||||
DMA_FROM_DEVICE,
|
||||
vb->baddr, vb->bsize);
|
||||
if (0 != err)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case V4L2_MEMORY_OVERLAY:
|
||||
if (NULL == fbuf)
|
||||
return -EINVAL;
|
||||
/* FIXME: need sanity checks for vb->boff */
|
||||
/*
|
||||
* Using a double cast to avoid compiler warnings when
|
||||
* building for PAE. Compiler doesn't like direct casting
|
||||
* of a 32 bit ptr to 64 bit integer.
|
||||
*/
|
||||
bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
|
||||
pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
|
||||
err = videobuf_dma_init_overlay(&mem->dma, DMA_FROM_DEVICE,
|
||||
bus, pages);
|
||||
if (0 != err)
|
||||
return err;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
err = videobuf_dma_map(q->dev, &mem->dma);
|
||||
if (0 != err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __videobuf_sync(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *buf)
|
||||
{
|
||||
struct videobuf_dma_sg_memory *mem = buf->priv;
|
||||
BUG_ON(!mem || !mem->dma.sglen);
|
||||
|
||||
MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
|
||||
MAGIC_CHECK(mem->dma.magic, MAGIC_DMABUF);
|
||||
|
||||
dma_sync_sg_for_cpu(q->dev, mem->dma.sglist,
|
||||
mem->dma.nr_pages, mem->dma.direction);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __videobuf_mmap_mapper(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *buf,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct videobuf_dma_sg_memory *mem = buf->priv;
|
||||
struct videobuf_mapping *map;
|
||||
unsigned int first, last, size = 0, i;
|
||||
int retval;
|
||||
|
||||
retval = -EINVAL;
|
||||
|
||||
BUG_ON(!mem);
|
||||
MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
|
||||
|
||||
/* look for first buffer to map */
|
||||
for (first = 0; first < VIDEO_MAX_FRAME; first++) {
|
||||
if (buf == q->bufs[first]) {
|
||||
size = PAGE_ALIGN(q->bufs[first]->bsize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* paranoia, should never happen since buf is always valid. */
|
||||
if (!size) {
|
||||
dprintk(1, "mmap app bug: offset invalid [offset=0x%lx]\n",
|
||||
(vma->vm_pgoff << PAGE_SHIFT));
|
||||
goto done;
|
||||
}
|
||||
|
||||
last = first;
|
||||
|
||||
/* create mapping + update buffer list */
|
||||
retval = -ENOMEM;
|
||||
map = kmalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
|
||||
if (NULL == map)
|
||||
goto done;
|
||||
|
||||
size = 0;
|
||||
for (i = first; i <= last; i++) {
|
||||
if (NULL == q->bufs[i])
|
||||
continue;
|
||||
q->bufs[i]->map = map;
|
||||
q->bufs[i]->baddr = vma->vm_start + size;
|
||||
size += PAGE_ALIGN(q->bufs[i]->bsize);
|
||||
}
|
||||
|
||||
map->count = 1;
|
||||
map->q = q;
|
||||
vma->vm_ops = &videobuf_vm_ops;
|
||||
/* using shared anonymous pages */
|
||||
vm_flags_mod(vma, VM_DONTEXPAND | VM_DONTDUMP, VM_IO);
|
||||
vma->vm_private_data = map;
|
||||
dprintk(1, "mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
|
||||
map, q, vma->vm_start, vma->vm_end, vma->vm_pgoff, first, last);
|
||||
retval = 0;
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct videobuf_qtype_ops sg_ops = {
|
||||
.magic = MAGIC_QTYPE_OPS,
|
||||
|
||||
.alloc_vb = __videobuf_alloc_vb,
|
||||
.iolock = __videobuf_iolock,
|
||||
.sync = __videobuf_sync,
|
||||
.mmap_mapper = __videobuf_mmap_mapper,
|
||||
.vaddr = __videobuf_to_vaddr,
|
||||
};
|
||||
|
||||
void *videobuf_sg_alloc(size_t size)
|
||||
{
|
||||
struct videobuf_queue q;
|
||||
|
||||
/* Required to make generic handler to call __videobuf_alloc */
|
||||
q.int_ops = &sg_ops;
|
||||
|
||||
q.msize = size;
|
||||
|
||||
return videobuf_alloc_vb(&q);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(videobuf_sg_alloc);
|
||||
|
||||
void videobuf_queue_sg_init(struct videobuf_queue *q,
|
||||
const struct videobuf_queue_ops *ops,
|
||||
struct device *dev,
|
||||
spinlock_t *irqlock,
|
||||
enum v4l2_buf_type type,
|
||||
enum v4l2_field field,
|
||||
unsigned int msize,
|
||||
void *priv,
|
||||
struct mutex *ext_lock)
|
||||
{
|
||||
videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
|
||||
priv, &sg_ops, ext_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(videobuf_queue_sg_init);
|
||||
|
@@ -1,326 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* helper functions for vmalloc video4linux capture buffers
|
||||
*
|
||||
* The functions expect the hardware being able to scatter gather
|
||||
* (i.e. the buffers are not linear in physical memory, but fragmented
|
||||
* into PAGE_SIZE chunks). They also assume the driver does not need
|
||||
* to touch the video data.
|
||||
*
|
||||
* (c) 2007 Mauro Carvalho Chehab <mchehab@kernel.org>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pgtable.h>
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include <media/videobuf-vmalloc.h>
|
||||
|
||||
#define MAGIC_DMABUF 0x17760309
|
||||
#define MAGIC_VMAL_MEM 0x18221223
|
||||
|
||||
#define MAGIC_CHECK(is, should) \
|
||||
if (unlikely((is) != (should))) { \
|
||||
printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \
|
||||
is, should); \
|
||||
BUG(); \
|
||||
}
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
|
||||
MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
|
||||
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define dprintk(level, fmt, arg...) \
|
||||
if (debug >= level) \
|
||||
printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
static void videobuf_vm_open(struct vm_area_struct *vma)
|
||||
{
|
||||
struct videobuf_mapping *map = vma->vm_private_data;
|
||||
|
||||
dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
|
||||
map->count, vma->vm_start, vma->vm_end);
|
||||
|
||||
map->count++;
|
||||
}
|
||||
|
||||
static void videobuf_vm_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct videobuf_mapping *map = vma->vm_private_data;
|
||||
struct videobuf_queue *q = map->q;
|
||||
int i;
|
||||
|
||||
dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
|
||||
map->count, vma->vm_start, vma->vm_end);
|
||||
|
||||
map->count--;
|
||||
if (0 == map->count) {
|
||||
struct videobuf_vmalloc_memory *mem;
|
||||
|
||||
dprintk(1, "munmap %p q=%p\n", map, q);
|
||||
videobuf_queue_lock(q);
|
||||
|
||||
/* We need first to cancel streams, before unmapping */
|
||||
if (q->streaming)
|
||||
videobuf_queue_cancel(q);
|
||||
|
||||
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
|
||||
if (NULL == q->bufs[i])
|
||||
continue;
|
||||
|
||||
if (q->bufs[i]->map != map)
|
||||
continue;
|
||||
|
||||
mem = q->bufs[i]->priv;
|
||||
if (mem) {
|
||||
/* This callback is called only if kernel has
|
||||
allocated memory and this memory is mmapped.
|
||||
In this case, memory should be freed,
|
||||
in order to do memory unmap.
|
||||
*/
|
||||
|
||||
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
|
||||
|
||||
/* vfree is not atomic - can't be
|
||||
called with IRQ's disabled
|
||||
*/
|
||||
dprintk(1, "%s: buf[%d] freeing (%p)\n",
|
||||
__func__, i, mem->vaddr);
|
||||
|
||||
vfree(mem->vaddr);
|
||||
mem->vaddr = NULL;
|
||||
}
|
||||
|
||||
q->bufs[i]->map = NULL;
|
||||
q->bufs[i]->baddr = 0;
|
||||
}
|
||||
|
||||
kfree(map);
|
||||
|
||||
videobuf_queue_unlock(q);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct videobuf_vm_ops = {
|
||||
.open = videobuf_vm_open,
|
||||
.close = videobuf_vm_close,
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* vmalloc handlers for the generic methods
|
||||
*/
|
||||
|
||||
/* Allocated area consists on 3 parts:
|
||||
struct video_buffer
|
||||
struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
|
||||
struct videobuf_dma_sg_memory
|
||||
*/
|
||||
|
||||
static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
|
||||
{
|
||||
struct videobuf_vmalloc_memory *mem;
|
||||
struct videobuf_buffer *vb;
|
||||
|
||||
vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
|
||||
if (!vb)
|
||||
return vb;
|
||||
|
||||
mem = vb->priv = ((char *)vb) + size;
|
||||
mem->magic = MAGIC_VMAL_MEM;
|
||||
|
||||
dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
|
||||
__func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb),
|
||||
mem, (long)sizeof(*mem));
|
||||
|
||||
return vb;
|
||||
}
|
||||
|
||||
static int __videobuf_iolock(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb,
|
||||
struct v4l2_framebuffer *fbuf)
|
||||
{
|
||||
struct videobuf_vmalloc_memory *mem = vb->priv;
|
||||
int pages;
|
||||
|
||||
BUG_ON(!mem);
|
||||
|
||||
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
|
||||
|
||||
switch (vb->memory) {
|
||||
case V4L2_MEMORY_MMAP:
|
||||
dprintk(1, "%s memory method MMAP\n", __func__);
|
||||
|
||||
/* All handling should be done by __videobuf_mmap_mapper() */
|
||||
if (!mem->vaddr) {
|
||||
printk(KERN_ERR "memory is not allocated/mmapped.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case V4L2_MEMORY_USERPTR:
|
||||
pages = PAGE_ALIGN(vb->size);
|
||||
|
||||
dprintk(1, "%s memory method USERPTR\n", __func__);
|
||||
|
||||
if (vb->baddr) {
|
||||
printk(KERN_ERR "USERPTR is currently not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The only USERPTR currently supported is the one needed for
|
||||
* read() method.
|
||||
*/
|
||||
|
||||
mem->vaddr = vmalloc_user(pages);
|
||||
if (!mem->vaddr) {
|
||||
printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dprintk(1, "vmalloc is at addr %p (%d pages)\n",
|
||||
mem->vaddr, pages);
|
||||
break;
|
||||
case V4L2_MEMORY_OVERLAY:
|
||||
default:
|
||||
dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
|
||||
|
||||
/* Currently, doesn't support V4L2_MEMORY_OVERLAY */
|
||||
printk(KERN_ERR "Memory method currently unsupported.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __videobuf_mmap_mapper(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *buf,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct videobuf_vmalloc_memory *mem;
|
||||
struct videobuf_mapping *map;
|
||||
int retval, pages;
|
||||
|
||||
dprintk(1, "%s\n", __func__);
|
||||
|
||||
/* create mapping + update buffer list */
|
||||
map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
|
||||
if (NULL == map)
|
||||
return -ENOMEM;
|
||||
|
||||
buf->map = map;
|
||||
map->q = q;
|
||||
|
||||
buf->baddr = vma->vm_start;
|
||||
|
||||
mem = buf->priv;
|
||||
BUG_ON(!mem);
|
||||
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
|
||||
|
||||
pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
|
||||
mem->vaddr = vmalloc_user(pages);
|
||||
if (!mem->vaddr) {
|
||||
printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
|
||||
goto error;
|
||||
}
|
||||
dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages);
|
||||
|
||||
/* Try to remap memory */
|
||||
retval = remap_vmalloc_range(vma, mem->vaddr, 0);
|
||||
if (retval < 0) {
|
||||
printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
|
||||
vfree(mem->vaddr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
vma->vm_ops = &videobuf_vm_ops;
|
||||
vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
|
||||
vma->vm_private_data = map;
|
||||
|
||||
dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
|
||||
map, q, vma->vm_start, vma->vm_end,
|
||||
(long int)buf->bsize,
|
||||
vma->vm_pgoff, buf->i);
|
||||
|
||||
videobuf_vm_open(vma);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
mem = NULL;
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static struct videobuf_qtype_ops qops = {
|
||||
.magic = MAGIC_QTYPE_OPS,
|
||||
|
||||
.alloc_vb = __videobuf_alloc_vb,
|
||||
.iolock = __videobuf_iolock,
|
||||
.mmap_mapper = __videobuf_mmap_mapper,
|
||||
.vaddr = videobuf_to_vmalloc,
|
||||
};
|
||||
|
||||
void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
|
||||
const struct videobuf_queue_ops *ops,
|
||||
struct device *dev,
|
||||
spinlock_t *irqlock,
|
||||
enum v4l2_buf_type type,
|
||||
enum v4l2_field field,
|
||||
unsigned int msize,
|
||||
void *priv,
|
||||
struct mutex *ext_lock)
|
||||
{
|
||||
videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
|
||||
priv, &qops, ext_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
|
||||
|
||||
void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
|
||||
{
|
||||
struct videobuf_vmalloc_memory *mem = buf->priv;
|
||||
BUG_ON(!mem);
|
||||
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
|
||||
|
||||
return mem->vaddr;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
|
||||
|
||||
void videobuf_vmalloc_free(struct videobuf_buffer *buf)
|
||||
{
|
||||
struct videobuf_vmalloc_memory *mem = buf->priv;
|
||||
|
||||
/* mmapped memory can't be freed here, otherwise mmapped region
|
||||
would be released, while still needed. In this case, the memory
|
||||
release should happen inside videobuf_vm_close().
|
||||
So, it should free memory only if the memory were allocated for
|
||||
read() operation.
|
||||
*/
|
||||
if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
|
||||
return;
|
||||
|
||||
if (!mem)
|
||||
return;
|
||||
|
||||
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
|
||||
|
||||
vfree(mem->vaddr);
|
||||
mem->vaddr = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
|
||||
|
@@ -26,7 +26,7 @@ TRACE_EVENT(pwc_handler_enter,
|
||||
__entry->urb__actual_length = urb->actual_length;
|
||||
__entry->fbuf__filled = (pdev->fill_buf
|
||||
? pdev->fill_buf->filled : 0);
|
||||
__assign_str(name, pdev->v4l2_dev.name);
|
||||
__assign_str(name);
|
||||
),
|
||||
TP_printk("dev=%s (fbuf=%p filled=%d) urb=%p (status=%d actual_length=%u)",
|
||||
__get_str(name),
|
||||
@@ -50,7 +50,7 @@ TRACE_EVENT(pwc_handler_exit,
|
||||
__entry->urb = urb;
|
||||
__entry->fbuf = pdev->fill_buf;
|
||||
__entry->fbuf__filled = pdev->fill_buf->filled;
|
||||
__assign_str(name, pdev->v4l2_dev.name);
|
||||
__assign_str(name);
|
||||
),
|
||||
TP_printk(" dev=%s (fbuf=%p filled=%d) urb=%p",
|
||||
__get_str(name),
|
||||
|
Reference in New Issue
Block a user