diff options
Diffstat (limited to 'drivers/staging/solo6x10/v4l2-enc.c')
-rw-r--r-- | drivers/staging/solo6x10/v4l2-enc.c | 1825 |
1 files changed, 1825 insertions, 0 deletions
diff --git a/drivers/staging/solo6x10/v4l2-enc.c b/drivers/staging/solo6x10/v4l2-enc.c new file mode 100644 index 00000000000..bee7280bbed --- /dev/null +++ b/drivers/staging/solo6x10/v4l2-enc.c | |||
@@ -0,0 +1,1825 @@ | |||
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 | #include "jpeg.h" | ||
30 | |||
31 | #define MIN_VID_BUFFERS 4 | ||
32 | #define FRAME_BUF_SIZE (128 * 1024) | ||
33 | #define MP4_QS 16 | ||
34 | |||
35 | static int solo_enc_thread(void *data); | ||
36 | |||
37 | extern unsigned video_nr; | ||
38 | |||
39 | struct solo_enc_fh { | ||
40 | struct solo_enc_dev *enc; | ||
41 | u32 fmt; | ||
42 | u16 rd_idx; | ||
43 | u8 enc_on; | ||
44 | enum solo_enc_types type; | ||
45 | struct videobuf_queue vidq; | ||
46 | struct list_head vidq_active; | ||
47 | struct task_struct *kthread; | ||
48 | struct p2m_desc desc[SOLO_NR_P2M_DESC]; | ||
49 | }; | ||
50 | |||
51 | static const u32 solo_user_ctrls[] = { | ||
52 | V4L2_CID_BRIGHTNESS, | ||
53 | V4L2_CID_CONTRAST, | ||
54 | V4L2_CID_SATURATION, | ||
55 | V4L2_CID_HUE, | ||
56 | V4L2_CID_SHARPNESS, | ||
57 | 0 | ||
58 | }; | ||
59 | |||
60 | static const u32 solo_mpeg_ctrls[] = { | ||
61 | V4L2_CID_MPEG_VIDEO_ENCODING, | ||
62 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, | ||
63 | 0 | ||
64 | }; | ||
65 | |||
66 | static const u32 solo_private_ctrls[] = { | ||
67 | V4L2_CID_MOTION_ENABLE, | ||
68 | V4L2_CID_MOTION_THRESHOLD, | ||
69 | 0 | ||
70 | }; | ||
71 | |||
72 | static const u32 solo_fmtx_ctrls[] = { | ||
73 | V4L2_CID_RDS_TX_RADIO_TEXT, | ||
74 | 0 | ||
75 | }; | ||
76 | |||
77 | static const u32 *solo_ctrl_classes[] = { | ||
78 | solo_user_ctrls, | ||
79 | solo_mpeg_ctrls, | ||
80 | solo_fmtx_ctrls, | ||
81 | solo_private_ctrls, | ||
82 | NULL | ||
83 | }; | ||
84 | |||
85 | static int solo_is_motion_on(struct solo_enc_dev *solo_enc) | ||
86 | { | ||
87 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
88 | u8 ch = solo_enc->ch; | ||
89 | |||
90 | if (solo_dev->motion_mask & (1 << ch)) | ||
91 | return 1; | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on) | ||
96 | { | ||
97 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
98 | u8 ch = solo_enc->ch; | ||
99 | |||
100 | spin_lock(&solo_enc->lock); | ||
101 | |||
102 | if (on) | ||
103 | solo_dev->motion_mask |= (1 << ch); | ||
104 | else | ||
105 | solo_dev->motion_mask &= ~(1 << ch); | ||
106 | |||
107 | /* Do this regardless of if we are turning on or off */ | ||
108 | solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR, | ||
109 | 1 << solo_enc->ch); | ||
110 | solo_enc->motion_detected = 0; | ||
111 | |||
112 | solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, | ||
113 | SOLO_VI_MOTION_EN(solo_dev->motion_mask) | | ||
114 | (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); | ||
115 | |||
116 | if (solo_dev->motion_mask) | ||
117 | solo_irq_on(solo_dev, SOLO_IRQ_MOTION); | ||
118 | else | ||
119 | solo_irq_off(solo_dev, SOLO_IRQ_MOTION); | ||
120 | |||
121 | spin_unlock(&solo_enc->lock); | ||
122 | } | ||
123 | |||
124 | /* Should be called with solo_enc->lock held */ | ||
125 | static void solo_update_mode(struct solo_enc_dev *solo_enc) | ||
126 | { | ||
127 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
128 | |||
129 | assert_spin_locked(&solo_enc->lock); | ||
130 | |||
131 | solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0; | ||
132 | solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1); | ||
133 | |||
134 | switch (solo_enc->mode) { | ||
135 | case SOLO_ENC_MODE_CIF: | ||
136 | solo_enc->width = solo_dev->video_hsize >> 1; | ||
137 | solo_enc->height = solo_dev->video_vsize; | ||
138 | break; | ||
139 | case SOLO_ENC_MODE_D1: | ||
140 | solo_enc->width = solo_dev->video_hsize; | ||
141 | solo_enc->height = solo_dev->video_vsize << 1; | ||
142 | solo_enc->bw_weight <<= 2; | ||
143 | break; | ||
144 | default: | ||
145 | WARN(1, "mode is unknown\n"); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | /* Should be called with solo_enc->lock held */ | ||
150 | static int solo_enc_on(struct solo_enc_fh *fh) | ||
151 | { | ||
152 | struct solo_enc_dev *solo_enc = fh->enc; | ||
153 | u8 ch = solo_enc->ch; | ||
154 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
155 | u8 interval; | ||
156 | |||
157 | assert_spin_locked(&solo_enc->lock); | ||
158 | |||
159 | if (fh->enc_on) | ||
160 | return 0; | ||
161 | |||
162 | solo_update_mode(solo_enc); | ||
163 | |||
164 | /* Make sure to bw check on first reader */ | ||
165 | if (!atomic_read(&solo_enc->readers)) { | ||
166 | if (solo_enc->bw_weight > solo_dev->enc_bw_remain) | ||
167 | return -EBUSY; | ||
168 | else | ||
169 | solo_dev->enc_bw_remain -= solo_enc->bw_weight; | ||
170 | } | ||
171 | |||
172 | fh->enc_on = 1; | ||
173 | fh->rd_idx = solo_enc->solo_dev->enc_wr_idx; | ||
174 | |||
175 | if (fh->type == SOLO_ENC_TYPE_EXT) | ||
176 | solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1); | ||
177 | |||
178 | if (atomic_inc_return(&solo_enc->readers) > 1) | ||
179 | return 0; | ||
180 | |||
181 | /* Disable all encoding for this channel */ | ||
182 | solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0); | ||
183 | |||
184 | /* Common for both std and ext encoding */ | ||
185 | solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch), | ||
186 | solo_enc->interlaced ? 1 : 0); | ||
187 | |||
188 | if (solo_enc->interlaced) | ||
189 | interval = solo_enc->interval - 1; | ||
190 | else | ||
191 | interval = solo_enc->interval; | ||
192 | |||
193 | /* Standard encoding only */ | ||
194 | solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop); | ||
195 | solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp); | ||
196 | solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval); | ||
197 | |||
198 | /* Extended encoding only */ | ||
199 | solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop); | ||
200 | solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp); | ||
201 | solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval); | ||
202 | |||
203 | /* Enables the standard encoder */ | ||
204 | solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode); | ||
205 | |||
206 | /* Settle down Beavis... */ | ||
207 | mdelay(10); | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static void solo_enc_off(struct solo_enc_fh *fh) | ||
213 | { | ||
214 | struct solo_enc_dev *solo_enc = fh->enc; | ||
215 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
216 | |||
217 | if (!fh->enc_on) | ||
218 | return; | ||
219 | |||
220 | if (fh->kthread) { | ||
221 | kthread_stop(fh->kthread); | ||
222 | fh->kthread = NULL; | ||
223 | } | ||
224 | |||
225 | solo_dev->enc_bw_remain += solo_enc->bw_weight; | ||
226 | fh->enc_on = 0; | ||
227 | |||
228 | if (atomic_dec_return(&solo_enc->readers) > 0) | ||
229 | return; | ||
230 | |||
231 | solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0); | ||
232 | solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0); | ||
233 | } | ||
234 | |||
235 | static int solo_start_fh_thread(struct solo_enc_fh *fh) | ||
236 | { | ||
237 | struct solo_enc_dev *solo_enc = fh->enc; | ||
238 | |||
239 | fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6X10_NAME "_enc"); | ||
240 | |||
241 | /* Oops, we had a problem */ | ||
242 | if (IS_ERR(fh->kthread)) { | ||
243 | spin_lock(&solo_enc->lock); | ||
244 | solo_enc_off(fh); | ||
245 | spin_unlock(&solo_enc->lock); | ||
246 | |||
247 | return PTR_ERR(fh->kthread); | ||
248 | } | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static void enc_reset_gop(struct solo_dev *solo_dev, u8 ch) | ||
254 | { | ||
255 | BUG_ON(ch >= solo_dev->nr_chans); | ||
256 | solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), 1); | ||
257 | solo_dev->v4l2_enc[ch]->reset_gop = 1; | ||
258 | } | ||
259 | |||
260 | static int enc_gop_reset(struct solo_dev *solo_dev, u8 ch, u8 vop) | ||
261 | { | ||
262 | BUG_ON(ch >= solo_dev->nr_chans); | ||
263 | if (!solo_dev->v4l2_enc[ch]->reset_gop) | ||
264 | return 0; | ||
265 | if (vop) | ||
266 | return 1; | ||
267 | solo_dev->v4l2_enc[ch]->reset_gop = 0; | ||
268 | solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), | ||
269 | solo_dev->v4l2_enc[ch]->gop); | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static void enc_write_sg(struct scatterlist *sglist, void *buf, int size) | ||
274 | { | ||
275 | struct scatterlist *sg; | ||
276 | u8 *src = buf; | ||
277 | |||
278 | for (sg = sglist; sg && size > 0; sg = sg_next(sg)) { | ||
279 | u8 *p = sg_virt(sg); | ||
280 | size_t len = sg_dma_len(sg); | ||
281 | int i; | ||
282 | |||
283 | for (i = 0; i < len && size; i++) | ||
284 | p[i] = *(src++); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static int enc_get_mpeg_dma_sg(struct solo_dev *solo_dev, | ||
289 | struct p2m_desc *desc, | ||
290 | struct scatterlist *sglist, int skip, | ||
291 | unsigned int off, unsigned int size) | ||
292 | { | ||
293 | int ret; | ||
294 | |||
295 | if (off > SOLO_MP4E_EXT_SIZE(solo_dev)) | ||
296 | return -EINVAL; | ||
297 | |||
298 | if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) { | ||
299 | return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, | ||
300 | desc, 0, sglist, skip, | ||
301 | SOLO_MP4E_EXT_ADDR(solo_dev) + off, size); | ||
302 | } | ||
303 | |||
304 | /* Buffer wrap */ | ||
305 | ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0, | ||
306 | sglist, skip, SOLO_MP4E_EXT_ADDR(solo_dev) + off, | ||
307 | SOLO_MP4E_EXT_SIZE(solo_dev) - off); | ||
308 | |||
309 | ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0, | ||
310 | sglist, skip + SOLO_MP4E_EXT_SIZE(solo_dev) - off, | ||
311 | SOLO_MP4E_EXT_ADDR(solo_dev), | ||
312 | size + off - SOLO_MP4E_EXT_SIZE(solo_dev)); | ||
313 | |||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | static int enc_get_mpeg_dma_t(struct solo_dev *solo_dev, | ||
318 | dma_addr_t buf, unsigned int off, | ||
319 | unsigned int size) | ||
320 | { | ||
321 | int ret; | ||
322 | |||
323 | if (off > SOLO_MP4E_EXT_SIZE(solo_dev)) | ||
324 | return -EINVAL; | ||
325 | |||
326 | if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) { | ||
327 | return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf, | ||
328 | SOLO_MP4E_EXT_ADDR(solo_dev) + off, size); | ||
329 | } | ||
330 | |||
331 | /* Buffer wrap */ | ||
332 | ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf, | ||
333 | SOLO_MP4E_EXT_ADDR(solo_dev) + off, | ||
334 | SOLO_MP4E_EXT_SIZE(solo_dev) - off); | ||
335 | |||
336 | ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, | ||
337 | buf + SOLO_MP4E_EXT_SIZE(solo_dev) - off, | ||
338 | SOLO_MP4E_EXT_ADDR(solo_dev), | ||
339 | size + off - SOLO_MP4E_EXT_SIZE(solo_dev)); | ||
340 | |||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | static int enc_get_mpeg_dma(struct solo_dev *solo_dev, void *buf, | ||
345 | unsigned int off, unsigned int size) | ||
346 | { | ||
347 | int ret; | ||
348 | |||
349 | dma_addr_t dma_addr = pci_map_single(solo_dev->pdev, buf, size, | ||
350 | PCI_DMA_FROMDEVICE); | ||
351 | ret = enc_get_mpeg_dma_t(solo_dev, dma_addr, off, size); | ||
352 | pci_unmap_single(solo_dev->pdev, dma_addr, size, PCI_DMA_FROMDEVICE); | ||
353 | |||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | static int enc_get_jpeg_dma_sg(struct solo_dev *solo_dev, | ||
358 | struct p2m_desc *desc, | ||
359 | struct scatterlist *sglist, int skip, | ||
360 | unsigned int off, unsigned int size) | ||
361 | { | ||
362 | int ret; | ||
363 | |||
364 | if (off > SOLO_JPEG_EXT_SIZE(solo_dev)) | ||
365 | return -EINVAL; | ||
366 | |||
367 | if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev)) { | ||
368 | return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, | ||
369 | desc, 0, sglist, skip, | ||
370 | SOLO_JPEG_EXT_ADDR(solo_dev) + off, size); | ||
371 | } | ||
372 | |||
373 | /* Buffer wrap */ | ||
374 | ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0, | ||
375 | sglist, skip, SOLO_JPEG_EXT_ADDR(solo_dev) + off, | ||
376 | SOLO_JPEG_EXT_SIZE(solo_dev) - off); | ||
377 | |||
378 | ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0, | ||
379 | sglist, skip + SOLO_JPEG_EXT_SIZE(solo_dev) - off, | ||
380 | SOLO_JPEG_EXT_ADDR(solo_dev), | ||
381 | size + off - SOLO_JPEG_EXT_SIZE(solo_dev)); | ||
382 | |||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | /* Returns true of __chk is within the first __range bytes of __off */ | ||
387 | #define OFF_IN_RANGE(__off, __range, __chk) \ | ||
388 | ((__off <= __chk) && ((__off + __range) >= __chk)) | ||
389 | |||
390 | static void solo_jpeg_header(struct solo_enc_dev *solo_enc, | ||
391 | struct videobuf_dmabuf *vbuf) | ||
392 | { | ||
393 | struct scatterlist *sg; | ||
394 | void *src = jpeg_header; | ||
395 | size_t copied = 0; | ||
396 | size_t to_copy = sizeof(jpeg_header); | ||
397 | |||
398 | for (sg = vbuf->sglist; sg && copied < to_copy; sg = sg_next(sg)) { | ||
399 | size_t this_copy = min(sg_dma_len(sg), | ||
400 | (unsigned int)(to_copy - copied)); | ||
401 | u8 *p = sg_virt(sg); | ||
402 | |||
403 | memcpy(p, src + copied, this_copy); | ||
404 | |||
405 | if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 5)) | ||
406 | p[(SOF0_START + 5) - copied] = | ||
407 | 0xff & (solo_enc->height >> 8); | ||
408 | if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 6)) | ||
409 | p[(SOF0_START + 6) - copied] = 0xff & solo_enc->height; | ||
410 | if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 7)) | ||
411 | p[(SOF0_START + 7) - copied] = | ||
412 | 0xff & (solo_enc->width >> 8); | ||
413 | if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 8)) | ||
414 | p[(SOF0_START + 8) - copied] = 0xff & solo_enc->width; | ||
415 | |||
416 | copied += this_copy; | ||
417 | } | ||
418 | } | ||
419 | |||
420 | static int solo_fill_jpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf, | ||
421 | struct videobuf_buffer *vb, | ||
422 | struct videobuf_dmabuf *vbuf) | ||
423 | { | ||
424 | struct solo_dev *solo_dev = fh->enc->solo_dev; | ||
425 | int size = enc_buf->jpeg_size; | ||
426 | |||
427 | /* Copy the header first (direct write) */ | ||
428 | solo_jpeg_header(fh->enc, vbuf); | ||
429 | |||
430 | vb->size = size + sizeof(jpeg_header); | ||
431 | |||
432 | /* Grab the jpeg frame */ | ||
433 | return enc_get_jpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist, | ||
434 | sizeof(jpeg_header), | ||
435 | enc_buf->jpeg_off, size); | ||
436 | } | ||
437 | |||
438 | static inline int vop_interlaced(__le32 *vh) | ||
439 | { | ||
440 | return (__le32_to_cpu(vh[0]) >> 30) & 1; | ||
441 | } | ||
442 | |||
443 | static inline u32 vop_size(__le32 *vh) | ||
444 | { | ||
445 | return __le32_to_cpu(vh[0]) & 0xFFFFF; | ||
446 | } | ||
447 | |||
448 | static inline u8 vop_hsize(__le32 *vh) | ||
449 | { | ||
450 | return (__le32_to_cpu(vh[1]) >> 8) & 0xFF; | ||
451 | } | ||
452 | |||
453 | static inline u8 vop_vsize(__le32 *vh) | ||
454 | { | ||
455 | return __le32_to_cpu(vh[1]) & 0xFF; | ||
456 | } | ||
457 | |||
458 | /* must be called with *bits % 8 = 0 */ | ||
459 | static void write_bytes(u8 **out, unsigned *bits, const u8 *src, unsigned count) | ||
460 | { | ||
461 | memcpy(*out, src, count); | ||
462 | *out += count; | ||
463 | *bits += count * 8; | ||
464 | } | ||
465 | |||
466 | static void write_bits(u8 **out, unsigned *bits, u32 value, unsigned count) | ||
467 | { | ||
468 | |||
469 | value <<= 32 - count; // shift to the right | ||
470 | |||
471 | while (count--) { | ||
472 | **out <<= 1; | ||
473 | **out |= !!(value & (1 << 31)); /* MSB */ | ||
474 | value <<= 1; | ||
475 | if (++(*bits) % 8 == 0) | ||
476 | (*out)++; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | static void write_ue(u8 **out, unsigned *bits, unsigned value) /* H.264 only */ | ||
481 | { | ||
482 | uint32_t max = 0, cnt = 0; | ||
483 | |||
484 | while (value > max) { | ||
485 | max = (max + 2) * 2 - 2; | ||
486 | cnt++; | ||
487 | } | ||
488 | write_bits(out, bits, 1, cnt + 1); | ||
489 | write_bits(out, bits, ~(max - value), cnt); | ||
490 | } | ||
491 | |||
492 | static void write_se(u8 **out, unsigned *bits, int value) /* H.264 only */ | ||
493 | { | ||
494 | if (value <= 0) | ||
495 | write_ue(out, bits, -value * 2); | ||
496 | else | ||
497 | write_ue(out, bits, value * 2 - 1); | ||
498 | } | ||
499 | |||
500 | static void write_mpeg4_end(u8 **out, unsigned *bits) | ||
501 | { | ||
502 | write_bits(out, bits, 0, 1); | ||
503 | /* align on 32-bit boundary */ | ||
504 | if (*bits % 32) | ||
505 | write_bits(out, bits, 0xFFFFFFFF, 32 - *bits % 32); | ||
506 | } | ||
507 | |||
508 | static void write_h264_end(u8 **out, unsigned *bits, int align) | ||
509 | { | ||
510 | write_bits(out, bits, 1, 1); | ||
511 | while ((*bits) % 8) | ||
512 | write_bits(out, bits, 0, 1); | ||
513 | if (align) | ||
514 | while ((*bits) % 32) | ||
515 | write_bits(out, bits, 0, 1); | ||
516 | } | ||
517 | |||
518 | static void mpeg4_write_vol(u8 **out, struct solo_dev *solo_dev, | ||
519 | __le32 *vh, unsigned fps, unsigned interval) | ||
520 | { | ||
521 | static const u8 hdr[] = { | ||
522 | 0, 0, 1, 0x00 /* video_object_start_code */, | ||
523 | 0, 0, 1, 0x20 /* video_object_layer_start_code */ | ||
524 | }; | ||
525 | unsigned bits = 0; | ||
526 | unsigned width = vop_hsize(vh) << 4; | ||
527 | unsigned height = vop_vsize(vh) << 4; | ||
528 | unsigned interlaced = vop_interlaced(vh); | ||
529 | |||
530 | write_bytes(out, &bits, hdr, sizeof(hdr)); | ||
531 | write_bits(out, &bits, 0, 1); /* random_accessible_vol */ | ||
532 | write_bits(out, &bits, 0x04, 8); /* video_object_type_indication: main */ | ||
533 | write_bits(out, &bits, 1, 1); /* is_object_layer_identifier */ | ||
534 | write_bits(out, &bits, 2, 4); /* video_object_layer_verid: table V2-39 */ | ||
535 | write_bits(out, &bits, 0, 3); /* video_object_layer_priority */ | ||
536 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) | ||
537 | write_bits(out, &bits, 3, 4); /* aspect_ratio_info, assuming 4:3 */ | ||
538 | else | ||
539 | write_bits(out, &bits, 2, 4); | ||
540 | write_bits(out, &bits, 1, 1); /* vol_control_parameters */ | ||
541 | write_bits(out, &bits, 1, 2); /* chroma_format: 4:2:0 */ | ||
542 | write_bits(out, &bits, 1, 1); /* low_delay */ | ||
543 | write_bits(out, &bits, 0, 1); /* vbv_parameters */ | ||
544 | write_bits(out, &bits, 0, 2); /* video_object_layer_shape: rectangular */ | ||
545 | write_bits(out, &bits, 1, 1); /* marker_bit */ | ||
546 | write_bits(out, &bits, fps, 16); /* vop_time_increment_resolution */ | ||
547 | write_bits(out, &bits, 1, 1); /* marker_bit */ | ||
548 | write_bits(out, &bits, 1, 1); /* fixed_vop_rate */ | ||
549 | write_bits(out, &bits, interval, 15); /* fixed_vop_time_increment */ | ||
550 | write_bits(out, &bits, 1, 1); /* marker_bit */ | ||
551 | write_bits(out, &bits, width, 13); /* video_object_layer_width */ | ||
552 | write_bits(out, &bits, 1, 1); /* marker_bit */ | ||
553 | write_bits(out, &bits, height, 13); /* video_object_layer_height */ | ||
554 | write_bits(out, &bits, 1, 1); /* marker_bit */ | ||
555 | write_bits(out, &bits, interlaced, 1); /* interlaced */ | ||
556 | write_bits(out, &bits, 1, 1); /* obmc_disable */ | ||
557 | write_bits(out, &bits, 0, 2); /* sprite_enable */ | ||
558 | write_bits(out, &bits, 0, 1); /* not_8_bit */ | ||
559 | write_bits(out, &bits, 1, 0); /* quant_type */ | ||
560 | write_bits(out, &bits, 0, 1); /* load_intra_quant_mat */ | ||
561 | write_bits(out, &bits, 0, 1); /* load_nonintra_quant_mat */ | ||
562 | write_bits(out, &bits, 0, 1); /* quarter_sample */ | ||
563 | write_bits(out, &bits, 1, 1); /* complexity_estimation_disable */ | ||
564 | write_bits(out, &bits, 1, 1); /* resync_marker_disable */ | ||
565 | write_bits(out, &bits, 0, 1); /* data_partitioned */ | ||
566 | write_bits(out, &bits, 0, 1); /* newpred_enable */ | ||
567 | write_bits(out, &bits, 0, 1); /* reduced_resolution_vop_enable */ | ||
568 | write_bits(out, &bits, 0, 1); /* scalability */ | ||
569 | write_mpeg4_end(out, &bits); | ||
570 | } | ||
571 | |||
572 | static void h264_write_vol(u8 **out, struct solo_dev *solo_dev, __le32 *vh) | ||
573 | { | ||
574 | static const u8 sps[] = { | ||
575 | 0, 0, 0, 1 /* start code */, 0x67, 66 /* profile_idc */, | ||
576 | 0 /* constraints */, 30 /* level_idc */ | ||
577 | }; | ||
578 | static const u8 pps[] = { | ||
579 | 0, 0, 0, 1 /* start code */, 0x68 | ||
580 | }; | ||
581 | |||
582 | unsigned bits = 0; | ||
583 | unsigned mbs_w = vop_hsize(vh); | ||
584 | unsigned mbs_h = vop_vsize(vh); | ||
585 | |||
586 | write_bytes(out, &bits, sps, sizeof(sps)); | ||
587 | write_ue(out, &bits, 0); /* seq_parameter_set_id */ | ||
588 | write_ue(out, &bits, 5); /* log2_max_frame_num_minus4 */ | ||
589 | write_ue(out, &bits, 0); /* pic_order_cnt_type */ | ||
590 | write_ue(out, &bits, 6); /* log2_max_pic_order_cnt_lsb_minus4 */ | ||
591 | write_ue(out, &bits, 1); /* max_num_ref_frames */ | ||
592 | write_bits(out, &bits, 0, 1); /* gaps_in_frame_num_value_allowed_flag */ | ||
593 | write_ue(out, &bits, mbs_w - 1); /* pic_width_in_mbs_minus1 */ | ||
594 | write_ue(out, &bits, mbs_h - 1); /* pic_height_in_map_units_minus1 */ | ||
595 | write_bits(out, &bits, 1, 1); /* frame_mbs_only_flag */ | ||
596 | write_bits(out, &bits, 1, 1); /* direct_8x8_frame_field_flag */ | ||
597 | write_bits(out, &bits, 0, 1); /* frame_cropping_flag */ | ||
598 | write_bits(out, &bits, 0, 1); /* vui_parameters_present_flag */ | ||
599 | write_h264_end(out, &bits, 0); | ||
600 | |||
601 | write_bytes(out, &bits, pps, sizeof(pps)); | ||
602 | write_ue(out, &bits, 0); /* pic_parameter_set_id */ | ||
603 | write_ue(out, &bits, 0); /* seq_parameter_set_id */ | ||
604 | write_bits(out, &bits, 0, 1); /* entropy_coding_mode_flag */ | ||
605 | write_bits(out, &bits, 0, 1); /* bottom_field_pic_order_in_frame_present_flag */ | ||
606 | write_ue(out, &bits, 0); /* num_slice_groups_minus1 */ | ||
607 | write_ue(out, &bits, 0); /* num_ref_idx_l0_default_active_minus1 */ | ||
608 | write_ue(out, &bits, 0); /* num_ref_idx_l1_default_active_minus1 */ | ||
609 | write_bits(out, &bits, 0, 1); /* weighted_pred_flag */ | ||
610 | write_bits(out, &bits, 0, 2); /* weighted_bipred_idc */ | ||
611 | write_se(out, &bits, 0); /* pic_init_qp_minus26 */ | ||
612 | write_se(out, &bits, 0); /* pic_init_qs_minus26 */ | ||
613 | write_se(out, &bits, 2); /* chroma_qp_index_offset */ | ||
614 | write_bits(out, &bits, 0, 1); /* deblocking_filter_control_present_flag */ | ||
615 | write_bits(out, &bits, 1, 1); /* constrained_intra_pred_flag */ | ||
616 | write_bits(out, &bits, 0, 1); /* redundant_pic_cnt_present_flag */ | ||
617 | write_h264_end(out, &bits, 1); | ||
618 | } | ||
619 | |||
620 | static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf, | ||
621 | struct videobuf_buffer *vb, | ||
622 | struct videobuf_dmabuf *vbuf) | ||
623 | { | ||
624 | struct solo_enc_dev *solo_enc = fh->enc; | ||
625 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
626 | |||
627 | #define VH_WORDS 16 | ||
628 | #define MAX_VOL_HEADER_LENGTH 64 | ||
629 | |||
630 | __le32 vh[VH_WORDS]; | ||
631 | int ret; | ||
632 | int frame_size, frame_off; | ||
633 | int skip = 0; | ||
634 | |||
635 | if (WARN_ON_ONCE(enc_buf->size <= sizeof(vh))) | ||
636 | return -EINVAL; | ||
637 | |||
638 | /* First get the hardware vop header (not real mpeg) */ | ||
639 | ret = enc_get_mpeg_dma(solo_dev, vh, enc_buf->off, sizeof(vh)); | ||
640 | if (WARN_ON_ONCE(ret)) | ||
641 | return ret; | ||
642 | |||
643 | if (WARN_ON_ONCE(vop_size(vh) > enc_buf->size)) | ||
644 | return -EINVAL; | ||
645 | |||
646 | vb->width = vop_hsize(vh) << 4; | ||
647 | vb->height = vop_vsize(vh) << 4; | ||
648 | vb->size = vop_size(vh); | ||
649 | |||
650 | /* If this is a key frame, add extra m4v header */ | ||
651 | if (!enc_buf->vop) { | ||
652 | u8 header[MAX_VOL_HEADER_LENGTH], *out = header; | ||
653 | |||
654 | if (solo_dev->flags & FLAGS_6110) | ||
655 | h264_write_vol(&out, solo_dev, vh); | ||
656 | else | ||
657 | mpeg4_write_vol(&out, solo_dev, vh, | ||
658 | solo_dev->fps * 1000, | ||
659 | solo_enc->interval * 1000); | ||
660 | skip = out - header; | ||
661 | enc_write_sg(vbuf->sglist, header, skip); | ||
662 | /* Adjust the dma buffer past this header */ | ||
663 | vb->size += skip; | ||
664 | } | ||
665 | |||
666 | /* Now get the actual mpeg payload */ | ||
667 | frame_off = (enc_buf->off + sizeof(vh)) % SOLO_MP4E_EXT_SIZE(solo_dev); | ||
668 | frame_size = enc_buf->size - sizeof(vh); | ||
669 | |||
670 | ret = enc_get_mpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist, | ||
671 | skip, frame_off, frame_size); | ||
672 | WARN_ON_ONCE(ret); | ||
673 | |||
674 | return ret; | ||
675 | } | ||
676 | |||
677 | static void solo_enc_fillbuf(struct solo_enc_fh *fh, | ||
678 | struct videobuf_buffer *vb) | ||
679 | { | ||
680 | struct solo_enc_dev *solo_enc = fh->enc; | ||
681 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
682 | struct solo_enc_buf *enc_buf = NULL; | ||
683 | struct videobuf_dmabuf *vbuf; | ||
684 | int ret; | ||
685 | int error = 1; | ||
686 | u16 idx = fh->rd_idx; | ||
687 | |||
688 | while (idx != solo_dev->enc_wr_idx) { | ||
689 | struct solo_enc_buf *ebuf = &solo_dev->enc_buf[idx]; | ||
690 | |||
691 | idx = (idx + 1) % SOLO_NR_RING_BUFS; | ||
692 | |||
693 | if (ebuf->ch != solo_enc->ch) | ||
694 | continue; | ||
695 | |||
696 | if (fh->fmt == V4L2_PIX_FMT_MPEG) { | ||
697 | if (fh->type == ebuf->type) { | ||
698 | enc_buf = ebuf; | ||
699 | break; | ||
700 | } | ||
701 | } else { | ||
702 | /* For mjpeg, keep reading to the newest frame */ | ||
703 | enc_buf = ebuf; | ||
704 | } | ||
705 | } | ||
706 | |||
707 | fh->rd_idx = idx; | ||
708 | |||
709 | if (WARN_ON_ONCE(!enc_buf)) | ||
710 | goto buf_err; | ||
711 | |||
712 | if ((fh->fmt == V4L2_PIX_FMT_MPEG && | ||
713 | vb->bsize < enc_buf->size) || | ||
714 | (fh->fmt == V4L2_PIX_FMT_MJPEG && | ||
715 | vb->bsize < (enc_buf->jpeg_size + sizeof(jpeg_header)))) { | ||
716 | WARN_ON_ONCE(1); | ||
717 | goto buf_err; | ||
718 | } | ||
719 | |||
720 | vbuf = videobuf_to_dma(vb); | ||
721 | if (WARN_ON_ONCE(!vbuf)) | ||
722 | goto buf_err; | ||
723 | |||
724 | if (fh->fmt == V4L2_PIX_FMT_MPEG) | ||
725 | ret = solo_fill_mpeg(fh, enc_buf, vb, vbuf); | ||
726 | else | ||
727 | ret = solo_fill_jpeg(fh, enc_buf, vb, vbuf); | ||
728 | |||
729 | if (!ret) | ||
730 | error = 0; | ||
731 | |||
732 | buf_err: | ||
733 | if (error) { | ||
734 | vb->state = VIDEOBUF_ERROR; | ||
735 | } else { | ||
736 | vb->field_count++; | ||
737 | vb->ts = enc_buf->ts; | ||
738 | vb->state = VIDEOBUF_DONE; | ||
739 | } | ||
740 | |||
741 | wake_up(&vb->done); | ||
742 | |||
743 | return; | ||
744 | } | ||
745 | |||
746 | static void solo_enc_thread_try(struct solo_enc_fh *fh) | ||
747 | { | ||
748 | struct solo_enc_dev *solo_enc = fh->enc; | ||
749 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
750 | struct videobuf_buffer *vb; | ||
751 | |||
752 | for (;;) { | ||
753 | spin_lock(&solo_enc->lock); | ||
754 | |||
755 | if (fh->rd_idx == solo_dev->enc_wr_idx) | ||
756 | break; | ||
757 | |||
758 | if (list_empty(&fh->vidq_active)) | ||
759 | break; | ||
760 | |||
761 | vb = list_first_entry(&fh->vidq_active, | ||
762 | struct videobuf_buffer, queue); | ||
763 | |||
764 | if (!waitqueue_active(&vb->done)) | ||
765 | break; | ||
766 | |||
767 | list_del(&vb->queue); | ||
768 | |||
769 | spin_unlock(&solo_enc->lock); | ||
770 | |||
771 | solo_enc_fillbuf(fh, vb); | ||
772 | } | ||
773 | |||
774 | assert_spin_locked(&solo_enc->lock); | ||
775 | spin_unlock(&solo_enc->lock); | ||
776 | } | ||
777 | |||
778 | static int solo_enc_thread(void *data) | ||
779 | { | ||
780 | struct solo_enc_fh *fh = data; | ||
781 | struct solo_enc_dev *solo_enc = fh->enc; | ||
782 | DECLARE_WAITQUEUE(wait, current); | ||
783 | |||
784 | set_freezable(); | ||
785 | add_wait_queue(&solo_enc->thread_wait, &wait); | ||
786 | |||
787 | for (;;) { | ||
788 | long timeout = schedule_timeout_interruptible(HZ); | ||
789 | if (timeout == -ERESTARTSYS || kthread_should_stop()) | ||
790 | break; | ||
791 | solo_enc_thread_try(fh); | ||
792 | try_to_freeze(); | ||
793 | } | ||
794 | |||
795 | remove_wait_queue(&solo_enc->thread_wait, &wait); | ||
796 | |||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | void solo_motion_isr(struct solo_dev *solo_dev) | ||
801 | { | ||
802 | u32 status; | ||
803 | int i; | ||
804 | |||
805 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_MOTION); | ||
806 | |||
807 | status = solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS); | ||
808 | |||
809 | for (i = 0; i < solo_dev->nr_chans; i++) { | ||
810 | struct solo_enc_dev *solo_enc = solo_dev->v4l2_enc[i]; | ||
811 | |||
812 | BUG_ON(solo_enc == NULL); | ||
813 | |||
814 | if (solo_enc->motion_detected) | ||
815 | continue; | ||
816 | if (!(status & (1 << i))) | ||
817 | continue; | ||
818 | |||
819 | solo_enc->motion_detected = 1; | ||
820 | } | ||
821 | } | ||
822 | |||
823 | void solo_enc_v4l2_isr(struct solo_dev *solo_dev) | ||
824 | { | ||
825 | struct solo_enc_buf *enc_buf; | ||
826 | u32 mpeg_current, mpeg_next, mpeg_size; | ||
827 | u32 jpeg_current, jpeg_next, jpeg_size; | ||
828 | u32 reg_mpeg_size; | ||
829 | u8 cur_q, vop_type; | ||
830 | u8 ch; | ||
831 | enum solo_enc_types enc_type; | ||
832 | |||
833 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_ENCODER); | ||
834 | |||
835 | cur_q = ((solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xF) + 1) % MP4_QS; | ||
836 | |||
837 | reg_mpeg_size = ((solo_reg_read(solo_dev, SOLO_VE_STATE(0)) & 0xFFFFF) + 64 + 8) & ~7; | ||
838 | |||
839 | while (solo_dev->enc_idx != cur_q) { | ||
840 | mpeg_current = solo_reg_read(solo_dev, | ||
841 | SOLO_VE_MPEG4_QUE(solo_dev->enc_idx)); | ||
842 | jpeg_current = solo_reg_read(solo_dev, | ||
843 | SOLO_VE_JPEG_QUE(solo_dev->enc_idx)); | ||
844 | solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS; | ||
845 | mpeg_next = solo_reg_read(solo_dev, | ||
846 | SOLO_VE_MPEG4_QUE(solo_dev->enc_idx)); | ||
847 | jpeg_next = solo_reg_read(solo_dev, | ||
848 | SOLO_VE_JPEG_QUE(solo_dev->enc_idx)); | ||
849 | |||
850 | ch = (mpeg_current >> 24) & 0x1f; | ||
851 | if (ch >= SOLO_MAX_CHANNELS) { | ||
852 | ch -= SOLO_MAX_CHANNELS; | ||
853 | enc_type = SOLO_ENC_TYPE_EXT; | ||
854 | } else | ||
855 | enc_type = SOLO_ENC_TYPE_STD; | ||
856 | |||
857 | vop_type = (mpeg_current >> 29) & 3; | ||
858 | |||
859 | mpeg_current &= 0x00ffffff; | ||
860 | mpeg_next &= 0x00ffffff; | ||
861 | jpeg_current &= 0x00ffffff; | ||
862 | jpeg_next &= 0x00ffffff; | ||
863 | |||
864 | mpeg_size = (SOLO_MP4E_EXT_SIZE(solo_dev) + | ||
865 | mpeg_next - mpeg_current) % | ||
866 | SOLO_MP4E_EXT_SIZE(solo_dev); | ||
867 | |||
868 | jpeg_size = (SOLO_JPEG_EXT_SIZE(solo_dev) + | ||
869 | jpeg_next - jpeg_current) % | ||
870 | SOLO_JPEG_EXT_SIZE(solo_dev); | ||
871 | |||
872 | /* XXX I think this means we had a ring overflow? */ | ||
873 | if (mpeg_current > mpeg_next && mpeg_size != reg_mpeg_size) { | ||
874 | enc_reset_gop(solo_dev, ch); | ||
875 | continue; | ||
876 | } | ||
877 | |||
878 | /* When resetting the GOP, skip frames until I-frame */ | ||
879 | if (enc_gop_reset(solo_dev, ch, vop_type)) | ||
880 | continue; | ||
881 | |||
882 | enc_buf = &solo_dev->enc_buf[solo_dev->enc_wr_idx]; | ||
883 | |||
884 | enc_buf->vop = vop_type; | ||
885 | enc_buf->ch = ch; | ||
886 | enc_buf->off = mpeg_current; | ||
887 | enc_buf->size = mpeg_size; | ||
888 | enc_buf->jpeg_off = jpeg_current; | ||
889 | enc_buf->jpeg_size = jpeg_size; | ||
890 | enc_buf->type = enc_type; | ||
891 | |||
892 | do_gettimeofday(&enc_buf->ts); | ||
893 | |||
894 | solo_dev->enc_wr_idx = (solo_dev->enc_wr_idx + 1) % | ||
895 | SOLO_NR_RING_BUFS; | ||
896 | |||
897 | wake_up_interruptible(&solo_dev->v4l2_enc[ch]->thread_wait); | ||
898 | } | ||
899 | |||
900 | return; | ||
901 | } | ||
902 | |||
903 | static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count, | ||
904 | unsigned int *size) | ||
905 | { | ||
906 | *size = FRAME_BUF_SIZE; | ||
907 | |||
908 | if (*count < MIN_VID_BUFFERS) | ||
909 | *count = MIN_VID_BUFFERS; | ||
910 | |||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | static int solo_enc_buf_prepare(struct videobuf_queue *vq, | ||
915 | struct videobuf_buffer *vb, | ||
916 | enum v4l2_field field) | ||
917 | { | ||
918 | struct solo_enc_fh *fh = vq->priv_data; | ||
919 | struct solo_enc_dev *solo_enc = fh->enc; | ||
920 | |||
921 | vb->size = FRAME_BUF_SIZE; | ||
922 | if (vb->baddr != 0 && vb->bsize < vb->size) | ||
923 | return -EINVAL; | ||
924 | |||
925 | /* These properties only change when queue is idle */ | ||
926 | vb->width = solo_enc->width; | ||
927 | vb->height = solo_enc->height; | ||
928 | vb->field = field; | ||
929 | |||
930 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | ||
931 | int rc = videobuf_iolock(vq, vb, NULL); | ||
932 | if (rc < 0) { | ||
933 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | ||
934 | videobuf_dma_unmap(vq->dev, dma); | ||
935 | videobuf_dma_free(dma); | ||
936 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
937 | return rc; | ||
938 | } | ||
939 | } | ||
940 | vb->state = VIDEOBUF_PREPARED; | ||
941 | |||
942 | return 0; | ||
943 | } | ||
944 | |||
945 | static void solo_enc_buf_queue(struct videobuf_queue *vq, | ||
946 | struct videobuf_buffer *vb) | ||
947 | { | ||
948 | struct solo_enc_fh *fh = vq->priv_data; | ||
949 | |||
950 | vb->state = VIDEOBUF_QUEUED; | ||
951 | list_add_tail(&vb->queue, &fh->vidq_active); | ||
952 | wake_up_interruptible(&fh->enc->thread_wait); | ||
953 | } | ||
954 | |||
955 | static void solo_enc_buf_release(struct videobuf_queue *vq, | ||
956 | struct videobuf_buffer *vb) | ||
957 | { | ||
958 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | ||
959 | |||
960 | videobuf_dma_unmap(vq->dev, dma); | ||
961 | videobuf_dma_free(dma); | ||
962 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
963 | } | ||
964 | |||
965 | static struct videobuf_queue_ops solo_enc_video_qops = { | ||
966 | .buf_setup = solo_enc_buf_setup, | ||
967 | .buf_prepare = solo_enc_buf_prepare, | ||
968 | .buf_queue = solo_enc_buf_queue, | ||
969 | .buf_release = solo_enc_buf_release, | ||
970 | }; | ||
971 | |||
972 | static unsigned int solo_enc_poll(struct file *file, | ||
973 | struct poll_table_struct *wait) | ||
974 | { | ||
975 | struct solo_enc_fh *fh = file->private_data; | ||
976 | |||
977 | return videobuf_poll_stream(file, &fh->vidq, wait); | ||
978 | } | ||
979 | |||
980 | static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma) | ||
981 | { | ||
982 | struct solo_enc_fh *fh = file->private_data; | ||
983 | |||
984 | return videobuf_mmap_mapper(&fh->vidq, vma); | ||
985 | } | ||
986 | |||
987 | static int solo_enc_open(struct file *file) | ||
988 | { | ||
989 | struct solo_enc_dev *solo_enc = video_drvdata(file); | ||
990 | struct solo_enc_fh *fh; | ||
991 | |||
992 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
993 | if (fh == NULL) | ||
994 | return -ENOMEM; | ||
995 | |||
996 | fh->enc = solo_enc; | ||
997 | file->private_data = fh; | ||
998 | INIT_LIST_HEAD(&fh->vidq_active); | ||
999 | fh->fmt = V4L2_PIX_FMT_MPEG; | ||
1000 | fh->type = SOLO_ENC_TYPE_STD; | ||
1001 | |||
1002 | videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops, | ||
1003 | &solo_enc->solo_dev->pdev->dev, | ||
1004 | &solo_enc->lock, | ||
1005 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1006 | V4L2_FIELD_INTERLACED, | ||
1007 | sizeof(struct videobuf_buffer), fh, NULL); | ||
1008 | |||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
1012 | static ssize_t solo_enc_read(struct file *file, char __user *data, | ||
1013 | size_t count, loff_t *ppos) | ||
1014 | { | ||
1015 | struct solo_enc_fh *fh = file->private_data; | ||
1016 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1017 | |||
1018 | /* Make sure the encoder is on */ | ||
1019 | if (!fh->enc_on) { | ||
1020 | int ret; | ||
1021 | |||
1022 | spin_lock(&solo_enc->lock); | ||
1023 | ret = solo_enc_on(fh); | ||
1024 | spin_unlock(&solo_enc->lock); | ||
1025 | if (ret) | ||
1026 | return ret; | ||
1027 | |||
1028 | ret = solo_start_fh_thread(fh); | ||
1029 | if (ret) | ||
1030 | return ret; | ||
1031 | } | ||
1032 | |||
1033 | return videobuf_read_stream(&fh->vidq, data, count, ppos, 0, | ||
1034 | file->f_flags & O_NONBLOCK); | ||
1035 | } | ||
1036 | |||
1037 | static int solo_enc_release(struct file *file) | ||
1038 | { | ||
1039 | struct solo_enc_fh *fh = file->private_data; | ||
1040 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1041 | |||
1042 | videobuf_stop(&fh->vidq); | ||
1043 | videobuf_mmap_free(&fh->vidq); | ||
1044 | |||
1045 | spin_lock(&solo_enc->lock); | ||
1046 | solo_enc_off(fh); | ||
1047 | spin_unlock(&solo_enc->lock); | ||
1048 | |||
1049 | kfree(fh); | ||
1050 | |||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
1054 | static int solo_enc_querycap(struct file *file, void *priv, | ||
1055 | struct v4l2_capability *cap) | ||
1056 | { | ||
1057 | struct solo_enc_fh *fh = priv; | ||
1058 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1059 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1060 | |||
1061 | strcpy(cap->driver, SOLO6X10_NAME); | ||
1062 | snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d", | ||
1063 | solo_enc->ch); | ||
1064 | snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s", | ||
1065 | pci_name(solo_dev->pdev)); | ||
1066 | cap->version = SOLO6X10_VER_NUM; | ||
1067 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | | ||
1068 | V4L2_CAP_READWRITE | | ||
1069 | V4L2_CAP_STREAMING; | ||
1070 | return 0; | ||
1071 | } | ||
1072 | |||
1073 | static int solo_enc_enum_input(struct file *file, void *priv, | ||
1074 | struct v4l2_input *input) | ||
1075 | { | ||
1076 | struct solo_enc_fh *fh = priv; | ||
1077 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1078 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1079 | |||
1080 | if (input->index) | ||
1081 | return -EINVAL; | ||
1082 | |||
1083 | snprintf(input->name, sizeof(input->name), "Encoder %d", | ||
1084 | solo_enc->ch + 1); | ||
1085 | input->type = V4L2_INPUT_TYPE_CAMERA; | ||
1086 | |||
1087 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) | ||
1088 | input->std = V4L2_STD_NTSC_M; | ||
1089 | else | ||
1090 | input->std = V4L2_STD_PAL_B; | ||
1091 | |||
1092 | if (!tw28_get_video_status(solo_dev, solo_enc->ch)) | ||
1093 | input->status = V4L2_IN_ST_NO_SIGNAL; | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | static int solo_enc_set_input(struct file *file, void *priv, unsigned int index) | ||
1099 | { | ||
1100 | if (index) | ||
1101 | return -EINVAL; | ||
1102 | |||
1103 | return 0; | ||
1104 | } | ||
1105 | |||
1106 | static int solo_enc_get_input(struct file *file, void *priv, | ||
1107 | unsigned int *index) | ||
1108 | { | ||
1109 | *index = 0; | ||
1110 | |||
1111 | return 0; | ||
1112 | } | ||
1113 | |||
1114 | static int solo_enc_enum_fmt_cap(struct file *file, void *priv, | ||
1115 | struct v4l2_fmtdesc *f) | ||
1116 | { | ||
1117 | switch (f->index) { | ||
1118 | case 0: | ||
1119 | f->pixelformat = V4L2_PIX_FMT_MPEG; | ||
1120 | strcpy(f->description, "MPEG-4 AVC"); | ||
1121 | break; | ||
1122 | case 1: | ||
1123 | f->pixelformat = V4L2_PIX_FMT_MJPEG; | ||
1124 | strcpy(f->description, "MJPEG"); | ||
1125 | break; | ||
1126 | default: | ||
1127 | return -EINVAL; | ||
1128 | } | ||
1129 | |||
1130 | f->flags = V4L2_FMT_FLAG_COMPRESSED; | ||
1131 | |||
1132 | return 0; | ||
1133 | } | ||
1134 | |||
1135 | static int solo_enc_try_fmt_cap(struct file *file, void *priv, | ||
1136 | struct v4l2_format *f) | ||
1137 | { | ||
1138 | struct solo_enc_fh *fh = priv; | ||
1139 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1140 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1141 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1142 | |||
1143 | if (pix->pixelformat != V4L2_PIX_FMT_MPEG && | ||
1144 | pix->pixelformat != V4L2_PIX_FMT_MJPEG) | ||
1145 | return -EINVAL; | ||
1146 | |||
1147 | /* We cannot change width/height in mid read */ | ||
1148 | if (atomic_read(&solo_enc->readers) > 0) { | ||
1149 | if (pix->width != solo_enc->width || | ||
1150 | pix->height != solo_enc->height) | ||
1151 | return -EBUSY; | ||
1152 | } | ||
1153 | |||
1154 | if (pix->width < solo_dev->video_hsize || | ||
1155 | pix->height < solo_dev->video_vsize << 1) { | ||
1156 | /* Default to CIF 1/2 size */ | ||
1157 | pix->width = solo_dev->video_hsize >> 1; | ||
1158 | pix->height = solo_dev->video_vsize; | ||
1159 | } else { | ||
1160 | /* Full frame */ | ||
1161 | pix->width = solo_dev->video_hsize; | ||
1162 | pix->height = solo_dev->video_vsize << 1; | ||
1163 | } | ||
1164 | |||
1165 | if (pix->field == V4L2_FIELD_ANY) | ||
1166 | pix->field = V4L2_FIELD_INTERLACED; | ||
1167 | else if (pix->field != V4L2_FIELD_INTERLACED) | ||
1168 | pix->field = V4L2_FIELD_INTERLACED; | ||
1169 | |||
1170 | /* Just set these */ | ||
1171 | pix->colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
1172 | pix->sizeimage = FRAME_BUF_SIZE; | ||
1173 | |||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | static int solo_enc_set_fmt_cap(struct file *file, void *priv, | ||
1178 | struct v4l2_format *f) | ||
1179 | { | ||
1180 | struct solo_enc_fh *fh = priv; | ||
1181 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1182 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1183 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1184 | int ret; | ||
1185 | |||
1186 | spin_lock(&solo_enc->lock); | ||
1187 | |||
1188 | ret = solo_enc_try_fmt_cap(file, priv, f); | ||
1189 | if (ret) { | ||
1190 | spin_unlock(&solo_enc->lock); | ||
1191 | return ret; | ||
1192 | } | ||
1193 | |||
1194 | if (pix->width == solo_dev->video_hsize) | ||
1195 | solo_enc->mode = SOLO_ENC_MODE_D1; | ||
1196 | else | ||
1197 | solo_enc->mode = SOLO_ENC_MODE_CIF; | ||
1198 | |||
1199 | /* This does not change the encoder at all */ | ||
1200 | fh->fmt = pix->pixelformat; | ||
1201 | |||
1202 | if (pix->priv) | ||
1203 | fh->type = SOLO_ENC_TYPE_EXT; | ||
1204 | ret = solo_enc_on(fh); | ||
1205 | |||
1206 | spin_unlock(&solo_enc->lock); | ||
1207 | |||
1208 | if (ret) | ||
1209 | return ret; | ||
1210 | |||
1211 | return solo_start_fh_thread(fh); | ||
1212 | } | ||
1213 | |||
1214 | static int solo_enc_get_fmt_cap(struct file *file, void *priv, | ||
1215 | struct v4l2_format *f) | ||
1216 | { | ||
1217 | struct solo_enc_fh *fh = priv; | ||
1218 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1219 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1220 | |||
1221 | pix->width = solo_enc->width; | ||
1222 | pix->height = solo_enc->height; | ||
1223 | pix->pixelformat = fh->fmt; | ||
1224 | pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED : | ||
1225 | V4L2_FIELD_NONE; | ||
1226 | pix->sizeimage = FRAME_BUF_SIZE; | ||
1227 | pix->colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
1228 | |||
1229 | return 0; | ||
1230 | } | ||
1231 | |||
1232 | static int solo_enc_reqbufs(struct file *file, void *priv, | ||
1233 | struct v4l2_requestbuffers *req) | ||
1234 | { | ||
1235 | struct solo_enc_fh *fh = priv; | ||
1236 | |||
1237 | return videobuf_reqbufs(&fh->vidq, req); | ||
1238 | } | ||
1239 | |||
1240 | static int solo_enc_querybuf(struct file *file, void *priv, | ||
1241 | struct v4l2_buffer *buf) | ||
1242 | { | ||
1243 | struct solo_enc_fh *fh = priv; | ||
1244 | |||
1245 | return videobuf_querybuf(&fh->vidq, buf); | ||
1246 | } | ||
1247 | |||
1248 | static int solo_enc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
1249 | { | ||
1250 | struct solo_enc_fh *fh = priv; | ||
1251 | |||
1252 | return videobuf_qbuf(&fh->vidq, buf); | ||
1253 | } | ||
1254 | |||
1255 | static int solo_enc_dqbuf(struct file *file, void *priv, | ||
1256 | struct v4l2_buffer *buf) | ||
1257 | { | ||
1258 | struct solo_enc_fh *fh = priv; | ||
1259 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1260 | int ret; | ||
1261 | |||
1262 | /* Make sure the encoder is on */ | ||
1263 | if (!fh->enc_on) { | ||
1264 | spin_lock(&solo_enc->lock); | ||
1265 | ret = solo_enc_on(fh); | ||
1266 | spin_unlock(&solo_enc->lock); | ||
1267 | if (ret) | ||
1268 | return ret; | ||
1269 | |||
1270 | ret = solo_start_fh_thread(fh); | ||
1271 | if (ret) | ||
1272 | return ret; | ||
1273 | } | ||
1274 | |||
1275 | ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK); | ||
1276 | if (ret) | ||
1277 | return ret; | ||
1278 | |||
1279 | /* Signal motion detection */ | ||
1280 | if (solo_is_motion_on(solo_enc)) { | ||
1281 | buf->flags |= V4L2_BUF_FLAG_MOTION_ON; | ||
1282 | if (solo_enc->motion_detected) { | ||
1283 | buf->flags |= V4L2_BUF_FLAG_MOTION_DETECTED; | ||
1284 | solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR, | ||
1285 | 1 << solo_enc->ch); | ||
1286 | solo_enc->motion_detected = 0; | ||
1287 | } | ||
1288 | } | ||
1289 | |||
1290 | /* Check for key frame on mpeg data */ | ||
1291 | if (fh->fmt == V4L2_PIX_FMT_MPEG) { | ||
1292 | struct videobuf_dmabuf *vbuf = | ||
1293 | videobuf_to_dma(fh->vidq.bufs[buf->index]); | ||
1294 | |||
1295 | if (vbuf) { | ||
1296 | u8 *p = sg_virt(vbuf->sglist); | ||
1297 | if (p[3] == 0x00) | ||
1298 | buf->flags |= V4L2_BUF_FLAG_KEYFRAME; | ||
1299 | else | ||
1300 | buf->flags |= V4L2_BUF_FLAG_PFRAME; | ||
1301 | } | ||
1302 | } | ||
1303 | |||
1304 | return 0; | ||
1305 | } | ||
1306 | |||
1307 | static int solo_enc_streamon(struct file *file, void *priv, | ||
1308 | enum v4l2_buf_type i) | ||
1309 | { | ||
1310 | struct solo_enc_fh *fh = priv; | ||
1311 | |||
1312 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1313 | return -EINVAL; | ||
1314 | |||
1315 | return videobuf_streamon(&fh->vidq); | ||
1316 | } | ||
1317 | |||
1318 | static int solo_enc_streamoff(struct file *file, void *priv, | ||
1319 | enum v4l2_buf_type i) | ||
1320 | { | ||
1321 | struct solo_enc_fh *fh = priv; | ||
1322 | |||
1323 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1324 | return -EINVAL; | ||
1325 | |||
1326 | return videobuf_streamoff(&fh->vidq); | ||
1327 | } | ||
1328 | |||
1329 | static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id *i) | ||
1330 | { | ||
1331 | return 0; | ||
1332 | } | ||
1333 | |||
1334 | static int solo_enum_framesizes(struct file *file, void *priv, | ||
1335 | struct v4l2_frmsizeenum *fsize) | ||
1336 | { | ||
1337 | struct solo_enc_fh *fh = priv; | ||
1338 | struct solo_dev *solo_dev = fh->enc->solo_dev; | ||
1339 | |||
1340 | if (fsize->pixel_format != V4L2_PIX_FMT_MPEG) | ||
1341 | return -EINVAL; | ||
1342 | |||
1343 | switch (fsize->index) { | ||
1344 | case 0: | ||
1345 | fsize->discrete.width = solo_dev->video_hsize >> 1; | ||
1346 | fsize->discrete.height = solo_dev->video_vsize; | ||
1347 | break; | ||
1348 | case 1: | ||
1349 | fsize->discrete.width = solo_dev->video_hsize; | ||
1350 | fsize->discrete.height = solo_dev->video_vsize << 1; | ||
1351 | break; | ||
1352 | default: | ||
1353 | return -EINVAL; | ||
1354 | } | ||
1355 | |||
1356 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
1357 | |||
1358 | return 0; | ||
1359 | } | ||
1360 | |||
1361 | static int solo_enum_frameintervals(struct file *file, void *priv, | ||
1362 | struct v4l2_frmivalenum *fintv) | ||
1363 | { | ||
1364 | struct solo_enc_fh *fh = priv; | ||
1365 | struct solo_dev *solo_dev = fh->enc->solo_dev; | ||
1366 | |||
1367 | if (fintv->pixel_format != V4L2_PIX_FMT_MPEG || fintv->index) | ||
1368 | return -EINVAL; | ||
1369 | |||
1370 | fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE; | ||
1371 | |||
1372 | fintv->stepwise.min.numerator = solo_dev->fps; | ||
1373 | fintv->stepwise.min.denominator = 1; | ||
1374 | |||
1375 | fintv->stepwise.max.numerator = solo_dev->fps; | ||
1376 | fintv->stepwise.max.denominator = 15; | ||
1377 | |||
1378 | fintv->stepwise.step.numerator = 1; | ||
1379 | fintv->stepwise.step.denominator = 1; | ||
1380 | |||
1381 | return 0; | ||
1382 | } | ||
1383 | |||
1384 | static int solo_g_parm(struct file *file, void *priv, | ||
1385 | struct v4l2_streamparm *sp) | ||
1386 | { | ||
1387 | struct solo_enc_fh *fh = priv; | ||
1388 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1389 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1390 | struct v4l2_captureparm *cp = &sp->parm.capture; | ||
1391 | |||
1392 | cp->capability = V4L2_CAP_TIMEPERFRAME; | ||
1393 | cp->timeperframe.numerator = solo_enc->interval; | ||
1394 | cp->timeperframe.denominator = solo_dev->fps; | ||
1395 | cp->capturemode = 0; | ||
1396 | /* XXX: Shouldn't we be able to get/set this from videobuf? */ | ||
1397 | cp->readbuffers = 2; | ||
1398 | |||
1399 | return 0; | ||
1400 | } | ||
1401 | |||
1402 | static int solo_s_parm(struct file *file, void *priv, | ||
1403 | struct v4l2_streamparm *sp) | ||
1404 | { | ||
1405 | struct solo_enc_fh *fh = priv; | ||
1406 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1407 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1408 | struct v4l2_captureparm *cp = &sp->parm.capture; | ||
1409 | |||
1410 | spin_lock(&solo_enc->lock); | ||
1411 | |||
1412 | if (atomic_read(&solo_enc->readers) > 0) { | ||
1413 | spin_unlock(&solo_enc->lock); | ||
1414 | return -EBUSY; | ||
1415 | } | ||
1416 | |||
1417 | if ((cp->timeperframe.numerator == 0) || | ||
1418 | (cp->timeperframe.denominator == 0)) { | ||
1419 | /* reset framerate */ | ||
1420 | cp->timeperframe.numerator = 1; | ||
1421 | cp->timeperframe.denominator = solo_dev->fps; | ||
1422 | } | ||
1423 | |||
1424 | if (cp->timeperframe.denominator != solo_dev->fps) | ||
1425 | cp->timeperframe.denominator = solo_dev->fps; | ||
1426 | |||
1427 | if (cp->timeperframe.numerator > 15) | ||
1428 | cp->timeperframe.numerator = 15; | ||
1429 | |||
1430 | solo_enc->interval = cp->timeperframe.numerator; | ||
1431 | |||
1432 | cp->capability = V4L2_CAP_TIMEPERFRAME; | ||
1433 | |||
1434 | solo_enc->gop = max(solo_dev->fps / solo_enc->interval, 1); | ||
1435 | solo_update_mode(solo_enc); | ||
1436 | |||
1437 | spin_unlock(&solo_enc->lock); | ||
1438 | |||
1439 | return 0; | ||
1440 | } | ||
1441 | |||
1442 | static int solo_queryctrl(struct file *file, void *priv, | ||
1443 | struct v4l2_queryctrl *qc) | ||
1444 | { | ||
1445 | struct solo_enc_fh *fh = priv; | ||
1446 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1447 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1448 | |||
1449 | qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id); | ||
1450 | if (!qc->id) | ||
1451 | return -EINVAL; | ||
1452 | |||
1453 | switch (qc->id) { | ||
1454 | case V4L2_CID_BRIGHTNESS: | ||
1455 | case V4L2_CID_CONTRAST: | ||
1456 | case V4L2_CID_SATURATION: | ||
1457 | case V4L2_CID_HUE: | ||
1458 | return v4l2_ctrl_query_fill(qc, 0x00, 0xff, 1, 0x80); | ||
1459 | case V4L2_CID_SHARPNESS: | ||
1460 | return v4l2_ctrl_query_fill(qc, 0x00, 0x0f, 1, 0x00); | ||
1461 | case V4L2_CID_MPEG_VIDEO_ENCODING: | ||
1462 | return v4l2_ctrl_query_fill( | ||
1463 | qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_1, | ||
1464 | V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1, | ||
1465 | V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); | ||
1466 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
1467 | return v4l2_ctrl_query_fill(qc, 1, 255, 1, solo_dev->fps); | ||
1468 | #ifdef PRIVATE_CIDS | ||
1469 | case V4L2_CID_MOTION_THRESHOLD: | ||
1470 | qc->flags |= V4L2_CTRL_FLAG_SLIDER; | ||
1471 | qc->type = V4L2_CTRL_TYPE_INTEGER; | ||
1472 | qc->minimum = 0; | ||
1473 | qc->maximum = 0xffff; | ||
1474 | qc->step = 1; | ||
1475 | qc->default_value = SOLO_DEF_MOT_THRESH; | ||
1476 | strlcpy(qc->name, "Motion Detection Threshold", | ||
1477 | sizeof(qc->name)); | ||
1478 | return 0; | ||
1479 | case V4L2_CID_MOTION_ENABLE: | ||
1480 | qc->type = V4L2_CTRL_TYPE_BOOLEAN; | ||
1481 | qc->minimum = 0; | ||
1482 | qc->maximum = qc->step = 1; | ||
1483 | qc->default_value = 0; | ||
1484 | strlcpy(qc->name, "Motion Detection Enable", sizeof(qc->name)); | ||
1485 | return 0; | ||
1486 | #else | ||
1487 | case V4L2_CID_MOTION_THRESHOLD: | ||
1488 | return v4l2_ctrl_query_fill(qc, 0, 0xffff, 1, | ||
1489 | SOLO_DEF_MOT_THRESH); | ||
1490 | case V4L2_CID_MOTION_ENABLE: | ||
1491 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
1492 | #endif | ||
1493 | case V4L2_CID_RDS_TX_RADIO_TEXT: | ||
1494 | qc->type = V4L2_CTRL_TYPE_STRING; | ||
1495 | qc->minimum = 0; | ||
1496 | qc->maximum = OSD_TEXT_MAX; | ||
1497 | qc->step = 1; | ||
1498 | qc->default_value = 0; | ||
1499 | strlcpy(qc->name, "OSD Text", sizeof(qc->name)); | ||
1500 | return 0; | ||
1501 | } | ||
1502 | |||
1503 | return -EINVAL; | ||
1504 | } | ||
1505 | |||
1506 | static int solo_querymenu(struct file *file, void *priv, | ||
1507 | struct v4l2_querymenu *qmenu) | ||
1508 | { | ||
1509 | struct v4l2_queryctrl qctrl; | ||
1510 | int err; | ||
1511 | |||
1512 | qctrl.id = qmenu->id; | ||
1513 | err = solo_queryctrl(file, priv, &qctrl); | ||
1514 | if (err) | ||
1515 | return err; | ||
1516 | |||
1517 | return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL); | ||
1518 | } | ||
1519 | |||
1520 | static int solo_g_ctrl(struct file *file, void *priv, | ||
1521 | struct v4l2_control *ctrl) | ||
1522 | { | ||
1523 | struct solo_enc_fh *fh = priv; | ||
1524 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1525 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1526 | |||
1527 | switch (ctrl->id) { | ||
1528 | case V4L2_CID_BRIGHTNESS: | ||
1529 | case V4L2_CID_CONTRAST: | ||
1530 | case V4L2_CID_SATURATION: | ||
1531 | case V4L2_CID_HUE: | ||
1532 | case V4L2_CID_SHARPNESS: | ||
1533 | return tw28_get_ctrl_val(solo_dev, ctrl->id, solo_enc->ch, | ||
1534 | &ctrl->value); | ||
1535 | case V4L2_CID_MPEG_VIDEO_ENCODING: | ||
1536 | ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC; | ||
1537 | break; | ||
1538 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
1539 | ctrl->value = solo_enc->gop; | ||
1540 | break; | ||
1541 | case V4L2_CID_MOTION_THRESHOLD: | ||
1542 | ctrl->value = solo_enc->motion_thresh; | ||
1543 | break; | ||
1544 | case V4L2_CID_MOTION_ENABLE: | ||
1545 | ctrl->value = solo_is_motion_on(solo_enc); | ||
1546 | break; | ||
1547 | default: | ||
1548 | return -EINVAL; | ||
1549 | } | ||
1550 | |||
1551 | return 0; | ||
1552 | } | ||
1553 | |||
1554 | static int solo_s_ctrl(struct file *file, void *priv, | ||
1555 | struct v4l2_control *ctrl) | ||
1556 | { | ||
1557 | struct solo_enc_fh *fh = priv; | ||
1558 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1559 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1560 | |||
1561 | switch (ctrl->id) { | ||
1562 | case V4L2_CID_BRIGHTNESS: | ||
1563 | case V4L2_CID_CONTRAST: | ||
1564 | case V4L2_CID_SATURATION: | ||
1565 | case V4L2_CID_HUE: | ||
1566 | case V4L2_CID_SHARPNESS: | ||
1567 | return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch, | ||
1568 | ctrl->value); | ||
1569 | case V4L2_CID_MPEG_VIDEO_ENCODING: | ||
1570 | if (ctrl->value != V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC) | ||
1571 | return -ERANGE; | ||
1572 | break; | ||
1573 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
1574 | if (ctrl->value < 1 || ctrl->value > 255) | ||
1575 | return -ERANGE; | ||
1576 | solo_enc->gop = ctrl->value; | ||
1577 | solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch), | ||
1578 | solo_enc->gop); | ||
1579 | solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch), | ||
1580 | solo_enc->gop); | ||
1581 | break; | ||
1582 | case V4L2_CID_MOTION_THRESHOLD: | ||
1583 | /* TODO accept value on lower 16-bits and use high | ||
1584 | * 16-bits to assign the value to a specific block */ | ||
1585 | if (ctrl->value < 0 || ctrl->value > 0xffff) | ||
1586 | return -ERANGE; | ||
1587 | solo_enc->motion_thresh = ctrl->value; | ||
1588 | solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->value); | ||
1589 | break; | ||
1590 | case V4L2_CID_MOTION_ENABLE: | ||
1591 | solo_motion_toggle(solo_enc, ctrl->value); | ||
1592 | break; | ||
1593 | default: | ||
1594 | return -EINVAL; | ||
1595 | } | ||
1596 | |||
1597 | return 0; | ||
1598 | } | ||
1599 | |||
1600 | static int solo_s_ext_ctrls(struct file *file, void *priv, | ||
1601 | struct v4l2_ext_controls *ctrls) | ||
1602 | { | ||
1603 | struct solo_enc_fh *fh = priv; | ||
1604 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1605 | int i; | ||
1606 | |||
1607 | for (i = 0; i < ctrls->count; i++) { | ||
1608 | struct v4l2_ext_control *ctrl = (ctrls->controls + i); | ||
1609 | int err; | ||
1610 | |||
1611 | switch (ctrl->id) { | ||
1612 | case V4L2_CID_RDS_TX_RADIO_TEXT: | ||
1613 | if (ctrl->size - 1 > OSD_TEXT_MAX) | ||
1614 | err = -ERANGE; | ||
1615 | else { | ||
1616 | err = copy_from_user(solo_enc->osd_text, | ||
1617 | ctrl->string, | ||
1618 | OSD_TEXT_MAX); | ||
1619 | solo_enc->osd_text[OSD_TEXT_MAX] = '\0'; | ||
1620 | if (!err) | ||
1621 | err = solo_osd_print(solo_enc); | ||
1622 | } | ||
1623 | break; | ||
1624 | default: | ||
1625 | err = -EINVAL; | ||
1626 | } | ||
1627 | |||
1628 | if (err < 0) { | ||
1629 | ctrls->error_idx = i; | ||
1630 | return err; | ||
1631 | } | ||
1632 | } | ||
1633 | |||
1634 | return 0; | ||
1635 | } | ||
1636 | |||
1637 | static int solo_g_ext_ctrls(struct file *file, void *priv, | ||
1638 | struct v4l2_ext_controls *ctrls) | ||
1639 | { | ||
1640 | struct solo_enc_fh *fh = priv; | ||
1641 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1642 | int i; | ||
1643 | |||
1644 | for (i = 0; i < ctrls->count; i++) { | ||
1645 | struct v4l2_ext_control *ctrl = (ctrls->controls + i); | ||
1646 | int err; | ||
1647 | |||
1648 | switch (ctrl->id) { | ||
1649 | case V4L2_CID_RDS_TX_RADIO_TEXT: | ||
1650 | if (ctrl->size < OSD_TEXT_MAX) { | ||
1651 | ctrl->size = OSD_TEXT_MAX; | ||
1652 | err = -ENOSPC; | ||
1653 | } else { | ||
1654 | err = copy_to_user(ctrl->string, | ||
1655 | solo_enc->osd_text, | ||
1656 | OSD_TEXT_MAX); | ||
1657 | } | ||
1658 | break; | ||
1659 | default: | ||
1660 | err = -EINVAL; | ||
1661 | } | ||
1662 | |||
1663 | if (err < 0) { | ||
1664 | ctrls->error_idx = i; | ||
1665 | return err; | ||
1666 | } | ||
1667 | } | ||
1668 | |||
1669 | return 0; | ||
1670 | } | ||
1671 | |||
1672 | static const struct v4l2_file_operations solo_enc_fops = { | ||
1673 | .owner = THIS_MODULE, | ||
1674 | .open = solo_enc_open, | ||
1675 | .release = solo_enc_release, | ||
1676 | .read = solo_enc_read, | ||
1677 | .poll = solo_enc_poll, | ||
1678 | .mmap = solo_enc_mmap, | ||
1679 | .ioctl = video_ioctl2, | ||
1680 | }; | ||
1681 | |||
1682 | static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { | ||
1683 | .vidioc_querycap = solo_enc_querycap, | ||
1684 | .vidioc_s_std = solo_enc_s_std, | ||
1685 | /* Input callbacks */ | ||
1686 | .vidioc_enum_input = solo_enc_enum_input, | ||
1687 | .vidioc_s_input = solo_enc_set_input, | ||
1688 | .vidioc_g_input = solo_enc_get_input, | ||
1689 | /* Video capture format callbacks */ | ||
1690 | .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap, | ||
1691 | .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap, | ||
1692 | .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap, | ||
1693 | .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap, | ||
1694 | /* Streaming I/O */ | ||
1695 | .vidioc_reqbufs = solo_enc_reqbufs, | ||
1696 | .vidioc_querybuf = solo_enc_querybuf, | ||
1697 | .vidioc_qbuf = solo_enc_qbuf, | ||
1698 | .vidioc_dqbuf = solo_enc_dqbuf, | ||
1699 | .vidioc_streamon = solo_enc_streamon, | ||
1700 | .vidioc_streamoff = solo_enc_streamoff, | ||
1701 | /* Frame size and interval */ | ||
1702 | .vidioc_enum_framesizes = solo_enum_framesizes, | ||
1703 | .vidioc_enum_frameintervals = solo_enum_frameintervals, | ||
1704 | /* Video capture parameters */ | ||
1705 | .vidioc_s_parm = solo_s_parm, | ||
1706 | .vidioc_g_parm = solo_g_parm, | ||
1707 | /* Controls */ | ||
1708 | .vidioc_queryctrl = solo_queryctrl, | ||
1709 | .vidioc_querymenu = solo_querymenu, | ||
1710 | .vidioc_g_ctrl = solo_g_ctrl, | ||
1711 | .vidioc_s_ctrl = solo_s_ctrl, | ||
1712 | .vidioc_g_ext_ctrls = solo_g_ext_ctrls, | ||
1713 | .vidioc_s_ext_ctrls = solo_s_ext_ctrls, | ||
1714 | }; | ||
1715 | |||
1716 | static struct video_device solo_enc_template = { | ||
1717 | .name = SOLO6X10_NAME, | ||
1718 | .fops = &solo_enc_fops, | ||
1719 | .ioctl_ops = &solo_enc_ioctl_ops, | ||
1720 | .minor = -1, | ||
1721 | .release = video_device_release, | ||
1722 | |||
1723 | .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B, | ||
1724 | .current_norm = V4L2_STD_NTSC_M, | ||
1725 | }; | ||
1726 | |||
1727 | static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch) | ||
1728 | { | ||
1729 | struct solo_enc_dev *solo_enc; | ||
1730 | int ret; | ||
1731 | |||
1732 | solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL); | ||
1733 | if (!solo_enc) | ||
1734 | return ERR_PTR(-ENOMEM); | ||
1735 | |||
1736 | solo_enc->vfd = video_device_alloc(); | ||
1737 | if (!solo_enc->vfd) { | ||
1738 | kfree(solo_enc); | ||
1739 | return ERR_PTR(-ENOMEM); | ||
1740 | } | ||
1741 | |||
1742 | solo_enc->solo_dev = solo_dev; | ||
1743 | solo_enc->ch = ch; | ||
1744 | |||
1745 | *solo_enc->vfd = solo_enc_template; | ||
1746 | solo_enc->vfd->parent = &solo_dev->pdev->dev; | ||
1747 | ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, | ||
1748 | video_nr); | ||
1749 | if (ret < 0) { | ||
1750 | video_device_release(solo_enc->vfd); | ||
1751 | kfree(solo_enc); | ||
1752 | return ERR_PTR(ret); | ||
1753 | } | ||
1754 | |||
1755 | video_set_drvdata(solo_enc->vfd, solo_enc); | ||
1756 | |||
1757 | snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name), | ||
1758 | "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num, | ||
1759 | solo_enc->vfd->num); | ||
1760 | |||
1761 | if (video_nr != -1) | ||
1762 | video_nr++; | ||
1763 | |||
1764 | spin_lock_init(&solo_enc->lock); | ||
1765 | init_waitqueue_head(&solo_enc->thread_wait); | ||
1766 | atomic_set(&solo_enc->readers, 0); | ||
1767 | |||
1768 | solo_enc->qp = SOLO_DEFAULT_QP; | ||
1769 | solo_enc->gop = solo_dev->fps; | ||
1770 | solo_enc->interval = 1; | ||
1771 | solo_enc->mode = SOLO_ENC_MODE_CIF; | ||
1772 | solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; | ||
1773 | |||
1774 | spin_lock(&solo_enc->lock); | ||
1775 | solo_update_mode(solo_enc); | ||
1776 | spin_unlock(&solo_enc->lock); | ||
1777 | |||
1778 | return solo_enc; | ||
1779 | } | ||
1780 | |||
1781 | static void solo_enc_free(struct solo_enc_dev *solo_enc) | ||
1782 | { | ||
1783 | if (solo_enc == NULL) | ||
1784 | return; | ||
1785 | |||
1786 | video_unregister_device(solo_enc->vfd); | ||
1787 | kfree(solo_enc); | ||
1788 | } | ||
1789 | |||
1790 | int solo_enc_v4l2_init(struct solo_dev *solo_dev) | ||
1791 | { | ||
1792 | int i; | ||
1793 | |||
1794 | for (i = 0; i < solo_dev->nr_chans; i++) { | ||
1795 | solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i); | ||
1796 | if (IS_ERR(solo_dev->v4l2_enc[i])) | ||
1797 | break; | ||
1798 | } | ||
1799 | |||
1800 | if (i != solo_dev->nr_chans) { | ||
1801 | int ret = PTR_ERR(solo_dev->v4l2_enc[i]); | ||
1802 | while (i--) | ||
1803 | solo_enc_free(solo_dev->v4l2_enc[i]); | ||
1804 | return ret; | ||
1805 | } | ||
1806 | |||
1807 | /* D1@MAX-FPS * 4 */ | ||
1808 | solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4; | ||
1809 | |||
1810 | dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n", | ||
1811 | solo_dev->v4l2_enc[0]->vfd->num, | ||
1812 | solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num); | ||
1813 | |||
1814 | return 0; | ||
1815 | } | ||
1816 | |||
1817 | void solo_enc_v4l2_exit(struct solo_dev *solo_dev) | ||
1818 | { | ||
1819 | int i; | ||
1820 | |||
1821 | solo_irq_off(solo_dev, SOLO_IRQ_MOTION); | ||
1822 | |||
1823 | for (i = 0; i < solo_dev->nr_chans; i++) | ||
1824 | solo_enc_free(solo_dev->v4l2_enc[i]); | ||
1825 | } | ||