diff options
Diffstat (limited to 'drivers/staging/cx25821/cx25821-video-upstream-ch2.c')
-rw-r--r-- | drivers/staging/cx25821/cx25821-video-upstream-ch2.c | 836 |
1 files changed, 836 insertions, 0 deletions
diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c b/drivers/staging/cx25821/cx25821-video-upstream-ch2.c new file mode 100644 index 00000000000..655357da3d6 --- /dev/null +++ b/drivers/staging/cx25821/cx25821-video-upstream-ch2.c | |||
@@ -0,0 +1,836 @@ | |||
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 = | ||
44 | FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | 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 | frame_size = | ||
149 | (bpl == | ||
150 | Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : | ||
151 | FRAME_SIZE_NTSC_Y422; | ||
152 | } else { | ||
153 | risc_program_size = PAL_VID_PROG_SIZE; | ||
154 | frame_size = | ||
155 | (bpl == | ||
156 | Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; | ||
157 | } | ||
158 | |||
159 | /* Virtual address of Risc buffer program */ | ||
160 | rp = dev->_dma_virt_addr_ch2; | ||
161 | |||
162 | for (frame = 0; frame < NUM_FRAMES; frame++) { | ||
163 | databuf_offset = frame_size * frame; | ||
164 | |||
165 | if (UNSET != top_offset) { | ||
166 | fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; | ||
167 | rp = cx25821_risc_field_upstream_ch2(dev, rp, | ||
168 | dev-> | ||
169 | _data_buf_phys_addr_ch2 | ||
170 | + databuf_offset, | ||
171 | top_offset, 0, bpl, | ||
172 | odd_num_lines, | ||
173 | fifo_enable, | ||
174 | ODD_FIELD); | ||
175 | } | ||
176 | |||
177 | fifo_enable = FIFO_DISABLE; | ||
178 | |||
179 | /* Even field */ | ||
180 | rp = cx25821_risc_field_upstream_ch2(dev, rp, | ||
181 | dev-> | ||
182 | _data_buf_phys_addr_ch2 + | ||
183 | databuf_offset, | ||
184 | bottom_offset, 0x200, bpl, | ||
185 | singlefield_lines, | ||
186 | fifo_enable, EVEN_FIELD); | ||
187 | |||
188 | if (frame == 0) { | ||
189 | risc_flag = RISC_CNT_RESET; | ||
190 | risc_phys_jump_addr = | ||
191 | dev->_dma_phys_start_addr_ch2 + risc_program_size; | ||
192 | } else { | ||
193 | risc_flag = RISC_CNT_INC; | ||
194 | risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2; | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | Loop to 2ndFrameRISC or to Start of | ||
199 | Risc program & generate IRQ | ||
200 | */ | ||
201 | *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); | ||
202 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
203 | *(rp++) = cpu_to_le32(0); | ||
204 | } | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev) | ||
210 | { | ||
211 | struct sram_channel *sram_ch = | ||
212 | dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; | ||
213 | u32 tmp = 0; | ||
214 | |||
215 | if (!dev->_is_running_ch2) { | ||
216 | pr_info("No video file is currently running so return!\n"); | ||
217 | return; | ||
218 | } | ||
219 | /* Disable RISC interrupts */ | ||
220 | tmp = cx_read(sram_ch->int_msk); | ||
221 | cx_write(sram_ch->int_msk, tmp & ~_intr_msk); | ||
222 | |||
223 | /* Turn OFF risc and fifo */ | ||
224 | tmp = cx_read(sram_ch->dma_ctl); | ||
225 | cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); | ||
226 | |||
227 | /* Clear data buffer memory */ | ||
228 | if (dev->_data_buf_virt_addr_ch2) | ||
229 | memset(dev->_data_buf_virt_addr_ch2, 0, | ||
230 | dev->_data_buf_size_ch2); | ||
231 | |||
232 | dev->_is_running_ch2 = 0; | ||
233 | dev->_is_first_frame_ch2 = 0; | ||
234 | dev->_frame_count_ch2 = 0; | ||
235 | dev->_file_status_ch2 = END_OF_FILE; | ||
236 | |||
237 | kfree(dev->_irq_queues_ch2); | ||
238 | dev->_irq_queues_ch2 = NULL; | ||
239 | |||
240 | kfree(dev->_filename_ch2); | ||
241 | |||
242 | tmp = cx_read(VID_CH_MODE_SEL); | ||
243 | cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); | ||
244 | } | ||
245 | |||
246 | void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev) | ||
247 | { | ||
248 | if (dev->_is_running_ch2) | ||
249 | cx25821_stop_upstream_video_ch2(dev); | ||
250 | |||
251 | if (dev->_dma_virt_addr_ch2) { | ||
252 | pci_free_consistent(dev->pci, dev->_risc_size_ch2, | ||
253 | dev->_dma_virt_addr_ch2, | ||
254 | dev->_dma_phys_addr_ch2); | ||
255 | dev->_dma_virt_addr_ch2 = NULL; | ||
256 | } | ||
257 | |||
258 | if (dev->_data_buf_virt_addr_ch2) { | ||
259 | pci_free_consistent(dev->pci, dev->_data_buf_size_ch2, | ||
260 | dev->_data_buf_virt_addr_ch2, | ||
261 | dev->_data_buf_phys_addr_ch2); | ||
262 | dev->_data_buf_virt_addr_ch2 = NULL; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) | ||
267 | { | ||
268 | struct file *myfile; | ||
269 | int frame_index_temp = dev->_frame_index_ch2; | ||
270 | int i = 0; | ||
271 | int line_size = | ||
272 | (dev->_pixel_format_ch2 == | ||
273 | PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; | ||
274 | int frame_size = 0; | ||
275 | int frame_offset = 0; | ||
276 | ssize_t vfs_read_retval = 0; | ||
277 | char mybuf[line_size]; | ||
278 | loff_t file_offset; | ||
279 | loff_t pos; | ||
280 | mm_segment_t old_fs; | ||
281 | |||
282 | if (dev->_file_status_ch2 == END_OF_FILE) | ||
283 | return 0; | ||
284 | |||
285 | if (dev->_isNTSC_ch2) { | ||
286 | frame_size = | ||
287 | (line_size == | ||
288 | Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : | ||
289 | FRAME_SIZE_NTSC_Y422; | ||
290 | } else { | ||
291 | frame_size = | ||
292 | (line_size == | ||
293 | Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; | ||
294 | } | ||
295 | |||
296 | frame_offset = (frame_index_temp > 0) ? frame_size : 0; | ||
297 | file_offset = dev->_frame_count_ch2 * frame_size; | ||
298 | |||
299 | myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); | ||
300 | if (IS_ERR(myfile)) { | ||
301 | const int open_errno = -PTR_ERR(myfile); | ||
302 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
303 | __func__, dev->_filename_ch2, open_errno); | ||
304 | return PTR_ERR(myfile); | ||
305 | } else { | ||
306 | if (!(myfile->f_op)) { | ||
307 | pr_err("%s(): File has no file operations registered!\n", | ||
308 | __func__); | ||
309 | filp_close(myfile, NULL); | ||
310 | return -EIO; | ||
311 | } | ||
312 | |||
313 | if (!myfile->f_op->read) { | ||
314 | pr_err("%s(): File has no READ operations registered!\n", | ||
315 | __func__); | ||
316 | filp_close(myfile, NULL); | ||
317 | return -EIO; | ||
318 | } | ||
319 | |||
320 | pos = myfile->f_pos; | ||
321 | old_fs = get_fs(); | ||
322 | set_fs(KERNEL_DS); | ||
323 | |||
324 | for (i = 0; i < dev->_lines_count_ch2; i++) { | ||
325 | pos = file_offset; | ||
326 | |||
327 | vfs_read_retval = | ||
328 | vfs_read(myfile, mybuf, line_size, &pos); | ||
329 | |||
330 | if (vfs_read_retval > 0 && vfs_read_retval == line_size | ||
331 | && dev->_data_buf_virt_addr_ch2 != NULL) { | ||
332 | memcpy((void *)(dev->_data_buf_virt_addr_ch2 + | ||
333 | frame_offset / 4), mybuf, | ||
334 | vfs_read_retval); | ||
335 | } | ||
336 | |||
337 | file_offset += vfs_read_retval; | ||
338 | frame_offset += vfs_read_retval; | ||
339 | |||
340 | if (vfs_read_retval < line_size) { | ||
341 | pr_info("Done: exit %s() since no more bytes to read from Video file\n", | ||
342 | __func__); | ||
343 | break; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | if (i > 0) | ||
348 | dev->_frame_count_ch2++; | ||
349 | |||
350 | dev->_file_status_ch2 = | ||
351 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | ||
352 | |||
353 | set_fs(old_fs); | ||
354 | filp_close(myfile, NULL); | ||
355 | } | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static void cx25821_vidups_handler_ch2(struct work_struct *work) | ||
361 | { | ||
362 | struct cx25821_dev *dev = | ||
363 | container_of(work, struct cx25821_dev, _irq_work_entry_ch2); | ||
364 | |||
365 | if (!dev) { | ||
366 | pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", | ||
367 | __func__); | ||
368 | return; | ||
369 | } | ||
370 | |||
371 | cx25821_get_frame_ch2(dev, | ||
372 | dev->channels[dev-> | ||
373 | _channel2_upstream_select].sram_channels); | ||
374 | } | ||
375 | |||
376 | int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) | ||
377 | { | ||
378 | struct file *myfile; | ||
379 | int i = 0, j = 0; | ||
380 | int line_size = | ||
381 | (dev->_pixel_format_ch2 == | ||
382 | PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; | ||
383 | ssize_t vfs_read_retval = 0; | ||
384 | char mybuf[line_size]; | ||
385 | loff_t pos; | ||
386 | loff_t offset = (unsigned long)0; | ||
387 | mm_segment_t old_fs; | ||
388 | |||
389 | myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); | ||
390 | |||
391 | if (IS_ERR(myfile)) { | ||
392 | const int open_errno = -PTR_ERR(myfile); | ||
393 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
394 | __func__, dev->_filename_ch2, open_errno); | ||
395 | return PTR_ERR(myfile); | ||
396 | } else { | ||
397 | if (!(myfile->f_op)) { | ||
398 | pr_err("%s(): File has no file operations registered!\n", | ||
399 | __func__); | ||
400 | filp_close(myfile, NULL); | ||
401 | return -EIO; | ||
402 | } | ||
403 | |||
404 | if (!myfile->f_op->read) { | ||
405 | pr_err("%s(): File has no READ operations registered! Returning\n", | ||
406 | __func__); | ||
407 | filp_close(myfile, NULL); | ||
408 | return -EIO; | ||
409 | } | ||
410 | |||
411 | pos = myfile->f_pos; | ||
412 | old_fs = get_fs(); | ||
413 | set_fs(KERNEL_DS); | ||
414 | |||
415 | for (j = 0; j < NUM_FRAMES; j++) { | ||
416 | for (i = 0; i < dev->_lines_count_ch2; i++) { | ||
417 | pos = offset; | ||
418 | |||
419 | vfs_read_retval = | ||
420 | vfs_read(myfile, mybuf, line_size, &pos); | ||
421 | |||
422 | if (vfs_read_retval > 0 | ||
423 | && vfs_read_retval == line_size | ||
424 | && dev->_data_buf_virt_addr_ch2 != NULL) { | ||
425 | memcpy((void *)(dev-> | ||
426 | _data_buf_virt_addr_ch2 | ||
427 | + offset / 4), mybuf, | ||
428 | vfs_read_retval); | ||
429 | } | ||
430 | |||
431 | offset += vfs_read_retval; | ||
432 | |||
433 | if (vfs_read_retval < line_size) { | ||
434 | pr_info("Done: exit %s() since no more bytes to read from Video file\n", | ||
435 | __func__); | ||
436 | break; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | if (i > 0) | ||
441 | dev->_frame_count_ch2++; | ||
442 | |||
443 | if (vfs_read_retval < line_size) | ||
444 | break; | ||
445 | } | ||
446 | |||
447 | dev->_file_status_ch2 = | ||
448 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | ||
449 | |||
450 | set_fs(old_fs); | ||
451 | myfile->f_pos = 0; | ||
452 | filp_close(myfile, NULL); | ||
453 | } | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, | ||
459 | struct sram_channel *sram_ch, | ||
460 | int bpl) | ||
461 | { | ||
462 | int ret = 0; | ||
463 | dma_addr_t dma_addr; | ||
464 | dma_addr_t data_dma_addr; | ||
465 | |||
466 | if (dev->_dma_virt_addr_ch2 != NULL) { | ||
467 | pci_free_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, | ||
468 | dev->_dma_virt_addr_ch2, | ||
469 | dev->_dma_phys_addr_ch2); | ||
470 | } | ||
471 | |||
472 | dev->_dma_virt_addr_ch2 = | ||
473 | pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, | ||
474 | &dma_addr); | ||
475 | dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2; | ||
476 | dev->_dma_phys_start_addr_ch2 = dma_addr; | ||
477 | dev->_dma_phys_addr_ch2 = dma_addr; | ||
478 | dev->_risc_size_ch2 = dev->upstream_riscbuf_size_ch2; | ||
479 | |||
480 | if (!dev->_dma_virt_addr_ch2) { | ||
481 | pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); | ||
482 | return -ENOMEM; | ||
483 | } | ||
484 | |||
485 | /* Iniitize at this address until n bytes to 0 */ | ||
486 | memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2); | ||
487 | |||
488 | if (dev->_data_buf_virt_addr_ch2 != NULL) { | ||
489 | pci_free_consistent(dev->pci, dev->upstream_databuf_size_ch2, | ||
490 | dev->_data_buf_virt_addr_ch2, | ||
491 | dev->_data_buf_phys_addr_ch2); | ||
492 | } | ||
493 | /* For Video Data buffer allocation */ | ||
494 | dev->_data_buf_virt_addr_ch2 = | ||
495 | pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2, | ||
496 | &data_dma_addr); | ||
497 | dev->_data_buf_phys_addr_ch2 = data_dma_addr; | ||
498 | dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2; | ||
499 | |||
500 | if (!dev->_data_buf_virt_addr_ch2) { | ||
501 | pr_err("FAILED to allocate memory for data buffer! Returning\n"); | ||
502 | return -ENOMEM; | ||
503 | } | ||
504 | |||
505 | /* Initialize at this address until n bytes to 0 */ | ||
506 | memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2); | ||
507 | |||
508 | ret = cx25821_openfile_ch2(dev, sram_ch); | ||
509 | if (ret < 0) | ||
510 | return ret; | ||
511 | |||
512 | /* Creating RISC programs */ | ||
513 | ret = | ||
514 | cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl, | ||
515 | dev->_lines_count_ch2); | ||
516 | if (ret < 0) { | ||
517 | pr_info("Failed creating Video Upstream Risc programs!\n"); | ||
518 | goto error; | ||
519 | } | ||
520 | |||
521 | return 0; | ||
522 | |||
523 | error: | ||
524 | return ret; | ||
525 | } | ||
526 | |||
527 | int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num, | ||
528 | u32 status) | ||
529 | { | ||
530 | u32 int_msk_tmp; | ||
531 | struct sram_channel *channel = dev->channels[chan_num].sram_channels; | ||
532 | int singlefield_lines = NTSC_FIELD_HEIGHT; | ||
533 | int line_size_in_bytes = Y422_LINE_SZ; | ||
534 | int odd_risc_prog_size = 0; | ||
535 | dma_addr_t risc_phys_jump_addr; | ||
536 | __le32 *rp; | ||
537 | |||
538 | if (status & FLD_VID_SRC_RISC1) { | ||
539 | /* We should only process one program per call */ | ||
540 | u32 prog_cnt = cx_read(channel->gpcnt); | ||
541 | |||
542 | /* | ||
543 | * Since we've identified our IRQ, clear our bits from the | ||
544 | * interrupt mask and interrupt status registers | ||
545 | */ | ||
546 | int_msk_tmp = cx_read(channel->int_msk); | ||
547 | cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); | ||
548 | cx_write(channel->int_stat, _intr_msk); | ||
549 | |||
550 | spin_lock(&dev->slock); | ||
551 | |||
552 | dev->_frame_index_ch2 = prog_cnt; | ||
553 | |||
554 | queue_work(dev->_irq_queues_ch2, &dev->_irq_work_entry_ch2); | ||
555 | |||
556 | if (dev->_is_first_frame_ch2) { | ||
557 | dev->_is_first_frame_ch2 = 0; | ||
558 | |||
559 | if (dev->_isNTSC_ch2) { | ||
560 | singlefield_lines += 1; | ||
561 | odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; | ||
562 | } else { | ||
563 | singlefield_lines = PAL_FIELD_HEIGHT; | ||
564 | odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; | ||
565 | } | ||
566 | |||
567 | if (dev->_dma_virt_start_addr_ch2 != NULL) { | ||
568 | line_size_in_bytes = | ||
569 | (dev->_pixel_format_ch2 == | ||
570 | PIXEL_FRMT_411) ? Y411_LINE_SZ : | ||
571 | Y422_LINE_SZ; | ||
572 | risc_phys_jump_addr = | ||
573 | dev->_dma_phys_start_addr_ch2 + | ||
574 | odd_risc_prog_size; | ||
575 | |||
576 | rp = cx25821_update_riscprogram_ch2(dev, | ||
577 | dev-> | ||
578 | _dma_virt_start_addr_ch2, | ||
579 | TOP_OFFSET, | ||
580 | line_size_in_bytes, | ||
581 | 0x0, | ||
582 | singlefield_lines, | ||
583 | FIFO_DISABLE, | ||
584 | ODD_FIELD); | ||
585 | |||
586 | /* Jump to Even Risc program of 1st Frame */ | ||
587 | *(rp++) = cpu_to_le32(RISC_JUMP); | ||
588 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
589 | *(rp++) = cpu_to_le32(0); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | spin_unlock(&dev->slock); | ||
594 | } | ||
595 | |||
596 | if (dev->_file_status_ch2 == END_OF_FILE) { | ||
597 | pr_info("EOF Channel 2 Framecount = %d\n", | ||
598 | dev->_frame_count_ch2); | ||
599 | return -1; | ||
600 | } | ||
601 | /* ElSE, set the interrupt mask register, re-enable irq. */ | ||
602 | int_msk_tmp = cx_read(channel->int_msk); | ||
603 | cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id) | ||
609 | { | ||
610 | struct cx25821_dev *dev = dev_id; | ||
611 | u32 msk_stat, vid_status; | ||
612 | int handled = 0; | ||
613 | int channel_num = 0; | ||
614 | struct sram_channel *sram_ch; | ||
615 | |||
616 | if (!dev) | ||
617 | return -1; | ||
618 | |||
619 | channel_num = VID_UPSTREAM_SRAM_CHANNEL_J; | ||
620 | sram_ch = dev->channels[channel_num].sram_channels; | ||
621 | |||
622 | msk_stat = cx_read(sram_ch->int_mstat); | ||
623 | vid_status = cx_read(sram_ch->int_stat); | ||
624 | |||
625 | /* Only deal with our interrupt */ | ||
626 | if (vid_status) { | ||
627 | handled = | ||
628 | cx25821_video_upstream_irq_ch2(dev, channel_num, | ||
629 | vid_status); | ||
630 | } | ||
631 | |||
632 | if (handled < 0) | ||
633 | cx25821_stop_upstream_video_ch2(dev); | ||
634 | else | ||
635 | handled += handled; | ||
636 | |||
637 | return IRQ_RETVAL(handled); | ||
638 | } | ||
639 | |||
640 | static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev, | ||
641 | struct sram_channel *ch, int pix_format) | ||
642 | { | ||
643 | int width = WIDTH_D1; | ||
644 | int height = dev->_lines_count_ch2; | ||
645 | int num_lines, odd_num_lines; | ||
646 | u32 value; | ||
647 | int vip_mode = PIXEL_ENGINE_VIP1; | ||
648 | |||
649 | value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); | ||
650 | value &= 0xFFFFFFEF; | ||
651 | value |= dev->_isNTSC_ch2 ? 0 : 0x10; | ||
652 | cx_write(ch->vid_fmt_ctl, value); | ||
653 | |||
654 | /* | ||
655 | * set number of active pixels in each line. Default is 720 | ||
656 | * pixels in both NTSC and PAL format | ||
657 | */ | ||
658 | cx_write(ch->vid_active_ctl1, width); | ||
659 | |||
660 | num_lines = (height / 2) & 0x3FF; | ||
661 | odd_num_lines = num_lines; | ||
662 | |||
663 | if (dev->_isNTSC_ch2) | ||
664 | odd_num_lines += 1; | ||
665 | |||
666 | value = (num_lines << 16) | odd_num_lines; | ||
667 | |||
668 | /* set number of active lines in field 0 (top) and field 1 (bottom) */ | ||
669 | cx_write(ch->vid_active_ctl2, value); | ||
670 | |||
671 | cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); | ||
672 | } | ||
673 | |||
674 | int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, | ||
675 | struct sram_channel *sram_ch) | ||
676 | { | ||
677 | u32 tmp = 0; | ||
678 | int err = 0; | ||
679 | |||
680 | /* | ||
681 | * 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface | ||
682 | * for channel A-C | ||
683 | */ | ||
684 | tmp = cx_read(VID_CH_MODE_SEL); | ||
685 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | ||
686 | |||
687 | /* | ||
688 | * Set the physical start address of the RISC program in the initial | ||
689 | * program counter(IPC) member of the cmds. | ||
690 | */ | ||
691 | cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2); | ||
692 | cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */ | ||
693 | |||
694 | /* reset counter */ | ||
695 | cx_write(sram_ch->gpcnt_ctl, 3); | ||
696 | |||
697 | /* Clear our bits from the interrupt status register. */ | ||
698 | cx_write(sram_ch->int_stat, _intr_msk); | ||
699 | |||
700 | /* Set the interrupt mask register, enable irq. */ | ||
701 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); | ||
702 | tmp = cx_read(sram_ch->int_msk); | ||
703 | cx_write(sram_ch->int_msk, tmp |= _intr_msk); | ||
704 | |||
705 | err = | ||
706 | request_irq(dev->pci->irq, cx25821_upstream_irq_ch2, | ||
707 | IRQF_SHARED | IRQF_DISABLED, dev->name, dev); | ||
708 | if (err < 0) { | ||
709 | pr_err("%s: can't get upstream IRQ %d\n", | ||
710 | dev->name, dev->pci->irq); | ||
711 | goto fail_irq; | ||
712 | } | ||
713 | /* Start the DMA engine */ | ||
714 | tmp = cx_read(sram_ch->dma_ctl); | ||
715 | cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); | ||
716 | |||
717 | dev->_is_running_ch2 = 1; | ||
718 | dev->_is_first_frame_ch2 = 1; | ||
719 | |||
720 | return 0; | ||
721 | |||
722 | fail_irq: | ||
723 | cx25821_dev_unregister(dev); | ||
724 | return err; | ||
725 | } | ||
726 | |||
727 | int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, | ||
728 | int pixel_format) | ||
729 | { | ||
730 | struct sram_channel *sram_ch; | ||
731 | u32 tmp; | ||
732 | int retval = 0; | ||
733 | int err = 0; | ||
734 | int data_frame_size = 0; | ||
735 | int risc_buffer_size = 0; | ||
736 | int str_length = 0; | ||
737 | |||
738 | if (dev->_is_running_ch2) { | ||
739 | pr_info("Video Channel is still running so return!\n"); | ||
740 | return 0; | ||
741 | } | ||
742 | |||
743 | dev->_channel2_upstream_select = channel_select; | ||
744 | sram_ch = dev->channels[channel_select].sram_channels; | ||
745 | |||
746 | INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2); | ||
747 | dev->_irq_queues_ch2 = | ||
748 | create_singlethread_workqueue("cx25821_workqueue2"); | ||
749 | |||
750 | if (!dev->_irq_queues_ch2) { | ||
751 | pr_err("create_singlethread_workqueue() for Video FAILED!\n"); | ||
752 | return -ENOMEM; | ||
753 | } | ||
754 | /* | ||
755 | * 656/VIP SRC Upstream Channel I & J and 7 - | ||
756 | * Host Bus Interface for channel A-C | ||
757 | */ | ||
758 | tmp = cx_read(VID_CH_MODE_SEL); | ||
759 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | ||
760 | |||
761 | dev->_is_running_ch2 = 0; | ||
762 | dev->_frame_count_ch2 = 0; | ||
763 | dev->_file_status_ch2 = RESET_STATUS; | ||
764 | dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576; | ||
765 | dev->_pixel_format_ch2 = pixel_format; | ||
766 | dev->_line_size_ch2 = | ||
767 | (dev->_pixel_format_ch2 == | ||
768 | PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; | ||
769 | data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; | ||
770 | risc_buffer_size = | ||
771 | dev->_isNTSC_ch2 ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; | ||
772 | |||
773 | if (dev->input_filename_ch2) { | ||
774 | str_length = strlen(dev->input_filename_ch2); | ||
775 | dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); | ||
776 | |||
777 | if (!dev->_filename_ch2) | ||
778 | goto error; | ||
779 | |||
780 | memcpy(dev->_filename_ch2, dev->input_filename_ch2, | ||
781 | str_length + 1); | ||
782 | } else { | ||
783 | str_length = strlen(dev->_defaultname_ch2); | ||
784 | dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); | ||
785 | |||
786 | if (!dev->_filename_ch2) | ||
787 | goto error; | ||
788 | |||
789 | memcpy(dev->_filename_ch2, dev->_defaultname_ch2, | ||
790 | str_length + 1); | ||
791 | } | ||
792 | |||
793 | /* Default if filename is empty string */ | ||
794 | if (strcmp(dev->input_filename_ch2, "") == 0) { | ||
795 | if (dev->_isNTSC_ch2) { | ||
796 | dev->_filename_ch2 = | ||
797 | (dev->_pixel_format_ch2 == | ||
798 | PIXEL_FRMT_411) ? "/root/vid411.yuv" : | ||
799 | "/root/vidtest.yuv"; | ||
800 | } else { | ||
801 | dev->_filename_ch2 = | ||
802 | (dev->_pixel_format_ch2 == | ||
803 | PIXEL_FRMT_411) ? "/root/pal411.yuv" : | ||
804 | "/root/pal422.yuv"; | ||
805 | } | ||
806 | } | ||
807 | |||
808 | retval = | ||
809 | cx25821_sram_channel_setup_upstream(dev, sram_ch, | ||
810 | dev->_line_size_ch2, 0); | ||
811 | |||
812 | /* setup fifo + format */ | ||
813 | cx25821_set_pixelengine_ch2(dev, sram_ch, dev->_pixel_format_ch2); | ||
814 | |||
815 | dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2; | ||
816 | dev->upstream_databuf_size_ch2 = data_frame_size * 2; | ||
817 | |||
818 | /* Allocating buffers and prepare RISC program */ | ||
819 | retval = | ||
820 | cx25821_upstream_buffer_prepare_ch2(dev, sram_ch, | ||
821 | dev->_line_size_ch2); | ||
822 | if (retval < 0) { | ||
823 | pr_err("%s: Failed to set up Video upstream buffers!\n", | ||
824 | dev->name); | ||
825 | goto error; | ||
826 | } | ||
827 | |||
828 | cx25821_start_video_dma_upstream_ch2(dev, sram_ch); | ||
829 | |||
830 | return 0; | ||
831 | |||
832 | error: | ||
833 | cx25821_dev_unregister(dev); | ||
834 | |||
835 | return err; | ||
836 | } | ||