1 /*
2  * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
3  * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/kthread.h>
23 #include <linux/freezer.h>
24 #include <media/v4l2-ioctl.h>
25 #include <media/v4l2-common.h>
26 #include <media/videobuf-dma-sg.h>
27 #include "solo6x10.h"
28 #include "tw28.h"
29 
30 #define SOLO_HW_BPL		2048
31 #define SOLO_DISP_PIX_FIELD	V4L2_FIELD_INTERLACED
32 
33 /* Image size is two fields, SOLO_HW_BPL is one horizontal line */
34 #define solo_vlines(__solo)	(__solo->video_vsize * 2)
35 #define solo_image_size(__solo) (solo_bytesperline(__solo) * \
36 				 solo_vlines(__solo))
37 #define solo_bytesperline(__solo) (__solo->video_hsize * 2)
38 
39 #define MIN_VID_BUFFERS		4
40 
41 /* Simple file handle */
42 struct solo_filehandle {
43 	struct solo_dev		*solo_dev;
44 	struct videobuf_queue	vidq;
45 	struct task_struct      *kthread;
46 	spinlock_t		slock;
47 	int			old_write;
48 	struct list_head	vidq_active;
49 	struct p2m_desc		desc[SOLO_NR_P2M_DESC];
50 	int			desc_idx;
51 };
52 
53 unsigned video_nr = -1;
54 module_param(video_nr, uint, 0644);
55 MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
56 
erase_on(struct solo_dev * solo_dev)57 static void erase_on(struct solo_dev *solo_dev)
58 {
59 	solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
60 	solo_dev->erasing = 1;
61 	solo_dev->frame_blank = 0;
62 }
63 
erase_off(struct solo_dev * solo_dev)64 static int erase_off(struct solo_dev *solo_dev)
65 {
66 	if (!solo_dev->erasing)
67 		return 0;
68 
69 	/* First time around, assert erase off */
70 	if (!solo_dev->frame_blank)
71 		solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
72 	/* Keep the erasing flag on for 8 frames minimum */
73 	if (solo_dev->frame_blank++ >= 8)
74 		solo_dev->erasing = 0;
75 
76 	return 1;
77 }
78 
solo_video_in_isr(struct solo_dev * solo_dev)79 void solo_video_in_isr(struct solo_dev *solo_dev)
80 {
81 	solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN);
82 	wake_up_interruptible(&solo_dev->disp_thread_wait);
83 }
84 
solo_win_setup(struct solo_dev * solo_dev,u8 ch,int sx,int sy,int ex,int ey,int scale)85 static void solo_win_setup(struct solo_dev *solo_dev, u8 ch,
86 			   int sx, int sy, int ex, int ey, int scale)
87 {
88 	if (ch >= solo_dev->nr_chans)
89 		return;
90 
91 	/* Here, we just keep window/channel the same */
92 	solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
93 		       SOLO_VI_WIN_CHANNEL(ch) |
94 		       SOLO_VI_WIN_SX(sx) |
95 		       SOLO_VI_WIN_EX(ex) |
96 		       SOLO_VI_WIN_SCALE(scale));
97 
98 	solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
99 		       SOLO_VI_WIN_SY(sy) |
100 		       SOLO_VI_WIN_EY(ey));
101 }
102 
solo_v4l2_ch_ext_4up(struct solo_dev * solo_dev,u8 idx,int on)103 static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
104 {
105 	u8 ch = idx * 4;
106 
107 	if (ch >= solo_dev->nr_chans)
108 		return -EINVAL;
109 
110 	if (!on) {
111 		u8 i;
112 		for (i = ch; i < ch + 4; i++)
113 			solo_win_setup(solo_dev, i, solo_dev->video_hsize,
114 				       solo_vlines(solo_dev),
115 				       solo_dev->video_hsize,
116 				       solo_vlines(solo_dev), 0);
117 		return 0;
118 	}
119 
120 	/* Row 1 */
121 	solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
122 		       solo_vlines(solo_dev) / 2, 3);
123 	solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
124 		       solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
125 	/* Row 2 */
126 	solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
127 		       solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
128 	solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
129 		       solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
130 		       solo_vlines(solo_dev), 3);
131 
132 	return 0;
133 }
134 
solo_v4l2_ch_ext_16up(struct solo_dev * solo_dev,int on)135 static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on)
136 {
137 	int sy, ysize, hsize, i;
138 
139 	if (!on) {
140 		for (i = 0; i < 16; i++)
141 			solo_win_setup(solo_dev, i, solo_dev->video_hsize,
142 				       solo_vlines(solo_dev),
143 				       solo_dev->video_hsize,
144 				       solo_vlines(solo_dev), 0);
145 		return 0;
146 	}
147 
148 	ysize = solo_vlines(solo_dev) / 4;
149 	hsize = solo_dev->video_hsize / 4;
150 
151 	for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
152 		solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
153 			       sy + ysize, 5);
154 		solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
155 			       hsize * 2, sy + ysize, 5);
156 		solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
157 			       hsize * 3, sy + ysize, 5);
158 		solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
159 			       solo_dev->video_hsize, sy + ysize, 5);
160 	}
161 
162 	return 0;
163 }
164 
solo_v4l2_ch(struct solo_dev * solo_dev,u8 ch,int on)165 static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on)
166 {
167 	u8 ext_ch;
168 
169 	if (ch < solo_dev->nr_chans) {
170 		solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
171 			       on ? 0 : solo_vlines(solo_dev),
172 			       solo_dev->video_hsize, solo_vlines(solo_dev),
173 			       on ? 1 : 0);
174 		return 0;
175 	}
176 
177 	if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
178 		return -EINVAL;
179 
180 	ext_ch = ch - solo_dev->nr_chans;
181 
182 	/* 4up's first */
183 	if (ext_ch < 4)
184 		return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
185 
186 	/* Remaining case is 16up for 16-port */
187 	return solo_v4l2_ch_ext_16up(solo_dev, on);
188 }
189 
solo_v4l2_set_ch(struct solo_dev * solo_dev,u8 ch)190 static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch)
191 {
192 	if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
193 		return -EINVAL;
194 
195 	erase_on(solo_dev);
196 
197 	solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
198 	solo_v4l2_ch(solo_dev, ch, 1);
199 
200 	solo_dev->cur_disp_ch = ch;
201 
202 	return 0;
203 }
204 
disp_reset_desc(struct solo_filehandle * fh)205 static void disp_reset_desc(struct solo_filehandle *fh)
206 {
207 	/* We use desc mode, which ignores desc 0 */
208 	memset(fh->desc, 0, sizeof(*fh->desc));
209 	fh->desc_idx = 1;
210 }
211 
disp_flush_descs(struct solo_filehandle * fh)212 static int disp_flush_descs(struct solo_filehandle *fh)
213 {
214 	int ret;
215 
216 	if (!fh->desc_idx)
217 		return 0;
218 
219 	ret = solo_p2m_dma_desc(fh->solo_dev, SOLO_P2M_DMA_ID_DISP,
220 				fh->desc, fh->desc_idx);
221 	disp_reset_desc(fh);
222 
223 	return ret;
224 }
225 
disp_push_desc(struct solo_filehandle * fh,dma_addr_t dma_addr,u32 ext_addr,int size,int repeat,int ext_size)226 static int disp_push_desc(struct solo_filehandle *fh, dma_addr_t dma_addr,
227 		      u32 ext_addr, int size, int repeat, int ext_size)
228 {
229 	if (fh->desc_idx >= SOLO_NR_P2M_DESC) {
230 		int ret = disp_flush_descs(fh);
231 		if (ret)
232 			return ret;
233 	}
234 
235 	solo_p2m_push_desc(&fh->desc[fh->desc_idx], 0, dma_addr, ext_addr,
236 			   size, repeat, ext_size);
237 	fh->desc_idx++;
238 
239 	return 0;
240 }
241 
solo_fillbuf(struct solo_filehandle * fh,struct videobuf_buffer * vb)242 static void solo_fillbuf(struct solo_filehandle *fh,
243 			 struct videobuf_buffer *vb)
244 {
245 	struct solo_dev *solo_dev = fh->solo_dev;
246 	struct videobuf_dmabuf *vbuf;
247 	unsigned int fdma_addr;
248 	int error = 1;
249 	int i;
250 	struct scatterlist *sg;
251 	dma_addr_t sg_dma;
252 	int sg_size_left;
253 
254 	vbuf = videobuf_to_dma(vb);
255 	if (!vbuf)
256 		goto finish_buf;
257 
258 	if (erase_off(solo_dev)) {
259 		int i;
260 
261 		/* Just blit to the entire sg list, ignoring size */
262 		for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) {
263 			void *p = sg_virt(sg);
264 			size_t len = sg_dma_len(sg);
265 
266 			for (i = 0; i < len; i += 2) {
267 				((u8 *)p)[i] = 0x80;
268 				((u8 *)p)[i + 1] = 0x00;
269 			}
270 		}
271 
272 		error = 0;
273 		goto finish_buf;
274 	}
275 
276 	disp_reset_desc(fh);
277 	sg = vbuf->sglist;
278 	sg_dma = sg_dma_address(sg);
279 	sg_size_left = sg_dma_len(sg);
280 
281 	fdma_addr = SOLO_DISP_EXT_ADDR + (fh->old_write *
282 			(SOLO_HW_BPL * solo_vlines(solo_dev)));
283 
284 	for (i = 0; i < solo_vlines(solo_dev); i++) {
285 		int line_len = solo_bytesperline(solo_dev);
286 		int lines;
287 
288 		if (!sg_size_left) {
289 			sg = sg_next(sg);
290 			if (sg == NULL)
291 				goto finish_buf;
292 			sg_dma = sg_dma_address(sg);
293 			sg_size_left = sg_dma_len(sg);
294 		}
295 
296 		/* No room for an entire line, so chunk it up */
297 		if (sg_size_left < line_len) {
298 			int this_addr = fdma_addr;
299 
300 			while (line_len > 0) {
301 				int this_write;
302 
303 				if (!sg_size_left) {
304 					sg = sg_next(sg);
305 					if (sg == NULL)
306 						goto finish_buf;
307 					sg_dma = sg_dma_address(sg);
308 					sg_size_left = sg_dma_len(sg);
309 				}
310 
311 				this_write = min(sg_size_left, line_len);
312 
313 				if (disp_push_desc(fh, sg_dma, this_addr,
314 						   this_write, 0, 0))
315 					goto finish_buf;
316 
317 				line_len -= this_write;
318 				sg_size_left -= this_write;
319 				sg_dma += this_write;
320 				this_addr += this_write;
321 			}
322 
323 			fdma_addr += SOLO_HW_BPL;
324 			continue;
325 		}
326 
327 		/* Shove as many lines into a repeating descriptor as possible */
328 		lines = min(sg_size_left / line_len,
329 			    solo_vlines(solo_dev) - i);
330 
331 		if (disp_push_desc(fh, sg_dma, fdma_addr, line_len,
332 				   lines - 1, SOLO_HW_BPL))
333 			goto finish_buf;
334 
335 		i += lines - 1;
336 		fdma_addr += SOLO_HW_BPL * lines;
337 		sg_dma += lines * line_len;
338 		sg_size_left -= lines * line_len;
339 	}
340 
341 	error = disp_flush_descs(fh);
342 
343 finish_buf:
344 	if (error) {
345 		vb->state = VIDEOBUF_ERROR;
346 	} else {
347 		vb->size = solo_vlines(solo_dev) * solo_bytesperline(solo_dev);
348 		vb->state = VIDEOBUF_DONE;
349 		vb->field_count++;
350 		do_gettimeofday(&vb->ts);
351 	}
352 
353 	wake_up(&vb->done);
354 
355 	return;
356 }
357 
solo_thread_try(struct solo_filehandle * fh)358 static void solo_thread_try(struct solo_filehandle *fh)
359 {
360 	struct videobuf_buffer *vb;
361 	unsigned int cur_write;
362 
363 	for (;;) {
364 		spin_lock(&fh->slock);
365 
366 		if (list_empty(&fh->vidq_active))
367 			break;
368 
369 		vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer,
370 				      queue);
371 
372 		if (!waitqueue_active(&vb->done))
373 			break;
374 
375 		cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev,
376 						 SOLO_VI_STATUS0));
377 		if (cur_write == fh->old_write)
378 			break;
379 
380 		fh->old_write = cur_write;
381 		list_del(&vb->queue);
382 
383 		spin_unlock(&fh->slock);
384 
385 		solo_fillbuf(fh, vb);
386 	}
387 
388 	assert_spin_locked(&fh->slock);
389 	spin_unlock(&fh->slock);
390 }
391 
solo_thread(void * data)392 static int solo_thread(void *data)
393 {
394 	struct solo_filehandle *fh = data;
395 	struct solo_dev *solo_dev = fh->solo_dev;
396 	DECLARE_WAITQUEUE(wait, current);
397 
398 	set_freezable();
399 	add_wait_queue(&solo_dev->disp_thread_wait, &wait);
400 
401 	for (;;) {
402 		long timeout = schedule_timeout_interruptible(HZ);
403 		if (timeout == -ERESTARTSYS || kthread_should_stop())
404 			break;
405 		solo_thread_try(fh);
406 		try_to_freeze();
407 	}
408 
409 	remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
410 
411 	return 0;
412 }
413 
solo_start_thread(struct solo_filehandle * fh)414 static int solo_start_thread(struct solo_filehandle *fh)
415 {
416 	fh->kthread = kthread_run(solo_thread, fh, SOLO6X10_NAME "_disp");
417 
418 	if (IS_ERR(fh->kthread))
419 		return PTR_ERR(fh->kthread);
420 
421 	return 0;
422 }
423 
solo_stop_thread(struct solo_filehandle * fh)424 static void solo_stop_thread(struct solo_filehandle *fh)
425 {
426 	if (fh->kthread) {
427 		kthread_stop(fh->kthread);
428 		fh->kthread = NULL;
429 	}
430 }
431 
solo_buf_setup(struct videobuf_queue * vq,unsigned int * count,unsigned int * size)432 static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
433 			  unsigned int *size)
434 {
435 	struct solo_filehandle *fh = vq->priv_data;
436 	struct solo_dev *solo_dev  = fh->solo_dev;
437 
438 	*size = solo_image_size(solo_dev);
439 
440 	if (*count < MIN_VID_BUFFERS)
441 		*count = MIN_VID_BUFFERS;
442 
443 	return 0;
444 }
445 
solo_buf_prepare(struct videobuf_queue * vq,struct videobuf_buffer * vb,enum v4l2_field field)446 static int solo_buf_prepare(struct videobuf_queue *vq,
447 			    struct videobuf_buffer *vb, enum v4l2_field field)
448 {
449 	struct solo_filehandle *fh  = vq->priv_data;
450 	struct solo_dev *solo_dev = fh->solo_dev;
451 
452 	vb->size = solo_image_size(solo_dev);
453 	if (vb->baddr != 0 && vb->bsize < vb->size)
454 		return -EINVAL;
455 
456 	/* XXX: These properties only change when queue is idle */
457 	vb->width  = solo_dev->video_hsize;
458 	vb->height = solo_vlines(solo_dev);
459 	vb->bytesperline = solo_bytesperline(solo_dev);
460 	vb->field  = field;
461 
462 	if (vb->state == VIDEOBUF_NEEDS_INIT) {
463 		int rc = videobuf_iolock(vq, vb, NULL);
464 		if (rc < 0) {
465 			struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
466 			videobuf_dma_unmap(vq->dev, dma);
467 			videobuf_dma_free(dma);
468 			vb->state = VIDEOBUF_NEEDS_INIT;
469 			return rc;
470 		}
471 	}
472 	vb->state = VIDEOBUF_PREPARED;
473 
474 	return 0;
475 }
476 
solo_buf_queue(struct videobuf_queue * vq,struct videobuf_buffer * vb)477 static void solo_buf_queue(struct videobuf_queue *vq,
478 			   struct videobuf_buffer *vb)
479 {
480 	struct solo_filehandle *fh = vq->priv_data;
481 	struct solo_dev *solo_dev = fh->solo_dev;
482 
483 	vb->state = VIDEOBUF_QUEUED;
484 	list_add_tail(&vb->queue, &fh->vidq_active);
485 	wake_up_interruptible(&solo_dev->disp_thread_wait);
486 }
487 
solo_buf_release(struct videobuf_queue * vq,struct videobuf_buffer * vb)488 static void solo_buf_release(struct videobuf_queue *vq,
489 			     struct videobuf_buffer *vb)
490 {
491 	struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
492 
493 	videobuf_dma_unmap(vq->dev, dma);
494 	videobuf_dma_free(dma);
495 	vb->state = VIDEOBUF_NEEDS_INIT;
496 }
497 
498 static struct videobuf_queue_ops solo_video_qops = {
499 	.buf_setup	= solo_buf_setup,
500 	.buf_prepare	= solo_buf_prepare,
501 	.buf_queue	= solo_buf_queue,
502 	.buf_release	= solo_buf_release,
503 };
504 
solo_v4l2_poll(struct file * file,struct poll_table_struct * wait)505 static unsigned int solo_v4l2_poll(struct file *file,
506 				   struct poll_table_struct *wait)
507 {
508 	struct solo_filehandle *fh = file->private_data;
509 
510 	return videobuf_poll_stream(file, &fh->vidq, wait);
511 }
512 
solo_v4l2_mmap(struct file * file,struct vm_area_struct * vma)513 static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
514 {
515 	struct solo_filehandle *fh = file->private_data;
516 
517 	return videobuf_mmap_mapper(&fh->vidq, vma);
518 }
519 
solo_v4l2_open(struct file * file)520 static int solo_v4l2_open(struct file *file)
521 {
522 	struct solo_dev *solo_dev = video_drvdata(file);
523 	struct solo_filehandle *fh;
524 	int ret;
525 
526 	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
527 	if (fh == NULL)
528 		return -ENOMEM;
529 
530 	spin_lock_init(&fh->slock);
531 	INIT_LIST_HEAD(&fh->vidq_active);
532 	fh->solo_dev = solo_dev;
533 	file->private_data = fh;
534 
535 	ret = solo_start_thread(fh);
536 	if (ret) {
537 		kfree(fh);
538 		return ret;
539 	}
540 
541 	videobuf_queue_sg_init(&fh->vidq, &solo_video_qops,
542 			       &solo_dev->pdev->dev, &fh->slock,
543 			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
544 			       SOLO_DISP_PIX_FIELD,
545 			       sizeof(struct videobuf_buffer), fh, NULL);
546 
547 	return 0;
548 }
549 
solo_v4l2_read(struct file * file,char __user * data,size_t count,loff_t * ppos)550 static ssize_t solo_v4l2_read(struct file *file, char __user *data,
551 			      size_t count, loff_t *ppos)
552 {
553 	struct solo_filehandle *fh = file->private_data;
554 
555 	return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
556 				    file->f_flags & O_NONBLOCK);
557 }
558 
solo_v4l2_release(struct file * file)559 static int solo_v4l2_release(struct file *file)
560 {
561 	struct solo_filehandle *fh = file->private_data;
562 
563 	videobuf_stop(&fh->vidq);
564 	videobuf_mmap_free(&fh->vidq);
565 	solo_stop_thread(fh);
566 	kfree(fh);
567 
568 	return 0;
569 }
570 
solo_querycap(struct file * file,void * priv,struct v4l2_capability * cap)571 static int solo_querycap(struct file *file, void  *priv,
572 			 struct v4l2_capability *cap)
573 {
574 	struct solo_filehandle  *fh  = priv;
575 	struct solo_dev *solo_dev = fh->solo_dev;
576 
577 	strcpy(cap->driver, SOLO6X10_NAME);
578 	strcpy(cap->card, "Softlogic 6x10");
579 	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
580 		 pci_name(solo_dev->pdev));
581 	cap->version = SOLO6X10_VER_NUM;
582 	cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
583 				V4L2_CAP_READWRITE |
584 				V4L2_CAP_STREAMING;
585 	return 0;
586 }
587 
solo_enum_ext_input(struct solo_dev * solo_dev,struct v4l2_input * input)588 static int solo_enum_ext_input(struct solo_dev *solo_dev,
589 			       struct v4l2_input *input)
590 {
591 	static const char *dispnames_1[] = { "4UP" };
592 	static const char *dispnames_2[] = { "4UP-1", "4UP-2" };
593 	static const char *dispnames_5[] = {
594 		"4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
595 	};
596 	const char **dispnames;
597 
598 	if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
599 		return -EINVAL;
600 
601 	if (solo_dev->nr_ext == 5)
602 		dispnames = dispnames_5;
603 	else if (solo_dev->nr_ext == 2)
604 		dispnames = dispnames_2;
605 	else
606 		dispnames = dispnames_1;
607 
608 	snprintf(input->name, sizeof(input->name), "Multi %s",
609 		 dispnames[input->index - solo_dev->nr_chans]);
610 
611 	return 0;
612 }
613 
solo_enum_input(struct file * file,void * priv,struct v4l2_input * input)614 static int solo_enum_input(struct file *file, void *priv,
615 			   struct v4l2_input *input)
616 {
617 	struct solo_filehandle *fh  = priv;
618 	struct solo_dev *solo_dev = fh->solo_dev;
619 
620 	if (input->index >= solo_dev->nr_chans) {
621 		int ret = solo_enum_ext_input(solo_dev, input);
622 		if (ret < 0)
623 			return ret;
624 	} else {
625 		snprintf(input->name, sizeof(input->name), "Camera %d",
626 			 input->index + 1);
627 
628 		/* We can only check this for normal inputs */
629 		if (!tw28_get_video_status(solo_dev, input->index))
630 			input->status = V4L2_IN_ST_NO_SIGNAL;
631 	}
632 
633 	input->type = V4L2_INPUT_TYPE_CAMERA;
634 
635 	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
636 		input->std = V4L2_STD_NTSC_M;
637 	else
638 		input->std = V4L2_STD_PAL_B;
639 
640 	return 0;
641 }
642 
solo_set_input(struct file * file,void * priv,unsigned int index)643 static int solo_set_input(struct file *file, void *priv, unsigned int index)
644 {
645 	struct solo_filehandle *fh = priv;
646 
647 	return solo_v4l2_set_ch(fh->solo_dev, index);
648 }
649 
solo_get_input(struct file * file,void * priv,unsigned int * index)650 static int solo_get_input(struct file *file, void *priv, unsigned int *index)
651 {
652 	struct solo_filehandle *fh = priv;
653 
654 	*index = fh->solo_dev->cur_disp_ch;
655 
656 	return 0;
657 }
658 
solo_enum_fmt_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)659 static int solo_enum_fmt_cap(struct file *file, void *priv,
660 			     struct v4l2_fmtdesc *f)
661 {
662 	if (f->index)
663 		return -EINVAL;
664 
665 	f->pixelformat = V4L2_PIX_FMT_UYVY;
666 	strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
667 
668 	return 0;
669 }
670 
solo_try_fmt_cap(struct file * file,void * priv,struct v4l2_format * f)671 static int solo_try_fmt_cap(struct file *file, void *priv,
672 			    struct v4l2_format *f)
673 {
674 	struct solo_filehandle *fh = priv;
675 	struct solo_dev *solo_dev = fh->solo_dev;
676 	struct v4l2_pix_format *pix = &f->fmt.pix;
677 	int image_size = solo_image_size(solo_dev);
678 
679 	/* Check supported sizes */
680 	if (pix->width != solo_dev->video_hsize)
681 		pix->width = solo_dev->video_hsize;
682 	if (pix->height != solo_vlines(solo_dev))
683 		pix->height = solo_vlines(solo_dev);
684 	if (pix->sizeimage != image_size)
685 		pix->sizeimage = image_size;
686 
687 	/* Check formats */
688 	if (pix->field == V4L2_FIELD_ANY)
689 		pix->field = SOLO_DISP_PIX_FIELD;
690 
691 	if (pix->pixelformat != V4L2_PIX_FMT_UYVY ||
692 	    pix->field       != SOLO_DISP_PIX_FIELD ||
693 	    pix->colorspace  != V4L2_COLORSPACE_SMPTE170M)
694 		return -EINVAL;
695 
696 	return 0;
697 }
698 
solo_set_fmt_cap(struct file * file,void * priv,struct v4l2_format * f)699 static int solo_set_fmt_cap(struct file *file, void *priv,
700 			    struct v4l2_format *f)
701 {
702 	struct solo_filehandle *fh = priv;
703 
704 	if (videobuf_queue_is_busy(&fh->vidq))
705 		return -EBUSY;
706 
707 	/* For right now, if it doesn't match our running config,
708 	 * then fail */
709 	return solo_try_fmt_cap(file, priv, f);
710 }
711 
solo_get_fmt_cap(struct file * file,void * priv,struct v4l2_format * f)712 static int solo_get_fmt_cap(struct file *file, void *priv,
713 			    struct v4l2_format *f)
714 {
715 	struct solo_filehandle *fh = priv;
716 	struct solo_dev *solo_dev = fh->solo_dev;
717 	struct v4l2_pix_format *pix = &f->fmt.pix;
718 
719 	pix->width = solo_dev->video_hsize;
720 	pix->height = solo_vlines(solo_dev);
721 	pix->pixelformat = V4L2_PIX_FMT_UYVY;
722 	pix->field = SOLO_DISP_PIX_FIELD;
723 	pix->sizeimage = solo_image_size(solo_dev);
724 	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
725 	pix->bytesperline = solo_bytesperline(solo_dev);
726 
727 	return 0;
728 }
729 
solo_reqbufs(struct file * file,void * priv,struct v4l2_requestbuffers * req)730 static int solo_reqbufs(struct file *file, void *priv,
731 			struct v4l2_requestbuffers *req)
732 {
733 	struct solo_filehandle *fh = priv;
734 
735 	return videobuf_reqbufs(&fh->vidq, req);
736 }
737 
solo_querybuf(struct file * file,void * priv,struct v4l2_buffer * buf)738 static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
739 {
740 	struct solo_filehandle *fh = priv;
741 
742 	return videobuf_querybuf(&fh->vidq, buf);
743 }
744 
solo_qbuf(struct file * file,void * priv,struct v4l2_buffer * buf)745 static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
746 {
747 	struct solo_filehandle *fh = priv;
748 
749 	return videobuf_qbuf(&fh->vidq, buf);
750 }
751 
solo_dqbuf(struct file * file,void * priv,struct v4l2_buffer * buf)752 static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
753 {
754 	struct solo_filehandle *fh = priv;
755 
756 	return videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
757 }
758 
solo_streamon(struct file * file,void * priv,enum v4l2_buf_type i)759 static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
760 {
761 	struct solo_filehandle *fh = priv;
762 
763 	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
764 		return -EINVAL;
765 
766 	return videobuf_streamon(&fh->vidq);
767 }
768 
solo_streamoff(struct file * file,void * priv,enum v4l2_buf_type i)769 static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
770 {
771 	struct solo_filehandle *fh = priv;
772 
773 	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
774 		return -EINVAL;
775 
776 	return videobuf_streamoff(&fh->vidq);
777 }
778 
solo_s_std(struct file * file,void * priv,v4l2_std_id * i)779 static int solo_s_std(struct file *file, void *priv, v4l2_std_id *i)
780 {
781 	return 0;
782 }
783 
784 static const u32 solo_motion_ctrls[] = {
785 	V4L2_CID_MOTION_TRACE,
786 	0
787 };
788 
789 static const u32 *solo_ctrl_classes[] = {
790 	solo_motion_ctrls,
791 	NULL
792 };
793 
solo_disp_queryctrl(struct file * file,void * priv,struct v4l2_queryctrl * qc)794 static int solo_disp_queryctrl(struct file *file, void *priv,
795 			       struct v4l2_queryctrl *qc)
796 {
797 	qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
798 	if (!qc->id)
799 		return -EINVAL;
800 
801 	switch (qc->id) {
802 #ifdef PRIVATE_CIDS
803 	case V4L2_CID_MOTION_TRACE:
804 		qc->type = V4L2_CTRL_TYPE_BOOLEAN;
805 		qc->minimum = 0;
806 		qc->maximum = qc->step = 1;
807 		qc->default_value = 0;
808 		strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name));
809 		return 0;
810 #else
811 	case V4L2_CID_MOTION_TRACE:
812 		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
813 #endif
814 	}
815 	return -EINVAL;
816 }
817 
solo_disp_g_ctrl(struct file * file,void * priv,struct v4l2_control * ctrl)818 static int solo_disp_g_ctrl(struct file *file, void *priv,
819 			    struct v4l2_control *ctrl)
820 {
821 	struct solo_filehandle *fh = priv;
822 	struct solo_dev *solo_dev = fh->solo_dev;
823 
824 	switch (ctrl->id) {
825 	case V4L2_CID_MOTION_TRACE:
826 		ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR)
827 			? 1 : 0;
828 		return 0;
829 	}
830 	return -EINVAL;
831 }
832 
solo_disp_s_ctrl(struct file * file,void * priv,struct v4l2_control * ctrl)833 static int solo_disp_s_ctrl(struct file *file, void *priv,
834 			    struct v4l2_control *ctrl)
835 {
836 	struct solo_filehandle *fh = priv;
837 	struct solo_dev *solo_dev = fh->solo_dev;
838 
839 	switch (ctrl->id) {
840 	case V4L2_CID_MOTION_TRACE:
841 		if (ctrl->value) {
842 			solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
843 					SOLO_VI_MOTION_Y_ADD |
844 					SOLO_VI_MOTION_Y_VALUE(0x20) |
845 					SOLO_VI_MOTION_CB_VALUE(0x10) |
846 					SOLO_VI_MOTION_CR_VALUE(0x10));
847 			solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
848 					SOLO_VI_MOTION_CR_ADD |
849 					SOLO_VI_MOTION_Y_VALUE(0x10) |
850 					SOLO_VI_MOTION_CB_VALUE(0x80) |
851 					SOLO_VI_MOTION_CR_VALUE(0x10));
852 		} else {
853 			solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
854 			solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
855 		}
856 		return 0;
857 	}
858 	return -EINVAL;
859 }
860 
861 static const struct v4l2_file_operations solo_v4l2_fops = {
862 	.owner			= THIS_MODULE,
863 	.open			= solo_v4l2_open,
864 	.release		= solo_v4l2_release,
865 	.read			= solo_v4l2_read,
866 	.poll			= solo_v4l2_poll,
867 	.mmap			= solo_v4l2_mmap,
868 	.ioctl			= video_ioctl2,
869 };
870 
871 static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
872 	.vidioc_querycap		= solo_querycap,
873 	.vidioc_s_std			= solo_s_std,
874 	/* Input callbacks */
875 	.vidioc_enum_input		= solo_enum_input,
876 	.vidioc_s_input			= solo_set_input,
877 	.vidioc_g_input			= solo_get_input,
878 	/* Video capture format callbacks */
879 	.vidioc_enum_fmt_vid_cap	= solo_enum_fmt_cap,
880 	.vidioc_try_fmt_vid_cap		= solo_try_fmt_cap,
881 	.vidioc_s_fmt_vid_cap		= solo_set_fmt_cap,
882 	.vidioc_g_fmt_vid_cap		= solo_get_fmt_cap,
883 	/* Streaming I/O */
884 	.vidioc_reqbufs			= solo_reqbufs,
885 	.vidioc_querybuf		= solo_querybuf,
886 	.vidioc_qbuf			= solo_qbuf,
887 	.vidioc_dqbuf			= solo_dqbuf,
888 	.vidioc_streamon		= solo_streamon,
889 	.vidioc_streamoff		= solo_streamoff,
890 	/* Controls */
891 	.vidioc_queryctrl		= solo_disp_queryctrl,
892 	.vidioc_g_ctrl			= solo_disp_g_ctrl,
893 	.vidioc_s_ctrl			= solo_disp_s_ctrl,
894 };
895 
896 static struct video_device solo_v4l2_template = {
897 	.name			= SOLO6X10_NAME,
898 	.fops			= &solo_v4l2_fops,
899 	.ioctl_ops		= &solo_v4l2_ioctl_ops,
900 	.minor			= -1,
901 	.release		= video_device_release,
902 
903 	.tvnorms		= V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
904 	.current_norm		= V4L2_STD_NTSC_M,
905 };
906 
solo_v4l2_init(struct solo_dev * solo_dev)907 int solo_v4l2_init(struct solo_dev *solo_dev)
908 {
909 	int ret;
910 	int i;
911 
912 	init_waitqueue_head(&solo_dev->disp_thread_wait);
913 
914 	solo_dev->vfd = video_device_alloc();
915 	if (!solo_dev->vfd)
916 		return -ENOMEM;
917 
918 	*solo_dev->vfd = solo_v4l2_template;
919 	solo_dev->vfd->parent = &solo_dev->pdev->dev;
920 
921 	ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr);
922 	if (ret < 0) {
923 		video_device_release(solo_dev->vfd);
924 		solo_dev->vfd = NULL;
925 		return ret;
926 	}
927 
928 	video_set_drvdata(solo_dev->vfd, solo_dev);
929 
930 	snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
931 		 SOLO6X10_NAME, solo_dev->vfd->num);
932 
933 	if (video_nr != -1)
934 		video_nr++;
935 
936 	dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
937 		 "%d inputs (%d extended)\n", solo_dev->vfd->num,
938 		 solo_dev->nr_chans, solo_dev->nr_ext);
939 
940 	/* Cycle all the channels and clear */
941 	for (i = 0; i < solo_dev->nr_chans; i++) {
942 		solo_v4l2_set_ch(solo_dev, i);
943 		while (erase_off(solo_dev))
944 			;/* Do nothing */
945 	}
946 
947 	/* Set the default display channel */
948 	solo_v4l2_set_ch(solo_dev, 0);
949 	while (erase_off(solo_dev))
950 		;/* Do nothing */
951 
952 	solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
953 
954 	return 0;
955 }
956 
solo_v4l2_exit(struct solo_dev * solo_dev)957 void solo_v4l2_exit(struct solo_dev *solo_dev)
958 {
959 	solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
960 	if (solo_dev->vfd) {
961 		video_unregister_device(solo_dev->vfd);
962 		solo_dev->vfd = NULL;
963 	}
964 }
965