diff options
Diffstat (limited to 'drivers/media/common/saa7146_fops.c')
-rw-r--r-- | drivers/media/common/saa7146_fops.c | 664 |
1 files changed, 0 insertions, 664 deletions
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c deleted file mode 100644 index b3890bd49df6..000000000000 --- a/drivers/media/common/saa7146_fops.c +++ /dev/null | |||
@@ -1,664 +0,0 @@ | |||
1 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
2 | |||
3 | #include <media/saa7146_vv.h> | ||
4 | #include <linux/module.h> | ||
5 | |||
6 | /****************************************************************************/ | ||
7 | /* resource management functions, shamelessly stolen from saa7134 driver */ | ||
8 | |||
9 | int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) | ||
10 | { | ||
11 | struct saa7146_dev *dev = fh->dev; | ||
12 | struct saa7146_vv *vv = dev->vv_data; | ||
13 | |||
14 | if (fh->resources & bit) { | ||
15 | DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n", | ||
16 | bit, vv->resources); | ||
17 | /* have it already allocated */ | ||
18 | return 1; | ||
19 | } | ||
20 | |||
21 | /* is it free? */ | ||
22 | if (vv->resources & bit) { | ||
23 | DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n", | ||
24 | vv->resources, bit); | ||
25 | /* no, someone else uses it */ | ||
26 | return 0; | ||
27 | } | ||
28 | /* it's free, grab it */ | ||
29 | fh->resources |= bit; | ||
30 | vv->resources |= bit; | ||
31 | DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources); | ||
32 | return 1; | ||
33 | } | ||
34 | |||
35 | void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) | ||
36 | { | ||
37 | struct saa7146_dev *dev = fh->dev; | ||
38 | struct saa7146_vv *vv = dev->vv_data; | ||
39 | |||
40 | BUG_ON((fh->resources & bits) != bits); | ||
41 | |||
42 | fh->resources &= ~bits; | ||
43 | vv->resources &= ~bits; | ||
44 | DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources); | ||
45 | } | ||
46 | |||
47 | |||
48 | /********************************************************************************/ | ||
49 | /* common dma functions */ | ||
50 | |||
51 | void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, | ||
52 | struct saa7146_buf *buf) | ||
53 | { | ||
54 | struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); | ||
55 | DEB_EE("dev:%p, buf:%p\n", dev, buf); | ||
56 | |||
57 | BUG_ON(in_interrupt()); | ||
58 | |||
59 | videobuf_waiton(q, &buf->vb, 0, 0); | ||
60 | videobuf_dma_unmap(q->dev, dma); | ||
61 | videobuf_dma_free(dma); | ||
62 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
63 | } | ||
64 | |||
65 | |||
66 | /********************************************************************************/ | ||
67 | /* common buffer functions */ | ||
68 | |||
69 | int saa7146_buffer_queue(struct saa7146_dev *dev, | ||
70 | struct saa7146_dmaqueue *q, | ||
71 | struct saa7146_buf *buf) | ||
72 | { | ||
73 | assert_spin_locked(&dev->slock); | ||
74 | DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf); | ||
75 | |||
76 | BUG_ON(!q); | ||
77 | |||
78 | if (NULL == q->curr) { | ||
79 | q->curr = buf; | ||
80 | DEB_D("immediately activating buffer %p\n", buf); | ||
81 | buf->activate(dev,buf,NULL); | ||
82 | } else { | ||
83 | list_add_tail(&buf->vb.queue,&q->queue); | ||
84 | buf->vb.state = VIDEOBUF_QUEUED; | ||
85 | DEB_D("adding buffer %p to queue. (active buffer present)\n", | ||
86 | buf); | ||
87 | } | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | void saa7146_buffer_finish(struct saa7146_dev *dev, | ||
92 | struct saa7146_dmaqueue *q, | ||
93 | int state) | ||
94 | { | ||
95 | assert_spin_locked(&dev->slock); | ||
96 | DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state); | ||
97 | DEB_EE("q->curr:%p\n", q->curr); | ||
98 | |||
99 | BUG_ON(!q->curr); | ||
100 | |||
101 | /* finish current buffer */ | ||
102 | if (NULL == q->curr) { | ||
103 | DEB_D("aiii. no current buffer\n"); | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | q->curr->vb.state = state; | ||
108 | do_gettimeofday(&q->curr->vb.ts); | ||
109 | wake_up(&q->curr->vb.done); | ||
110 | |||
111 | q->curr = NULL; | ||
112 | } | ||
113 | |||
114 | void saa7146_buffer_next(struct saa7146_dev *dev, | ||
115 | struct saa7146_dmaqueue *q, int vbi) | ||
116 | { | ||
117 | struct saa7146_buf *buf,*next = NULL; | ||
118 | |||
119 | BUG_ON(!q); | ||
120 | |||
121 | DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi); | ||
122 | |||
123 | assert_spin_locked(&dev->slock); | ||
124 | if (!list_empty(&q->queue)) { | ||
125 | /* activate next one from queue */ | ||
126 | buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue); | ||
127 | list_del(&buf->vb.queue); | ||
128 | if (!list_empty(&q->queue)) | ||
129 | next = list_entry(q->queue.next,struct saa7146_buf, vb.queue); | ||
130 | q->curr = buf; | ||
131 | DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n", | ||
132 | buf, q->queue.prev, q->queue.next); | ||
133 | buf->activate(dev,buf,next); | ||
134 | } else { | ||
135 | DEB_INT("no next buffer. stopping.\n"); | ||
136 | if( 0 != vbi ) { | ||
137 | /* turn off video-dma3 */ | ||
138 | saa7146_write(dev,MC1, MASK_20); | ||
139 | } else { | ||
140 | /* nothing to do -- just prevent next video-dma1 transfer | ||
141 | by lowering the protection address */ | ||
142 | |||
143 | // fixme: fix this for vflip != 0 | ||
144 | |||
145 | saa7146_write(dev, PROT_ADDR1, 0); | ||
146 | saa7146_write(dev, MC2, (MASK_02|MASK_18)); | ||
147 | |||
148 | /* write the address of the rps-program */ | ||
149 | saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle); | ||
150 | /* turn on rps */ | ||
151 | saa7146_write(dev, MC1, (MASK_12 | MASK_28)); | ||
152 | |||
153 | /* | ||
154 | printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1)); | ||
155 | printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1)); | ||
156 | printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1)); | ||
157 | printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1)); | ||
158 | printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1)); | ||
159 | printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1)); | ||
160 | */ | ||
161 | } | ||
162 | del_timer(&q->timeout); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | void saa7146_buffer_timeout(unsigned long data) | ||
167 | { | ||
168 | struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data; | ||
169 | struct saa7146_dev *dev = q->dev; | ||
170 | unsigned long flags; | ||
171 | |||
172 | DEB_EE("dev:%p, dmaq:%p\n", dev, q); | ||
173 | |||
174 | spin_lock_irqsave(&dev->slock,flags); | ||
175 | if (q->curr) { | ||
176 | DEB_D("timeout on %p\n", q->curr); | ||
177 | saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR); | ||
178 | } | ||
179 | |||
180 | /* we don't restart the transfer here like other drivers do. when | ||
181 | a streaming capture is disabled, the timeout function will be | ||
182 | called for the current buffer. if we activate the next buffer now, | ||
183 | we mess up our capture logic. if a timeout occurs on another buffer, | ||
184 | then something is seriously broken before, so no need to buffer the | ||
185 | next capture IMHO... */ | ||
186 | /* | ||
187 | saa7146_buffer_next(dev,q); | ||
188 | */ | ||
189 | spin_unlock_irqrestore(&dev->slock,flags); | ||
190 | } | ||
191 | |||
192 | /********************************************************************************/ | ||
193 | /* file operations */ | ||
194 | |||
195 | static int fops_open(struct file *file) | ||
196 | { | ||
197 | struct video_device *vdev = video_devdata(file); | ||
198 | struct saa7146_dev *dev = video_drvdata(file); | ||
199 | struct saa7146_fh *fh = NULL; | ||
200 | int result = 0; | ||
201 | |||
202 | DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev)); | ||
203 | |||
204 | if (mutex_lock_interruptible(vdev->lock)) | ||
205 | return -ERESTARTSYS; | ||
206 | |||
207 | DEB_D("using: %p\n", dev); | ||
208 | |||
209 | /* check if an extension is registered */ | ||
210 | if( NULL == dev->ext ) { | ||
211 | DEB_S("no extension registered for this device\n"); | ||
212 | result = -ENODEV; | ||
213 | goto out; | ||
214 | } | ||
215 | |||
216 | /* allocate per open data */ | ||
217 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); | ||
218 | if (NULL == fh) { | ||
219 | DEB_S("cannot allocate memory for per open data\n"); | ||
220 | result = -ENOMEM; | ||
221 | goto out; | ||
222 | } | ||
223 | |||
224 | v4l2_fh_init(&fh->fh, vdev); | ||
225 | |||
226 | file->private_data = &fh->fh; | ||
227 | fh->dev = dev; | ||
228 | |||
229 | if (vdev->vfl_type == VFL_TYPE_VBI) { | ||
230 | DEB_S("initializing vbi...\n"); | ||
231 | if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) | ||
232 | result = saa7146_vbi_uops.open(dev,file); | ||
233 | if (dev->ext_vv_data->vbi_fops.open) | ||
234 | dev->ext_vv_data->vbi_fops.open(file); | ||
235 | } else { | ||
236 | DEB_S("initializing video...\n"); | ||
237 | result = saa7146_video_uops.open(dev,file); | ||
238 | } | ||
239 | |||
240 | if (0 != result) { | ||
241 | goto out; | ||
242 | } | ||
243 | |||
244 | if( 0 == try_module_get(dev->ext->module)) { | ||
245 | result = -EINVAL; | ||
246 | goto out; | ||
247 | } | ||
248 | |||
249 | result = 0; | ||
250 | v4l2_fh_add(&fh->fh); | ||
251 | out: | ||
252 | if (fh && result != 0) { | ||
253 | kfree(fh); | ||
254 | file->private_data = NULL; | ||
255 | } | ||
256 | mutex_unlock(vdev->lock); | ||
257 | return result; | ||
258 | } | ||
259 | |||
260 | static int fops_release(struct file *file) | ||
261 | { | ||
262 | struct video_device *vdev = video_devdata(file); | ||
263 | struct saa7146_fh *fh = file->private_data; | ||
264 | struct saa7146_dev *dev = fh->dev; | ||
265 | |||
266 | DEB_EE("file:%p\n", file); | ||
267 | |||
268 | if (mutex_lock_interruptible(vdev->lock)) | ||
269 | return -ERESTARTSYS; | ||
270 | |||
271 | if (vdev->vfl_type == VFL_TYPE_VBI) { | ||
272 | if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) | ||
273 | saa7146_vbi_uops.release(dev,file); | ||
274 | if (dev->ext_vv_data->vbi_fops.release) | ||
275 | dev->ext_vv_data->vbi_fops.release(file); | ||
276 | } else { | ||
277 | saa7146_video_uops.release(dev,file); | ||
278 | } | ||
279 | |||
280 | v4l2_fh_del(&fh->fh); | ||
281 | v4l2_fh_exit(&fh->fh); | ||
282 | module_put(dev->ext->module); | ||
283 | file->private_data = NULL; | ||
284 | kfree(fh); | ||
285 | |||
286 | mutex_unlock(vdev->lock); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int fops_mmap(struct file *file, struct vm_area_struct * vma) | ||
292 | { | ||
293 | struct video_device *vdev = video_devdata(file); | ||
294 | struct saa7146_fh *fh = file->private_data; | ||
295 | struct videobuf_queue *q; | ||
296 | int res; | ||
297 | |||
298 | switch (vdev->vfl_type) { | ||
299 | case VFL_TYPE_GRABBER: { | ||
300 | DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n", | ||
301 | file, vma); | ||
302 | q = &fh->video_q; | ||
303 | break; | ||
304 | } | ||
305 | case VFL_TYPE_VBI: { | ||
306 | DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n", | ||
307 | file, vma); | ||
308 | if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT) | ||
309 | return -ENODEV; | ||
310 | q = &fh->vbi_q; | ||
311 | break; | ||
312 | } | ||
313 | default: | ||
314 | BUG(); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | if (mutex_lock_interruptible(vdev->lock)) | ||
319 | return -ERESTARTSYS; | ||
320 | res = videobuf_mmap_mapper(q, vma); | ||
321 | mutex_unlock(vdev->lock); | ||
322 | return res; | ||
323 | } | ||
324 | |||
325 | static unsigned int __fops_poll(struct file *file, struct poll_table_struct *wait) | ||
326 | { | ||
327 | struct video_device *vdev = video_devdata(file); | ||
328 | struct saa7146_fh *fh = file->private_data; | ||
329 | struct videobuf_buffer *buf = NULL; | ||
330 | struct videobuf_queue *q; | ||
331 | unsigned int res = v4l2_ctrl_poll(file, wait); | ||
332 | |||
333 | DEB_EE("file:%p, poll:%p\n", file, wait); | ||
334 | |||
335 | if (vdev->vfl_type == VFL_TYPE_VBI) { | ||
336 | if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT) | ||
337 | return res | POLLOUT | POLLWRNORM; | ||
338 | if( 0 == fh->vbi_q.streaming ) | ||
339 | return res | videobuf_poll_stream(file, &fh->vbi_q, wait); | ||
340 | q = &fh->vbi_q; | ||
341 | } else { | ||
342 | DEB_D("using video queue\n"); | ||
343 | q = &fh->video_q; | ||
344 | } | ||
345 | |||
346 | if (!list_empty(&q->stream)) | ||
347 | buf = list_entry(q->stream.next, struct videobuf_buffer, stream); | ||
348 | |||
349 | if (!buf) { | ||
350 | DEB_D("buf == NULL!\n"); | ||
351 | return res | POLLERR; | ||
352 | } | ||
353 | |||
354 | poll_wait(file, &buf->done, wait); | ||
355 | if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { | ||
356 | DEB_D("poll succeeded!\n"); | ||
357 | return res | POLLIN | POLLRDNORM; | ||
358 | } | ||
359 | |||
360 | DEB_D("nothing to poll for, buf->state:%d\n", buf->state); | ||
361 | return res; | ||
362 | } | ||
363 | |||
364 | static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait) | ||
365 | { | ||
366 | struct video_device *vdev = video_devdata(file); | ||
367 | unsigned int res; | ||
368 | |||
369 | mutex_lock(vdev->lock); | ||
370 | res = __fops_poll(file, wait); | ||
371 | mutex_unlock(vdev->lock); | ||
372 | return res; | ||
373 | } | ||
374 | |||
375 | static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | ||
376 | { | ||
377 | struct video_device *vdev = video_devdata(file); | ||
378 | struct saa7146_fh *fh = file->private_data; | ||
379 | int ret; | ||
380 | |||
381 | switch (vdev->vfl_type) { | ||
382 | case VFL_TYPE_GRABBER: | ||
383 | /* | ||
384 | DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", | ||
385 | file, data, (unsigned long)count); | ||
386 | */ | ||
387 | return saa7146_video_uops.read(file,data,count,ppos); | ||
388 | case VFL_TYPE_VBI: | ||
389 | /* | ||
390 | DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", | ||
391 | file, data, (unsigned long)count); | ||
392 | */ | ||
393 | if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) { | ||
394 | if (mutex_lock_interruptible(vdev->lock)) | ||
395 | return -ERESTARTSYS; | ||
396 | ret = saa7146_vbi_uops.read(file, data, count, ppos); | ||
397 | mutex_unlock(vdev->lock); | ||
398 | return ret; | ||
399 | } | ||
400 | return -EINVAL; | ||
401 | default: | ||
402 | BUG(); | ||
403 | return 0; | ||
404 | } | ||
405 | } | ||
406 | |||
407 | static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) | ||
408 | { | ||
409 | struct video_device *vdev = video_devdata(file); | ||
410 | struct saa7146_fh *fh = file->private_data; | ||
411 | int ret; | ||
412 | |||
413 | switch (vdev->vfl_type) { | ||
414 | case VFL_TYPE_GRABBER: | ||
415 | return -EINVAL; | ||
416 | case VFL_TYPE_VBI: | ||
417 | if (fh->dev->ext_vv_data->vbi_fops.write) { | ||
418 | if (mutex_lock_interruptible(vdev->lock)) | ||
419 | return -ERESTARTSYS; | ||
420 | ret = fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos); | ||
421 | mutex_unlock(vdev->lock); | ||
422 | return ret; | ||
423 | } | ||
424 | return -EINVAL; | ||
425 | default: | ||
426 | BUG(); | ||
427 | return -EINVAL; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | static const struct v4l2_file_operations video_fops = | ||
432 | { | ||
433 | .owner = THIS_MODULE, | ||
434 | .open = fops_open, | ||
435 | .release = fops_release, | ||
436 | .read = fops_read, | ||
437 | .write = fops_write, | ||
438 | .poll = fops_poll, | ||
439 | .mmap = fops_mmap, | ||
440 | .unlocked_ioctl = video_ioctl2, | ||
441 | }; | ||
442 | |||
443 | static void vv_callback(struct saa7146_dev *dev, unsigned long status) | ||
444 | { | ||
445 | u32 isr = status; | ||
446 | |||
447 | DEB_INT("dev:%p, isr:0x%08x\n", dev, (u32)status); | ||
448 | |||
449 | if (0 != (isr & (MASK_27))) { | ||
450 | DEB_INT("irq: RPS0 (0x%08x)\n", isr); | ||
451 | saa7146_video_uops.irq_done(dev,isr); | ||
452 | } | ||
453 | |||
454 | if (0 != (isr & (MASK_28))) { | ||
455 | u32 mc2 = saa7146_read(dev, MC2); | ||
456 | if( 0 != (mc2 & MASK_15)) { | ||
457 | DEB_INT("irq: RPS1 vbi workaround (0x%08x)\n", isr); | ||
458 | wake_up(&dev->vv_data->vbi_wq); | ||
459 | saa7146_write(dev,MC2, MASK_31); | ||
460 | return; | ||
461 | } | ||
462 | DEB_INT("irq: RPS1 (0x%08x)\n", isr); | ||
463 | saa7146_vbi_uops.irq_done(dev,isr); | ||
464 | } | ||
465 | } | ||
466 | |||
467 | static const struct v4l2_ctrl_ops saa7146_ctrl_ops = { | ||
468 | .s_ctrl = saa7146_s_ctrl, | ||
469 | }; | ||
470 | |||
471 | int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) | ||
472 | { | ||
473 | struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler; | ||
474 | struct v4l2_pix_format *fmt; | ||
475 | struct v4l2_vbi_format *vbi; | ||
476 | struct saa7146_vv *vv; | ||
477 | int err; | ||
478 | |||
479 | err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev); | ||
480 | if (err) | ||
481 | return err; | ||
482 | |||
483 | v4l2_ctrl_handler_init(hdl, 6); | ||
484 | v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops, | ||
485 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); | ||
486 | v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops, | ||
487 | V4L2_CID_CONTRAST, 0, 127, 1, 64); | ||
488 | v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops, | ||
489 | V4L2_CID_SATURATION, 0, 127, 1, 64); | ||
490 | v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops, | ||
491 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
492 | v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops, | ||
493 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
494 | if (hdl->error) { | ||
495 | err = hdl->error; | ||
496 | v4l2_ctrl_handler_free(hdl); | ||
497 | return err; | ||
498 | } | ||
499 | dev->v4l2_dev.ctrl_handler = hdl; | ||
500 | |||
501 | vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL); | ||
502 | if (vv == NULL) { | ||
503 | ERR("out of memory. aborting.\n"); | ||
504 | v4l2_ctrl_handler_free(hdl); | ||
505 | return -ENOMEM; | ||
506 | } | ||
507 | ext_vv->vid_ops = saa7146_video_ioctl_ops; | ||
508 | ext_vv->vbi_ops = saa7146_vbi_ioctl_ops; | ||
509 | ext_vv->core_ops = &saa7146_video_ioctl_ops; | ||
510 | |||
511 | DEB_EE("dev:%p\n", dev); | ||
512 | |||
513 | /* set default values for video parts of the saa7146 */ | ||
514 | saa7146_write(dev, BCS_CTRL, 0x80400040); | ||
515 | |||
516 | /* enable video-port pins */ | ||
517 | saa7146_write(dev, MC1, (MASK_10 | MASK_26)); | ||
518 | |||
519 | /* save per-device extension data (one extension can | ||
520 | handle different devices that might need different | ||
521 | configuration data) */ | ||
522 | dev->ext_vv_data = ext_vv; | ||
523 | |||
524 | vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle); | ||
525 | if( NULL == vv->d_clipping.cpu_addr ) { | ||
526 | ERR("out of memory. aborting.\n"); | ||
527 | kfree(vv); | ||
528 | v4l2_ctrl_handler_free(hdl); | ||
529 | return -1; | ||
530 | } | ||
531 | memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM); | ||
532 | |||
533 | saa7146_video_uops.init(dev,vv); | ||
534 | if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) | ||
535 | saa7146_vbi_uops.init(dev,vv); | ||
536 | |||
537 | fmt = &vv->ov_fb.fmt; | ||
538 | fmt->width = vv->standard->h_max_out; | ||
539 | fmt->height = vv->standard->v_max_out; | ||
540 | fmt->pixelformat = V4L2_PIX_FMT_RGB565; | ||
541 | fmt->bytesperline = 2 * fmt->width; | ||
542 | fmt->sizeimage = fmt->bytesperline * fmt->height; | ||
543 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | ||
544 | |||
545 | fmt = &vv->video_fmt; | ||
546 | fmt->width = 384; | ||
547 | fmt->height = 288; | ||
548 | fmt->pixelformat = V4L2_PIX_FMT_BGR24; | ||
549 | fmt->field = V4L2_FIELD_ANY; | ||
550 | fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
551 | fmt->bytesperline = 3 * fmt->width; | ||
552 | fmt->sizeimage = fmt->bytesperline * fmt->height; | ||
553 | |||
554 | vbi = &vv->vbi_fmt; | ||
555 | vbi->sampling_rate = 27000000; | ||
556 | vbi->offset = 248; /* todo */ | ||
557 | vbi->samples_per_line = 720 * 2; | ||
558 | vbi->sample_format = V4L2_PIX_FMT_GREY; | ||
559 | |||
560 | /* fixme: this only works for PAL */ | ||
561 | vbi->start[0] = 5; | ||
562 | vbi->count[0] = 16; | ||
563 | vbi->start[1] = 312; | ||
564 | vbi->count[1] = 16; | ||
565 | |||
566 | init_timer(&vv->vbi_read_timeout); | ||
567 | |||
568 | vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING; | ||
569 | vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY; | ||
570 | dev->vv_data = vv; | ||
571 | dev->vv_callback = &vv_callback; | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | EXPORT_SYMBOL_GPL(saa7146_vv_init); | ||
576 | |||
577 | int saa7146_vv_release(struct saa7146_dev* dev) | ||
578 | { | ||
579 | struct saa7146_vv *vv = dev->vv_data; | ||
580 | |||
581 | DEB_EE("dev:%p\n", dev); | ||
582 | |||
583 | v4l2_device_unregister(&dev->v4l2_dev); | ||
584 | pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle); | ||
585 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | ||
586 | kfree(vv); | ||
587 | dev->vv_data = NULL; | ||
588 | dev->vv_callback = NULL; | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | EXPORT_SYMBOL_GPL(saa7146_vv_release); | ||
593 | |||
594 | int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, | ||
595 | char *name, int type) | ||
596 | { | ||
597 | struct video_device *vfd; | ||
598 | int err; | ||
599 | int i; | ||
600 | |||
601 | DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type); | ||
602 | |||
603 | // released by vfd->release | ||
604 | vfd = video_device_alloc(); | ||
605 | if (vfd == NULL) | ||
606 | return -ENOMEM; | ||
607 | |||
608 | vfd->fops = &video_fops; | ||
609 | if (type == VFL_TYPE_GRABBER) | ||
610 | vfd->ioctl_ops = &dev->ext_vv_data->vid_ops; | ||
611 | else | ||
612 | vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops; | ||
613 | vfd->release = video_device_release; | ||
614 | vfd->lock = &dev->v4l2_lock; | ||
615 | vfd->v4l2_dev = &dev->v4l2_dev; | ||
616 | vfd->tvnorms = 0; | ||
617 | set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); | ||
618 | for (i = 0; i < dev->ext_vv_data->num_stds; i++) | ||
619 | vfd->tvnorms |= dev->ext_vv_data->stds[i].id; | ||
620 | strlcpy(vfd->name, name, sizeof(vfd->name)); | ||
621 | video_set_drvdata(vfd, dev); | ||
622 | |||
623 | err = video_register_device(vfd, type, -1); | ||
624 | if (err < 0) { | ||
625 | ERR("cannot register v4l2 device. skipping.\n"); | ||
626 | video_device_release(vfd); | ||
627 | return err; | ||
628 | } | ||
629 | |||
630 | pr_info("%s: registered device %s [v4l2]\n", | ||
631 | dev->name, video_device_node_name(vfd)); | ||
632 | |||
633 | *vid = vfd; | ||
634 | return 0; | ||
635 | } | ||
636 | EXPORT_SYMBOL_GPL(saa7146_register_device); | ||
637 | |||
638 | int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev) | ||
639 | { | ||
640 | DEB_EE("dev:%p\n", dev); | ||
641 | |||
642 | video_unregister_device(*vid); | ||
643 | *vid = NULL; | ||
644 | |||
645 | return 0; | ||
646 | } | ||
647 | EXPORT_SYMBOL_GPL(saa7146_unregister_device); | ||
648 | |||
649 | static int __init saa7146_vv_init_module(void) | ||
650 | { | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | |||
655 | static void __exit saa7146_vv_cleanup_module(void) | ||
656 | { | ||
657 | } | ||
658 | |||
659 | module_init(saa7146_vv_init_module); | ||
660 | module_exit(saa7146_vv_cleanup_module); | ||
661 | |||
662 | MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); | ||
663 | MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware"); | ||
664 | MODULE_LICENSE("GPL"); | ||