0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0015
0016 #include <linux/module.h>
0017 #include <linux/errno.h>
0018 #include <linux/fs.h>
0019 #include <linux/kernel.h>
0020 #include <linux/interrupt.h>
0021 #include <linux/kdev_t.h>
0022 #include <media/v4l2-ioctl.h>
0023 #include <asm/io.h>
0024 #include "bttvp.h"
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 #define VBI_OFFSET 244
0036
0037
0038
0039
0040
0041
0042 #define VBI_BPL 2048
0043
0044
0045 #define VBI_DEFLINES 16
0046
0047 static unsigned int vbibufs = 4;
0048 static unsigned int vbi_debug;
0049
0050 module_param(vbibufs, int, 0444);
0051 module_param(vbi_debug, int, 0644);
0052 MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32, default 4");
0053 MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
0054
0055 #ifdef dprintk
0056 # undef dprintk
0057 #endif
0058 #define dprintk(fmt, ...) \
0059 do { \
0060 if (vbi_debug) \
0061 pr_debug("%d: " fmt, btv->c.nr, ##__VA_ARGS__); \
0062 } while (0)
0063
0064 #define IMAGE_SIZE(fmt) \
0065 (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line)
0066
0067
0068
0069
0070 static int vbi_buffer_setup(struct videobuf_queue *q,
0071 unsigned int *count, unsigned int *size)
0072 {
0073 struct bttv_fh *fh = q->priv_data;
0074 struct bttv *btv = fh->btv;
0075
0076 if (0 == *count)
0077 *count = vbibufs;
0078
0079 *size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
0080
0081 dprintk("setup: samples=%u start=%d,%d count=%u,%u\n",
0082 fh->vbi_fmt.fmt.samples_per_line,
0083 fh->vbi_fmt.fmt.start[0],
0084 fh->vbi_fmt.fmt.start[1],
0085 fh->vbi_fmt.fmt.count[0],
0086 fh->vbi_fmt.fmt.count[1]);
0087
0088 return 0;
0089 }
0090
0091 static int vbi_buffer_prepare(struct videobuf_queue *q,
0092 struct videobuf_buffer *vb,
0093 enum v4l2_field field)
0094 {
0095 struct bttv_fh *fh = q->priv_data;
0096 struct bttv *btv = fh->btv;
0097 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
0098 const struct bttv_tvnorm *tvnorm;
0099 unsigned int skip_lines0, skip_lines1, min_vdelay;
0100 int redo_dma_risc;
0101 int rc;
0102
0103 buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
0104 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
0105 return -EINVAL;
0106
0107 tvnorm = fh->vbi_fmt.tvnorm;
0108
0109
0110
0111
0112
0113
0114
0115
0116 skip_lines0 = 0;
0117 skip_lines1 = 0;
0118
0119 if (fh->vbi_fmt.fmt.count[0] > 0)
0120 skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0]
0121 - tvnorm->vbistart[0]));
0122 if (fh->vbi_fmt.fmt.count[1] > 0)
0123 skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1]
0124 - tvnorm->vbistart[1]));
0125
0126 redo_dma_risc = 0;
0127
0128 if (buf->vbi_skip[0] != skip_lines0 ||
0129 buf->vbi_skip[1] != skip_lines1 ||
0130 buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] ||
0131 buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) {
0132 buf->vbi_skip[0] = skip_lines0;
0133 buf->vbi_skip[1] = skip_lines1;
0134 buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0];
0135 buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1];
0136 redo_dma_risc = 1;
0137 }
0138
0139 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
0140 redo_dma_risc = 1;
0141 if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
0142 goto fail;
0143 }
0144
0145 if (redo_dma_risc) {
0146 unsigned int bpl, padding, offset;
0147 struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
0148
0149 bpl = 2044;
0150 padding = VBI_BPL - bpl;
0151
0152 if (fh->vbi_fmt.fmt.count[0] > 0) {
0153 rc = bttv_risc_packed(btv, &buf->top,
0154 dma->sglist,
0155 0, bpl,
0156 padding, skip_lines0,
0157 fh->vbi_fmt.fmt.count[0]);
0158 if (0 != rc)
0159 goto fail;
0160 }
0161
0162 if (fh->vbi_fmt.fmt.count[1] > 0) {
0163 offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
0164
0165 rc = bttv_risc_packed(btv, &buf->bottom,
0166 dma->sglist,
0167 offset, bpl,
0168 padding, skip_lines1,
0169 fh->vbi_fmt.fmt.count[1]);
0170 if (0 != rc)
0171 goto fail;
0172 }
0173 }
0174
0175
0176
0177
0178
0179 min_vdelay = MIN_VDELAY;
0180 if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
0181 min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top;
0182
0183
0184 buf->geo.vdelay = min_vdelay;
0185
0186 buf->vb.state = VIDEOBUF_PREPARED;
0187 buf->vb.field = field;
0188 dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
0189 vb, &buf->top, &buf->bottom,
0190 v4l2_field_names[buf->vb.field]);
0191 return 0;
0192
0193 fail:
0194 bttv_dma_free(q,btv,buf);
0195 return rc;
0196 }
0197
0198 static void
0199 vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
0200 {
0201 struct bttv_fh *fh = q->priv_data;
0202 struct bttv *btv = fh->btv;
0203 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
0204
0205 dprintk("queue %p\n",vb);
0206 buf->vb.state = VIDEOBUF_QUEUED;
0207 list_add_tail(&buf->vb.queue,&btv->vcapture);
0208 if (NULL == btv->cvbi) {
0209 fh->btv->loop_irq |= 4;
0210 bttv_set_dma(btv,0x0c);
0211 }
0212 }
0213
0214 static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
0215 {
0216 struct bttv_fh *fh = q->priv_data;
0217 struct bttv *btv = fh->btv;
0218 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
0219
0220 dprintk("free %p\n",vb);
0221 bttv_dma_free(q,fh->btv,buf);
0222 }
0223
0224 const struct videobuf_queue_ops bttv_vbi_qops = {
0225 .buf_setup = vbi_buffer_setup,
0226 .buf_prepare = vbi_buffer_prepare,
0227 .buf_queue = vbi_buffer_queue,
0228 .buf_release = vbi_buffer_release,
0229 };
0230
0231
0232
0233 static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
0234 __s32 crop_start)
0235 {
0236 __s32 min_start, max_start, max_end, f2_offset;
0237 unsigned int i;
0238
0239
0240
0241
0242
0243
0244
0245 min_start = tvnorm->vbistart[0];
0246 max_start = (crop_start >> 1) - 1;
0247 max_end = (tvnorm->cropcap.bounds.top
0248 + tvnorm->cropcap.bounds.height) >> 1;
0249
0250 if (min_start > max_start)
0251 return -EBUSY;
0252
0253 BUG_ON(max_start >= max_end);
0254
0255 f->sampling_rate = tvnorm->Fsc;
0256 f->samples_per_line = VBI_BPL;
0257 f->sample_format = V4L2_PIX_FMT_GREY;
0258 f->offset = VBI_OFFSET;
0259
0260 f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0];
0261
0262 for (i = 0; i < 2; ++i) {
0263 if (0 == f->count[i]) {
0264
0265
0266
0267
0268 } else {
0269 s64 start, count;
0270
0271 start = clamp(f->start[i], min_start, max_start);
0272
0273 count = (s64) f->start[i] + f->count[i] - start;
0274 f->start[i] = start;
0275 f->count[i] = clamp(count, (s64) 1,
0276 max_end - start);
0277 }
0278
0279 min_start += f2_offset;
0280 max_start += f2_offset;
0281 max_end += f2_offset;
0282 }
0283
0284 if (0 == (f->count[0] | f->count[1])) {
0285
0286 f->start[0] = tvnorm->vbistart[0];
0287 f->start[1] = tvnorm->vbistart[1];
0288 f->count[0] = 1;
0289 f->count[1] = 1;
0290 }
0291
0292 f->flags = 0;
0293
0294 f->reserved[0] = 0;
0295 f->reserved[1] = 0;
0296
0297 return 0;
0298 }
0299
0300 int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
0301 {
0302 struct bttv_fh *fh = f;
0303 struct bttv *btv = fh->btv;
0304 const struct bttv_tvnorm *tvnorm;
0305 __s32 crop_start;
0306
0307 mutex_lock(&btv->lock);
0308
0309 tvnorm = &bttv_tvnorms[btv->tvnorm];
0310 crop_start = btv->crop_start;
0311
0312 mutex_unlock(&btv->lock);
0313
0314 return try_fmt(&frt->fmt.vbi, tvnorm, crop_start);
0315 }
0316
0317
0318 int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
0319 {
0320 struct bttv_fh *fh = f;
0321 struct bttv *btv = fh->btv;
0322 const struct bttv_tvnorm *tvnorm;
0323 __s32 start1, end;
0324 int rc;
0325
0326 mutex_lock(&btv->lock);
0327
0328 rc = -EBUSY;
0329 if (fh->resources & RESOURCE_VBI)
0330 goto fail;
0331
0332 tvnorm = &bttv_tvnorms[btv->tvnorm];
0333
0334 rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start);
0335 if (0 != rc)
0336 goto fail;
0337
0338 start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] +
0339 tvnorm->vbistart[0];
0340
0341
0342
0343
0344
0345
0346
0347 end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
0348
0349 mutex_lock(&fh->vbi.vb_lock);
0350
0351 fh->vbi_fmt.fmt = frt->fmt.vbi;
0352 fh->vbi_fmt.tvnorm = tvnorm;
0353 fh->vbi_fmt.end = end;
0354
0355 mutex_unlock(&fh->vbi.vb_lock);
0356
0357 rc = 0;
0358
0359 fail:
0360 mutex_unlock(&btv->lock);
0361
0362 return rc;
0363 }
0364
0365
0366 int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
0367 {
0368 struct bttv_fh *fh = f;
0369 const struct bttv_tvnorm *tvnorm;
0370
0371 frt->fmt.vbi = fh->vbi_fmt.fmt;
0372
0373 tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
0374
0375 if (tvnorm != fh->vbi_fmt.tvnorm) {
0376 __s32 max_end;
0377 unsigned int i;
0378
0379
0380
0381
0382
0383 max_end = (tvnorm->cropcap.bounds.top
0384 + tvnorm->cropcap.bounds.height) >> 1;
0385
0386 frt->fmt.vbi.sampling_rate = tvnorm->Fsc;
0387
0388 for (i = 0; i < 2; ++i) {
0389 __s32 new_start;
0390
0391 new_start = frt->fmt.vbi.start[i]
0392 + tvnorm->vbistart[i]
0393 - fh->vbi_fmt.tvnorm->vbistart[i];
0394
0395 frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
0396 frt->fmt.vbi.count[i] =
0397 min((__s32) frt->fmt.vbi.count[i],
0398 max_end - frt->fmt.vbi.start[i]);
0399
0400 max_end += tvnorm->vbistart[1]
0401 - tvnorm->vbistart[0];
0402 }
0403 }
0404 return 0;
0405 }
0406
0407 void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm)
0408 {
0409 const struct bttv_tvnorm *tvnorm;
0410 unsigned int real_samples_per_line;
0411 unsigned int real_count;
0412
0413 tvnorm = &bttv_tvnorms[norm];
0414
0415 f->fmt.sampling_rate = tvnorm->Fsc;
0416 f->fmt.samples_per_line = VBI_BPL;
0417 f->fmt.sample_format = V4L2_PIX_FMT_GREY;
0418 f->fmt.offset = VBI_OFFSET;
0419 f->fmt.start[0] = tvnorm->vbistart[0];
0420 f->fmt.start[1] = tvnorm->vbistart[1];
0421 f->fmt.count[0] = VBI_DEFLINES;
0422 f->fmt.count[1] = VBI_DEFLINES;
0423 f->fmt.flags = 0;
0424 f->fmt.reserved[0] = 0;
0425 f->fmt.reserved[1] = 0;
0426
0427
0428
0429 real_samples_per_line = 1024 + tvnorm->vbipack * 4;
0430 real_count = ((tvnorm->cropcap.defrect.top >> 1)
0431 - tvnorm->vbistart[0]);
0432
0433 BUG_ON(real_samples_per_line > VBI_BPL);
0434 BUG_ON(real_count > VBI_DEFLINES);
0435
0436 f->tvnorm = tvnorm;
0437
0438
0439 f->end = tvnorm->vbistart[0] * 2 + 2;
0440 }