diff options
Diffstat (limited to 'drivers/media/video/cx25821/cx25821-video-upstream-ch2.c')
-rw-r--r-- | drivers/media/video/cx25821/cx25821-video-upstream-ch2.c | 823 |
1 files changed, 823 insertions, 0 deletions
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c new file mode 100644 index 00000000000..2a724ddfa53 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c | |||
@@ -0,0 +1,823 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
24 | |||
25 | #include "cx25821-video.h" | ||
26 | #include "cx25821-video-upstream-ch2.h" | ||
27 | |||
28 | #include <linux/fs.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/syscalls.h> | ||
34 | #include <linux/file.h> | ||
35 | #include <linux/fcntl.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/uaccess.h> | ||
38 | |||
39 | MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); | ||
40 | MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | | ||
44 | FLD_VID_SRC_OPC_ERR; | ||
45 | |||
46 | static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev, | ||
47 | __le32 *rp, unsigned int offset, | ||
48 | unsigned int bpl, u32 sync_line, | ||
49 | unsigned int lines, | ||
50 | int fifo_enable, int field_type) | ||
51 | { | ||
52 | unsigned int line, i; | ||
53 | int dist_betwn_starts = bpl * 2; | ||
54 | |||
55 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
56 | |||
57 | if (USE_RISC_NOOP_VIDEO) { | ||
58 | for (i = 0; i < NUM_NO_OPS; i++) | ||
59 | *(rp++) = cpu_to_le32(RISC_NOOP); | ||
60 | } | ||
61 | |||
62 | /* scan lines */ | ||
63 | for (line = 0; line < lines; line++) { | ||
64 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | ||
65 | *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset); | ||
66 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
67 | |||
68 | if ((lines <= NTSC_FIELD_HEIGHT) | ||
69 | || (line < (NTSC_FIELD_HEIGHT - 1)) | ||
70 | || !(dev->_isNTSC_ch2)) { | ||
71 | offset += dist_betwn_starts; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | return rp; | ||
76 | } | ||
77 | |||
78 | static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, | ||
79 | __le32 *rp, | ||
80 | dma_addr_t databuf_phys_addr, | ||
81 | unsigned int offset, | ||
82 | u32 sync_line, unsigned int bpl, | ||
83 | unsigned int lines, | ||
84 | int fifo_enable, int field_type) | ||
85 | { | ||
86 | unsigned int line, i; | ||
87 | struct sram_channel *sram_ch = | ||
88 | dev->channels[dev->_channel2_upstream_select].sram_channels; | ||
89 | int dist_betwn_starts = bpl * 2; | ||
90 | |||
91 | /* sync instruction */ | ||
92 | if (sync_line != NO_SYNC_LINE) | ||
93 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
94 | |||
95 | if (USE_RISC_NOOP_VIDEO) { | ||
96 | for (i = 0; i < NUM_NO_OPS; i++) | ||
97 | *(rp++) = cpu_to_le32(RISC_NOOP); | ||
98 | } | ||
99 | |||
100 | /* scan lines */ | ||
101 | for (line = 0; line < lines; line++) { | ||
102 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | ||
103 | *(rp++) = cpu_to_le32(databuf_phys_addr + offset); | ||
104 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
105 | |||
106 | if ((lines <= NTSC_FIELD_HEIGHT) | ||
107 | || (line < (NTSC_FIELD_HEIGHT - 1)) | ||
108 | || !(dev->_isNTSC_ch2)) { | ||
109 | offset += dist_betwn_starts; | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | check if we need to enable the FIFO after the first 4 lines | ||
114 | For the upstream video channel, the risc engine will enable | ||
115 | the FIFO. | ||
116 | */ | ||
117 | if (fifo_enable && line == 3) { | ||
118 | *(rp++) = RISC_WRITECR; | ||
119 | *(rp++) = sram_ch->dma_ctl; | ||
120 | *(rp++) = FLD_VID_FIFO_EN; | ||
121 | *(rp++) = 0x00000001; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | return rp; | ||
126 | } | ||
127 | |||
128 | int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, | ||
129 | struct pci_dev *pci, | ||
130 | unsigned int top_offset, unsigned int bpl, | ||
131 | unsigned int lines) | ||
132 | { | ||
133 | __le32 *rp; | ||
134 | int fifo_enable = 0; | ||
135 | int singlefield_lines = lines >> 1; /*get line count for single field */ | ||
136 | int odd_num_lines = singlefield_lines; | ||
137 | int frame = 0; | ||
138 | int frame_size = 0; | ||
139 | int databuf_offset = 0; | ||
140 | int risc_program_size = 0; | ||
141 | int risc_flag = RISC_CNT_RESET; | ||
142 | unsigned int bottom_offset = bpl; | ||
143 | dma_addr_t risc_phys_jump_addr; | ||
144 | |||
145 | if (dev->_isNTSC_ch2) { | ||
146 | odd_num_lines = singlefield_lines + 1; | ||
147 | risc_program_size = FRAME1_VID_PROG_SIZE; | ||
148 | if (bpl == Y411_LINE_SZ) | ||
149 | frame_size = FRAME_SIZE_NTSC_Y411; | ||
150 | else | ||
151 | frame_size = FRAME_SIZE_NTSC_Y422; | ||
152 | } else { | ||
153 | risc_program_size = PAL_VID_PROG_SIZE; | ||
154 | if (bpl == Y411_LINE_SZ) | ||
155 | frame_size = FRAME_SIZE_PAL_Y411; | ||
156 | else | ||
157 | frame_size = FRAME_SIZE_PAL_Y422; | ||
158 | } | ||
159 | |||
160 | /* Virtual address of Risc buffer program */ | ||
161 | rp = dev->_dma_virt_addr_ch2; | ||
162 | |||
163 | for (frame = 0; frame < NUM_FRAMES; frame++) { | ||
164 | databuf_offset = frame_size * frame; | ||
165 | |||
166 | if (UNSET != top_offset) { | ||
167 | fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; | ||
168 | rp = cx25821_risc_field_upstream_ch2(dev, rp, | ||
169 | dev->_data_buf_phys_addr_ch2 + databuf_offset, | ||
170 | top_offset, 0, bpl, odd_num_lines, fifo_enable, | ||
171 | ODD_FIELD); | ||
172 | } | ||
173 | |||
174 | fifo_enable = FIFO_DISABLE; | ||
175 | |||
176 | /* Even field */ | ||
177 | rp = cx25821_risc_field_upstream_ch2(dev, rp, | ||
178 | dev->_data_buf_phys_addr_ch2 + databuf_offset, | ||
179 | bottom_offset, 0x200, bpl, singlefield_lines, | ||
180 | fifo_enable, EVEN_FIELD); | ||
181 | |||
182 | if (frame == 0) { | ||
183 | risc_flag = RISC_CNT_RESET; | ||
184 | risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2 + | ||
185 | risc_program_size; | ||
186 | } else { | ||
187 | risc_flag = RISC_CNT_INC; | ||
188 | risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | Loop to 2ndFrameRISC or to Start of | ||
193 | Risc program & generate IRQ | ||
194 | */ | ||
195 | *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); | ||
196 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
197 | *(rp++) = cpu_to_le32(0); | ||
198 | } | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev) | ||
204 | { | ||
205 | struct sram_channel *sram_ch = | ||
206 | dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; | ||
207 | u32 tmp = 0; | ||
208 | |||
209 | if (!dev->_is_running_ch2) { | ||
210 | pr_info("No video file is currently running so return!\n"); | ||
211 | return; | ||
212 | } | ||
213 | /* Disable RISC interrupts */ | ||
214 | tmp = cx_read(sram_ch->int_msk); | ||
215 | cx_write(sram_ch->int_msk, tmp & ~_intr_msk); | ||
216 | |||
217 | /* Turn OFF risc and fifo */ | ||
218 | tmp = cx_read(sram_ch->dma_ctl); | ||
219 | cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); | ||
220 | |||
221 | /* Clear data buffer memory */ | ||
222 | if (dev->_data_buf_virt_addr_ch2) | ||
223 | memset(dev->_data_buf_virt_addr_ch2, 0, | ||
224 | dev->_data_buf_size_ch2); | ||
225 | |||
226 | dev->_is_running_ch2 = 0; | ||
227 | dev->_is_first_frame_ch2 = 0; | ||
228 | dev->_frame_count_ch2 = 0; | ||
229 | dev->_file_status_ch2 = END_OF_FILE; | ||
230 | |||
231 | kfree(dev->_irq_queues_ch2); | ||
232 | dev->_irq_queues_ch2 = NULL; | ||
233 | |||
234 | kfree(dev->_filename_ch2); | ||
235 | |||
236 | tmp = cx_read(VID_CH_MODE_SEL); | ||
237 | cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); | ||
238 | } | ||
239 | |||
240 | void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev) | ||
241 | { | ||
242 | if (dev->_is_running_ch2) | ||
243 | cx25821_stop_upstream_video_ch2(dev); | ||
244 | |||
245 | if (dev->_dma_virt_addr_ch2) { | ||
246 | pci_free_consistent(dev->pci, dev->_risc_size_ch2, | ||
247 | dev->_dma_virt_addr_ch2, | ||
248 | dev->_dma_phys_addr_ch2); | ||
249 | dev->_dma_virt_addr_ch2 = NULL; | ||
250 | } | ||
251 | |||
252 | if (dev->_data_buf_virt_addr_ch2) { | ||
253 | pci_free_consistent(dev->pci, dev->_data_buf_size_ch2, | ||
254 | dev->_data_buf_virt_addr_ch2, | ||
255 | dev->_data_buf_phys_addr_ch2); | ||
256 | dev->_data_buf_virt_addr_ch2 = NULL; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) | ||
261 | { | ||
262 | struct file *myfile; | ||
263 | int frame_index_temp = dev->_frame_index_ch2; | ||
264 | int i = 0; | ||
265 | int line_size = | ||
266 | (dev->_pixel_format_ch2 == | ||
267 | PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; | ||
268 | int frame_size = 0; | ||
269 | int frame_offset = 0; | ||
270 | ssize_t vfs_read_retval = 0; | ||
271 | char mybuf[line_size]; | ||
272 | loff_t file_offset; | ||
273 | loff_t pos; | ||
274 | mm_segment_t old_fs; | ||
275 | |||
276 | if (dev->_file_status_ch2 == END_OF_FILE) | ||
277 | return 0; | ||
278 | |||
279 | if (dev->_isNTSC_ch2) { | ||
280 | frame_size = | ||
281 | (line_size == | ||
282 | Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : | ||
283 | FRAME_SIZE_NTSC_Y422; | ||
284 | } else { | ||
285 | frame_size = | ||
286 | (line_size == | ||
287 | Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; | ||
288 | } | ||
289 | |||
290 | frame_offset = (frame_index_temp > 0) ? frame_size : 0; | ||
291 | file_offset = dev->_frame_count_ch2 * frame_size; | ||
292 | |||
293 | myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); | ||
294 | if (IS_ERR(myfile)) { | ||
295 | const int open_errno = -PTR_ERR(myfile); | ||
296 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
297 | __func__, dev->_filename_ch2, open_errno); | ||
298 | return PTR_ERR(myfile); | ||
299 | } else { | ||
300 | if (!(myfile->f_op)) { | ||
301 | pr_err("%s(): File has no file operations registered!\n", | ||
302 | __func__); | ||
303 | filp_close(myfile, NULL); | ||
304 | return -EIO; | ||
305 | } | ||
306 | |||
307 | if (!myfile->f_op->read) { | ||
308 | pr_err("%s(): File has no READ operations registered!\n", | ||
309 | __func__); | ||
310 | filp_close(myfile, NULL); | ||
311 | return -EIO; | ||
312 | } | ||
313 | |||
314 | pos = myfile->f_pos; | ||
315 | old_fs = get_fs(); | ||
316 | set_fs(KERNEL_DS); | ||
317 | |||
318 | for (i = 0; i < dev->_lines_count_ch2; i++) { | ||
319 | pos = file_offset; | ||
320 | |||
321 | vfs_read_retval = | ||
322 | vfs_read(myfile, mybuf, line_size, &pos); | ||
323 | |||
324 | if (vfs_read_retval > 0 && vfs_read_retval == line_size | ||
325 | && dev->_data_buf_virt_addr_ch2 != NULL) { | ||
326 | memcpy((void *)(dev->_data_buf_virt_addr_ch2 + | ||
327 | frame_offset / 4), mybuf, | ||
328 | vfs_read_retval); | ||
329 | } | ||
330 | |||
331 | file_offset += vfs_read_retval; | ||
332 | frame_offset += vfs_read_retval; | ||
333 | |||
334 | if (vfs_read_retval < line_size) { | ||
335 | pr_info("Done: exit %s() since no more bytes to read from Video file\n", | ||
336 | __func__); | ||
337 | break; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | if (i > 0) | ||
342 | dev->_frame_count_ch2++; | ||
343 | |||
344 | dev->_file_status_ch2 = | ||
345 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | ||
346 | |||
347 | set_fs(old_fs); | ||
348 | filp_close(myfile, NULL); | ||
349 | } | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static void cx25821_vidups_handler_ch2(struct work_struct *work) | ||
355 | { | ||
356 | struct cx25821_dev *dev = | ||
357 | container_of(work, struct cx25821_dev, _irq_work_entry_ch2); | ||
358 | |||
359 | if (!dev) { | ||
360 | pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", | ||
361 | __func__); | ||
362 | return; | ||
363 | } | ||
364 | |||
365 | cx25821_get_frame_ch2(dev, | ||
366 | dev->channels[dev-> | ||
367 | _channel2_upstream_select].sram_channels); | ||
368 | } | ||
369 | |||
370 | int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) | ||
371 | { | ||
372 | struct file *myfile; | ||
373 | int i = 0, j = 0; | ||
374 | int line_size = | ||
375 | (dev->_pixel_format_ch2 == | ||
376 | PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; | ||
377 | ssize_t vfs_read_retval = 0; | ||
378 | char mybuf[line_size]; | ||
379 | loff_t pos; | ||
380 | loff_t offset = (unsigned long)0; | ||
381 | mm_segment_t old_fs; | ||
382 | |||
383 | myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); | ||
384 | |||
385 | if (IS_ERR(myfile)) { | ||
386 | const int open_errno = -PTR_ERR(myfile); | ||
387 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
388 | __func__, dev->_filename_ch2, open_errno); | ||
389 | return PTR_ERR(myfile); | ||
390 | } else { | ||
391 | if (!(myfile->f_op)) { | ||
392 | pr_err("%s(): File has no file operations registered!\n", | ||
393 | __func__); | ||
394 | filp_close(myfile, NULL); | ||
395 | return -EIO; | ||
396 | } | ||
397 | |||
398 | if (!myfile->f_op->read) { | ||
399 | pr_err("%s(): File has no READ operations registered! Returning\n", | ||
400 | __func__); | ||
401 | filp_close(myfile, NULL); | ||
402 | return -EIO; | ||
403 | } | ||
404 | |||
405 | pos = myfile->f_pos; | ||
406 | old_fs = get_fs(); | ||
407 | set_fs(KERNEL_DS); | ||
408 | |||
409 | for (j = 0; j < NUM_FRAMES; j++) { | ||
410 | for (i = 0; i < dev->_lines_count_ch2; i++) { | ||
411 | pos = offset; | ||
412 | |||
413 | vfs_read_retval = | ||
414 | vfs_read(myfile, mybuf, line_size, &pos); | ||
415 | |||
416 | if (vfs_read_retval > 0 | ||
417 | && vfs_read_retval == line_size | ||
418 | && dev->_data_buf_virt_addr_ch2 != NULL) { | ||
419 | memcpy((void *)(dev-> | ||
420 | _data_buf_virt_addr_ch2 | ||
421 | + offset / 4), mybuf, | ||
422 | vfs_read_retval); | ||
423 | } | ||
424 | |||
425 | offset += vfs_read_retval; | ||
426 | |||
427 | if (vfs_read_retval < line_size) { | ||
428 | pr_info("Done: exit %s() since no more bytes to read from Video file\n", | ||
429 | __func__); | ||
430 | break; | ||
431 | } | ||
432 | } | ||
433 | |||
434 | if (i > 0) | ||
435 | dev->_frame_count_ch2++; | ||
436 | |||
437 | if (vfs_read_retval < line_size) | ||
438 | break; | ||
439 | } | ||
440 | |||
441 | dev->_file_status_ch2 = | ||
442 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | ||
443 | |||
444 | set_fs(old_fs); | ||
445 | myfile->f_pos = 0; | ||
446 | filp_close(myfile, NULL); | ||
447 | } | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, | ||
453 | struct sram_channel *sram_ch, | ||
454 | int bpl) | ||
455 | { | ||
456 | int ret = 0; | ||
457 | dma_addr_t dma_addr; | ||
458 | dma_addr_t data_dma_addr; | ||
459 | |||
460 | if (dev->_dma_virt_addr_ch2 != NULL) { | ||
461 | pci_free_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, | ||
462 | dev->_dma_virt_addr_ch2, | ||
463 | dev->_dma_phys_addr_ch2); | ||
464 | } | ||
465 | |||
466 | dev->_dma_virt_addr_ch2 = | ||
467 | pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, | ||
468 | &dma_addr); | ||
469 | dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2; | ||
470 | dev->_dma_phys_start_addr_ch2 = dma_addr; | ||
471 | dev->_dma_phys_addr_ch2 = dma_addr; | ||
472 | dev->_risc_size_ch2 = dev->upstream_riscbuf_size_ch2; | ||
473 | |||
474 | if (!dev->_dma_virt_addr_ch2) { | ||
475 | pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); | ||
476 | return -ENOMEM; | ||
477 | } | ||
478 | |||
479 | /* Iniitize at this address until n bytes to 0 */ | ||
480 | memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2); | ||
481 | |||
482 | if (dev->_data_buf_virt_addr_ch2 != NULL) { | ||
483 | pci_free_consistent(dev->pci, dev->upstream_databuf_size_ch2, | ||
484 | dev->_data_buf_virt_addr_ch2, | ||
485 | dev->_data_buf_phys_addr_ch2); | ||
486 | } | ||
487 | /* For Video Data buffer allocation */ | ||
488 | dev->_data_buf_virt_addr_ch2 = | ||
489 | pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2, | ||
490 | &data_dma_addr); | ||
491 | dev->_data_buf_phys_addr_ch2 = data_dma_addr; | ||
492 | dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2; | ||
493 | |||
494 | if (!dev->_data_buf_virt_addr_ch2) { | ||
495 | pr_err("FAILED to allocate memory for data buffer! Returning\n"); | ||
496 | return -ENOMEM; | ||
497 | } | ||
498 | |||
499 | /* Initialize at this address until n bytes to 0 */ | ||
500 | memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2); | ||
501 | |||
502 | ret = cx25821_openfile_ch2(dev, sram_ch); | ||
503 | if (ret < 0) | ||
504 | return ret; | ||
505 | |||
506 | /* Creating RISC programs */ | ||
507 | ret = cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl, | ||
508 | dev->_lines_count_ch2); | ||
509 | if (ret < 0) { | ||
510 | pr_info("Failed creating Video Upstream Risc programs!\n"); | ||
511 | goto error; | ||
512 | } | ||
513 | |||
514 | return 0; | ||
515 | |||
516 | error: | ||
517 | return ret; | ||
518 | } | ||
519 | |||
520 | int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num, | ||
521 | u32 status) | ||
522 | { | ||
523 | u32 int_msk_tmp; | ||
524 | struct sram_channel *channel = dev->channels[chan_num].sram_channels; | ||
525 | int singlefield_lines = NTSC_FIELD_HEIGHT; | ||
526 | int line_size_in_bytes = Y422_LINE_SZ; | ||
527 | int odd_risc_prog_size = 0; | ||
528 | dma_addr_t risc_phys_jump_addr; | ||
529 | __le32 *rp; | ||
530 | |||
531 | if (status & FLD_VID_SRC_RISC1) { | ||
532 | /* We should only process one program per call */ | ||
533 | u32 prog_cnt = cx_read(channel->gpcnt); | ||
534 | |||
535 | /* | ||
536 | * Since we've identified our IRQ, clear our bits from the | ||
537 | * interrupt mask and interrupt status registers | ||
538 | */ | ||
539 | int_msk_tmp = cx_read(channel->int_msk); | ||
540 | cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); | ||
541 | cx_write(channel->int_stat, _intr_msk); | ||
542 | |||
543 | spin_lock(&dev->slock); | ||
544 | |||
545 | dev->_frame_index_ch2 = prog_cnt; | ||
546 | |||
547 | queue_work(dev->_irq_queues_ch2, &dev->_irq_work_entry_ch2); | ||
548 | |||
549 | if (dev->_is_first_frame_ch2) { | ||
550 | dev->_is_first_frame_ch2 = 0; | ||
551 | |||
552 | if (dev->_isNTSC_ch2) { | ||
553 | singlefield_lines += 1; | ||
554 | odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; | ||
555 | } else { | ||
556 | singlefield_lines = PAL_FIELD_HEIGHT; | ||
557 | odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; | ||
558 | } | ||
559 | |||
560 | if (dev->_dma_virt_start_addr_ch2 != NULL) { | ||
561 | if (dev->_pixel_format_ch2 == PIXEL_FRMT_411) | ||
562 | line_size_in_bytes = Y411_LINE_SZ; | ||
563 | else | ||
564 | line_size_in_bytes = Y422_LINE_SZ; | ||
565 | risc_phys_jump_addr = | ||
566 | dev->_dma_phys_start_addr_ch2 + | ||
567 | odd_risc_prog_size; | ||
568 | |||
569 | rp = cx25821_update_riscprogram_ch2(dev, | ||
570 | dev->_dma_virt_start_addr_ch2, | ||
571 | TOP_OFFSET, line_size_in_bytes, | ||
572 | 0x0, singlefield_lines, | ||
573 | FIFO_DISABLE, ODD_FIELD); | ||
574 | |||
575 | /* Jump to Even Risc program of 1st Frame */ | ||
576 | *(rp++) = cpu_to_le32(RISC_JUMP); | ||
577 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
578 | *(rp++) = cpu_to_le32(0); | ||
579 | } | ||
580 | } | ||
581 | |||
582 | spin_unlock(&dev->slock); | ||
583 | } | ||
584 | |||
585 | if (dev->_file_status_ch2 == END_OF_FILE) { | ||
586 | pr_info("EOF Channel 2 Framecount = %d\n", | ||
587 | dev->_frame_count_ch2); | ||
588 | return -1; | ||
589 | } | ||
590 | /* ElSE, set the interrupt mask register, re-enable irq. */ | ||
591 | int_msk_tmp = cx_read(channel->int_msk); | ||
592 | cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id) | ||
598 | { | ||
599 | struct cx25821_dev *dev = dev_id; | ||
600 | u32 msk_stat, vid_status; | ||
601 | int handled = 0; | ||
602 | int channel_num = 0; | ||
603 | struct sram_channel *sram_ch; | ||
604 | |||
605 | if (!dev) | ||
606 | return -1; | ||
607 | |||
608 | channel_num = VID_UPSTREAM_SRAM_CHANNEL_J; | ||
609 | sram_ch = dev->channels[channel_num].sram_channels; | ||
610 | |||
611 | msk_stat = cx_read(sram_ch->int_mstat); | ||
612 | vid_status = cx_read(sram_ch->int_stat); | ||
613 | |||
614 | /* Only deal with our interrupt */ | ||
615 | if (vid_status) { | ||
616 | handled = | ||
617 | cx25821_video_upstream_irq_ch2(dev, channel_num, | ||
618 | vid_status); | ||
619 | } | ||
620 | |||
621 | if (handled < 0) | ||
622 | cx25821_stop_upstream_video_ch2(dev); | ||
623 | else | ||
624 | handled += handled; | ||
625 | |||
626 | return IRQ_RETVAL(handled); | ||
627 | } | ||
628 | |||
629 | static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev, | ||
630 | struct sram_channel *ch, int pix_format) | ||
631 | { | ||
632 | int width = WIDTH_D1; | ||
633 | int height = dev->_lines_count_ch2; | ||
634 | int num_lines, odd_num_lines; | ||
635 | u32 value; | ||
636 | int vip_mode = PIXEL_ENGINE_VIP1; | ||
637 | |||
638 | value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); | ||
639 | value &= 0xFFFFFFEF; | ||
640 | value |= dev->_isNTSC_ch2 ? 0 : 0x10; | ||
641 | cx_write(ch->vid_fmt_ctl, value); | ||
642 | |||
643 | /* | ||
644 | * set number of active pixels in each line. Default is 720 | ||
645 | * pixels in both NTSC and PAL format | ||
646 | */ | ||
647 | cx_write(ch->vid_active_ctl1, width); | ||
648 | |||
649 | num_lines = (height / 2) & 0x3FF; | ||
650 | odd_num_lines = num_lines; | ||
651 | |||
652 | if (dev->_isNTSC_ch2) | ||
653 | odd_num_lines += 1; | ||
654 | |||
655 | value = (num_lines << 16) | odd_num_lines; | ||
656 | |||
657 | /* set number of active lines in field 0 (top) and field 1 (bottom) */ | ||
658 | cx_write(ch->vid_active_ctl2, value); | ||
659 | |||
660 | cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); | ||
661 | } | ||
662 | |||
663 | int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, | ||
664 | struct sram_channel *sram_ch) | ||
665 | { | ||
666 | u32 tmp = 0; | ||
667 | int err = 0; | ||
668 | |||
669 | /* | ||
670 | * 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface | ||
671 | * for channel A-C | ||
672 | */ | ||
673 | tmp = cx_read(VID_CH_MODE_SEL); | ||
674 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | ||
675 | |||
676 | /* | ||
677 | * Set the physical start address of the RISC program in the initial | ||
678 | * program counter(IPC) member of the cmds. | ||
679 | */ | ||
680 | cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2); | ||
681 | cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */ | ||
682 | |||
683 | /* reset counter */ | ||
684 | cx_write(sram_ch->gpcnt_ctl, 3); | ||
685 | |||
686 | /* Clear our bits from the interrupt status register. */ | ||
687 | cx_write(sram_ch->int_stat, _intr_msk); | ||
688 | |||
689 | /* Set the interrupt mask register, enable irq. */ | ||
690 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); | ||
691 | tmp = cx_read(sram_ch->int_msk); | ||
692 | cx_write(sram_ch->int_msk, tmp |= _intr_msk); | ||
693 | |||
694 | err = | ||
695 | request_irq(dev->pci->irq, cx25821_upstream_irq_ch2, | ||
696 | IRQF_SHARED, dev->name, dev); | ||
697 | if (err < 0) { | ||
698 | pr_err("%s: can't get upstream IRQ %d\n", | ||
699 | dev->name, dev->pci->irq); | ||
700 | goto fail_irq; | ||
701 | } | ||
702 | /* Start the DMA engine */ | ||
703 | tmp = cx_read(sram_ch->dma_ctl); | ||
704 | cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); | ||
705 | |||
706 | dev->_is_running_ch2 = 1; | ||
707 | dev->_is_first_frame_ch2 = 1; | ||
708 | |||
709 | return 0; | ||
710 | |||
711 | fail_irq: | ||
712 | cx25821_dev_unregister(dev); | ||
713 | return err; | ||
714 | } | ||
715 | |||
716 | int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, | ||
717 | int pixel_format) | ||
718 | { | ||
719 | struct sram_channel *sram_ch; | ||
720 | u32 tmp; | ||
721 | int retval = 0; | ||
722 | int err = 0; | ||
723 | int data_frame_size = 0; | ||
724 | int risc_buffer_size = 0; | ||
725 | int str_length = 0; | ||
726 | |||
727 | if (dev->_is_running_ch2) { | ||
728 | pr_info("Video Channel is still running so return!\n"); | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | dev->_channel2_upstream_select = channel_select; | ||
733 | sram_ch = dev->channels[channel_select].sram_channels; | ||
734 | |||
735 | INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2); | ||
736 | dev->_irq_queues_ch2 = | ||
737 | create_singlethread_workqueue("cx25821_workqueue2"); | ||
738 | |||
739 | if (!dev->_irq_queues_ch2) { | ||
740 | pr_err("create_singlethread_workqueue() for Video FAILED!\n"); | ||
741 | return -ENOMEM; | ||
742 | } | ||
743 | /* | ||
744 | * 656/VIP SRC Upstream Channel I & J and 7 - | ||
745 | * Host Bus Interface for channel A-C | ||
746 | */ | ||
747 | tmp = cx_read(VID_CH_MODE_SEL); | ||
748 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | ||
749 | |||
750 | dev->_is_running_ch2 = 0; | ||
751 | dev->_frame_count_ch2 = 0; | ||
752 | dev->_file_status_ch2 = RESET_STATUS; | ||
753 | dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576; | ||
754 | dev->_pixel_format_ch2 = pixel_format; | ||
755 | dev->_line_size_ch2 = | ||
756 | (dev->_pixel_format_ch2 == | ||
757 | PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; | ||
758 | data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; | ||
759 | risc_buffer_size = | ||
760 | dev->_isNTSC_ch2 ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; | ||
761 | |||
762 | if (dev->input_filename_ch2) { | ||
763 | str_length = strlen(dev->input_filename_ch2); | ||
764 | dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); | ||
765 | |||
766 | if (!dev->_filename_ch2) | ||
767 | goto error; | ||
768 | |||
769 | memcpy(dev->_filename_ch2, dev->input_filename_ch2, | ||
770 | str_length + 1); | ||
771 | } else { | ||
772 | str_length = strlen(dev->_defaultname_ch2); | ||
773 | dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); | ||
774 | |||
775 | if (!dev->_filename_ch2) | ||
776 | goto error; | ||
777 | |||
778 | memcpy(dev->_filename_ch2, dev->_defaultname_ch2, | ||
779 | str_length + 1); | ||
780 | } | ||
781 | |||
782 | /* Default if filename is empty string */ | ||
783 | if (strcmp(dev->input_filename_ch2, "") == 0) { | ||
784 | if (dev->_isNTSC_ch2) { | ||
785 | dev->_filename_ch2 = | ||
786 | (dev->_pixel_format_ch2 == | ||
787 | PIXEL_FRMT_411) ? "/root/vid411.yuv" : | ||
788 | "/root/vidtest.yuv"; | ||
789 | } else { | ||
790 | dev->_filename_ch2 = | ||
791 | (dev->_pixel_format_ch2 == | ||
792 | PIXEL_FRMT_411) ? "/root/pal411.yuv" : | ||
793 | "/root/pal422.yuv"; | ||
794 | } | ||
795 | } | ||
796 | |||
797 | retval = cx25821_sram_channel_setup_upstream(dev, sram_ch, | ||
798 | dev->_line_size_ch2, 0); | ||
799 | |||
800 | /* setup fifo + format */ | ||
801 | cx25821_set_pixelengine_ch2(dev, sram_ch, dev->_pixel_format_ch2); | ||
802 | |||
803 | dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2; | ||
804 | dev->upstream_databuf_size_ch2 = data_frame_size * 2; | ||
805 | |||
806 | /* Allocating buffers and prepare RISC program */ | ||
807 | retval = cx25821_upstream_buffer_prepare_ch2(dev, sram_ch, | ||
808 | dev->_line_size_ch2); | ||
809 | if (retval < 0) { | ||
810 | pr_err("%s: Failed to set up Video upstream buffers!\n", | ||
811 | dev->name); | ||
812 | goto error; | ||
813 | } | ||
814 | |||
815 | cx25821_start_video_dma_upstream_ch2(dev, sram_ch); | ||
816 | |||
817 | return 0; | ||
818 | |||
819 | error: | ||
820 | cx25821_dev_unregister(dev); | ||
821 | |||
822 | return err; | ||
823 | } | ||